Skip to content

Commit badfeea

Browse files
committed
github: add data source enterprise_actions_hosted_runner
1 parent 59cb1cb commit badfeea

6 files changed

Lines changed: 663 additions & 0 deletions
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/google/go-github/v82/github"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
)
11+
12+
func dataSourceGithubEnterpriseActionsHostedRunner() *schema.Resource {
13+
return &schema.Resource{
14+
Read: dataSourceGithubEnterpriseActionsHostedRunnerRead,
15+
16+
Schema: map[string]*schema.Schema{
17+
"enterprise_slug": {
18+
Type: schema.TypeString,
19+
Required: true,
20+
Description: "The slug of the enterprise.",
21+
},
22+
"name": {
23+
Type: schema.TypeString,
24+
Required: true,
25+
Description: "The name of the hosted runner to lookup.",
26+
},
27+
"runner_id": {
28+
Type: schema.TypeInt,
29+
Computed: true,
30+
Description: "The numeric ID of the hosted runner.",
31+
},
32+
"runner_group_id": {
33+
Type: schema.TypeInt,
34+
Computed: true,
35+
Description: "The runner group ID this runner belongs to.",
36+
},
37+
"platform": {
38+
Type: schema.TypeString,
39+
Computed: true,
40+
Description: "The platform of the runner (e.g., 'linux-x64', 'win-x64').",
41+
},
42+
"status": {
43+
Type: schema.TypeString,
44+
Computed: true,
45+
Description: "Current status of the runner (e.g., 'Ready', 'Provisioning').",
46+
},
47+
"maximum_runners": {
48+
Type: schema.TypeInt,
49+
Computed: true,
50+
Description: "Maximum number of runners to scale up to.",
51+
},
52+
"public_ip_enabled": {
53+
Type: schema.TypeBool,
54+
Computed: true,
55+
Description: "Whether static public IP is enabled for this runner.",
56+
},
57+
"last_active_on": {
58+
Type: schema.TypeString,
59+
Computed: true,
60+
Description: "RFC3339 timestamp indicating when the runner was last active.",
61+
},
62+
"image_details": {
63+
Type: schema.TypeList,
64+
Computed: true,
65+
Description: "Details about the runner's image.",
66+
Elem: &schema.Resource{
67+
Schema: map[string]*schema.Schema{
68+
"id": {
69+
Type: schema.TypeString,
70+
Computed: true,
71+
Description: "The image ID.",
72+
},
73+
"source": {
74+
Type: schema.TypeString,
75+
Computed: true,
76+
Description: "The image source (github, partner, or custom).",
77+
},
78+
"version": {
79+
Type: schema.TypeString,
80+
Computed: true,
81+
Description: "The image version.",
82+
},
83+
"size_gb": {
84+
Type: schema.TypeInt,
85+
Computed: true,
86+
Description: "The size of the image in GB.",
87+
},
88+
"display_name": {
89+
Type: schema.TypeString,
90+
Computed: true,
91+
Description: "Human-readable display name for the image.",
92+
},
93+
},
94+
},
95+
},
96+
"machine_size_details": {
97+
Type: schema.TypeList,
98+
Computed: true,
99+
Description: "Details about the runner's machine size.",
100+
Elem: &schema.Resource{
101+
Schema: map[string]*schema.Schema{
102+
"id": {
103+
Type: schema.TypeString,
104+
Computed: true,
105+
Description: "Machine size identifier (e.g., '4-core', '8-core').",
106+
},
107+
"cpu_cores": {
108+
Type: schema.TypeInt,
109+
Computed: true,
110+
Description: "Number of CPU cores.",
111+
},
112+
"memory_gb": {
113+
Type: schema.TypeInt,
114+
Computed: true,
115+
Description: "Amount of memory in GB.",
116+
},
117+
"storage_gb": {
118+
Type: schema.TypeInt,
119+
Computed: true,
120+
Description: "Amount of SSD storage in GB.",
121+
},
122+
},
123+
},
124+
},
125+
"public_ips": {
126+
Type: schema.TypeList,
127+
Computed: true,
128+
Description: "List of public IP ranges assigned to this runner (only if public_ip_enabled is true).",
129+
Elem: &schema.Resource{
130+
Schema: map[string]*schema.Schema{
131+
"enabled": {
132+
Type: schema.TypeBool,
133+
Computed: true,
134+
Description: "Whether this IP range is enabled.",
135+
},
136+
"prefix": {
137+
Type: schema.TypeString,
138+
Computed: true,
139+
Description: "IP address prefix.",
140+
},
141+
"length": {
142+
Type: schema.TypeInt,
143+
Computed: true,
144+
Description: "Subnet length (CIDR notation).",
145+
},
146+
},
147+
},
148+
},
149+
},
150+
}
151+
}
152+
153+
func dataSourceGithubEnterpriseActionsHostedRunnerRead(d *schema.ResourceData, meta any) error {
154+
client := meta.(*Owner).v3client
155+
ctx := context.Background()
156+
157+
enterpriseSlug := d.Get("enterprise_slug").(string)
158+
runnerName := d.Get("name").(string)
159+
160+
// List all runners and find the one matching the name
161+
opts := &github.ListOptions{PerPage: 100}
162+
var foundRunner *github.HostedRunner
163+
164+
for {
165+
runners, resp, err := client.Enterprise.ListHostedRunners(ctx, enterpriseSlug, opts)
166+
if err != nil {
167+
return err
168+
}
169+
170+
for _, runner := range runners.Runners {
171+
if runner.Name != nil && *runner.Name == runnerName {
172+
foundRunner = runner
173+
break
174+
}
175+
}
176+
177+
if foundRunner != nil || resp.NextPage == 0 {
178+
break
179+
}
180+
opts.Page = resp.NextPage
181+
}
182+
183+
if foundRunner == nil {
184+
return fmt.Errorf("no hosted runner found with name %q in enterprise %q", runnerName, enterpriseSlug)
185+
}
186+
187+
// Set the ID as enterprise_slug/runner_id
188+
d.SetId(fmt.Sprintf("%s/%d", enterpriseSlug, *foundRunner.ID))
189+
190+
if foundRunner.ID != nil {
191+
if err := d.Set("runner_id", int(*foundRunner.ID)); err != nil {
192+
return err
193+
}
194+
}
195+
196+
if foundRunner.RunnerGroupID != nil {
197+
if err := d.Set("runner_group_id", int(*foundRunner.RunnerGroupID)); err != nil {
198+
return err
199+
}
200+
}
201+
202+
if foundRunner.Platform != nil {
203+
if err := d.Set("platform", *foundRunner.Platform); err != nil {
204+
return err
205+
}
206+
}
207+
208+
if foundRunner.Status != nil {
209+
if err := d.Set("status", *foundRunner.Status); err != nil {
210+
return err
211+
}
212+
}
213+
214+
if foundRunner.MaximumRunners != nil {
215+
if err := d.Set("maximum_runners", int(*foundRunner.MaximumRunners)); err != nil {
216+
return err
217+
}
218+
}
219+
220+
if foundRunner.PublicIPEnabled != nil {
221+
if err := d.Set("public_ip_enabled", *foundRunner.PublicIPEnabled); err != nil {
222+
return err
223+
}
224+
}
225+
226+
if foundRunner.LastActiveOn != nil {
227+
if err := d.Set("last_active_on", foundRunner.LastActiveOn.Format(time.RFC3339)); err != nil {
228+
return err
229+
}
230+
}
231+
232+
if foundRunner.ImageDetails != nil {
233+
if err := d.Set("image_details", flattenHostedRunnerImage(foundRunner.ImageDetails)); err != nil {
234+
return err
235+
}
236+
}
237+
238+
if foundRunner.MachineSizeDetails != nil {
239+
if err := d.Set("machine_size_details", flattenHostedRunnerMachineSpec(foundRunner.MachineSizeDetails)); err != nil {
240+
return err
241+
}
242+
}
243+
244+
if foundRunner.PublicIPs != nil {
245+
if err := d.Set("public_ips", flattenHostedRunnerPublicIPs(foundRunner.PublicIPs)); err != nil {
246+
return err
247+
}
248+
}
249+
250+
return nil
251+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package github
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8+
)
9+
10+
func TestAccGithubEnterpriseActionsHostedRunnersDataSource(t *testing.T) {
11+
t.Run("lists all enterprise hosted runners", func(t *testing.T) {
12+
config := fmt.Sprintf(`
13+
data "github_enterprise_actions_hosted_runners" "test" {
14+
enterprise_slug = "%s"
15+
}
16+
`, testAccConf.enterpriseSlug)
17+
18+
resource.Test(t, resource.TestCase{
19+
PreCheck: func() { skipUnlessMode(t, enterprise) },
20+
ProviderFactories: providerFactories,
21+
Steps: []resource.TestStep{
22+
{
23+
Config: config,
24+
Check: resource.ComposeTestCheckFunc(
25+
resource.TestCheckResourceAttrSet("data.github_enterprise_actions_hosted_runners.test", "runners.#"),
26+
),
27+
},
28+
},
29+
})
30+
})
31+
}
32+
33+
func TestAccGithubEnterpriseActionsHostedRunnerDataSource(t *testing.T) {
34+
t.Run("gets a specific enterprise hosted runner by name", func(t *testing.T) {
35+
config := fmt.Sprintf(`
36+
data "github_enterprise" "enterprise" {
37+
slug = "%s"
38+
}
39+
40+
resource "github_enterprise_actions_runner_group" "test" {
41+
enterprise_slug = data.github_enterprise.enterprise.slug
42+
name = "test-runner-group"
43+
visibility = "all"
44+
}
45+
46+
resource "github_enterprise_actions_hosted_runner" "test" {
47+
enterprise_slug = data.github_enterprise.enterprise.slug
48+
name = "test-runner-for-datasource"
49+
50+
image {
51+
id = "2306"
52+
source = "github"
53+
}
54+
55+
size = "4-core"
56+
runner_group_id = github_enterprise_actions_runner_group.test.id
57+
}
58+
59+
data "github_enterprise_actions_hosted_runner" "test" {
60+
enterprise_slug = data.github_enterprise.enterprise.slug
61+
name = github_enterprise_actions_hosted_runner.test.name
62+
}
63+
`, testAccConf.enterpriseSlug)
64+
65+
resource.Test(t, resource.TestCase{
66+
PreCheck: func() { skipUnlessMode(t, enterprise) },
67+
ProviderFactories: providerFactories,
68+
Steps: []resource.TestStep{
69+
{
70+
Config: config,
71+
Check: resource.ComposeTestCheckFunc(
72+
resource.TestCheckResourceAttr("data.github_enterprise_actions_hosted_runner.test", "name", "test-runner-for-datasource"),
73+
resource.TestCheckResourceAttrSet("data.github_enterprise_actions_hosted_runner.test", "runner_id"),
74+
resource.TestCheckResourceAttrSet("data.github_enterprise_actions_hosted_runner.test", "status"),
75+
resource.TestCheckResourceAttrSet("data.github_enterprise_actions_hosted_runner.test", "platform"),
76+
resource.TestCheckResourceAttr("data.github_enterprise_actions_hosted_runner.test", "image_details.0.id", "2306"),
77+
resource.TestCheckResourceAttr("data.github_enterprise_actions_hosted_runner.test", "machine_size_details.0.id", "4-core"),
78+
),
79+
},
80+
},
81+
})
82+
})
83+
}

0 commit comments

Comments
 (0)