Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 195 additions & 0 deletions github/data_source_github_enterprise_actions_hosted_runner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package github

import (
"context"
"strconv"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceGithubEnterpriseActionsHostedRunner() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceGithubEnterpriseActionsHostedRunnerRead,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a top-level Description


Schema: map[string]*schema.Schema{
"enterprise_slug": {
Type: schema.TypeString,
Required: true,
Description: "The slug of the enterprise.",
},
"runner_id": {
Type: schema.TypeInt,
Required: true,
Description: "The numeric ID of the hosted runner.",
},
"name": {
Type: schema.TypeString,
Computed: true,
Description: "The name of the hosted runner.",
},
"runner_group_id": {
Type: schema.TypeInt,
Computed: true,
Description: "The runner group ID this runner belongs to.",
},
"platform": {
Type: schema.TypeString,
Computed: true,
Description: "The platform of the runner (e.g., 'linux-x64', 'win-x64').",
},
"status": {
Type: schema.TypeString,
Computed: true,
Description: "Current status of the runner (e.g., 'Ready', 'Provisioning').",
},
"maximum_runners": {
Type: schema.TypeInt,
Computed: true,
Description: "Maximum number of runners to scale up to.",
},
"public_ip_enabled": {
Type: schema.TypeBool,
Computed: true,
Description: "Whether static public IP is enabled for this runner.",
},
"last_active_on": {
Type: schema.TypeString,
Computed: true,
Description: "RFC3339 timestamp indicating when the runner was last active.",
},
"image_details": {
Type: schema.TypeList,
Computed: true,
Description: "Details about the runner's image.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Computed: true,
Description: "The image ID.",
},
"source": {
Type: schema.TypeString,
Computed: true,
Description: "The image source (github, partner, or custom).",
},
"version": {
Type: schema.TypeString,
Computed: true,
Description: "The image version.",
},
"size_gb": {
Type: schema.TypeInt,
Computed: true,
Description: "The size of the image in GB.",
},
"display_name": {
Type: schema.TypeString,
Computed: true,
Description: "Human-readable display name for the image.",
},
},
},
},
"machine_size_details": {
Type: schema.TypeList,
Computed: true,
Description: "Details about the runner's machine size.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Computed: true,
Description: "Machine size identifier (e.g., '4-core', '8-core').",
},
"cpu_cores": {
Type: schema.TypeInt,
Computed: true,
Description: "Number of CPU cores.",
},
"memory_gb": {
Type: schema.TypeInt,
Computed: true,
Description: "Amount of memory in GB.",
},
"storage_gb": {
Type: schema.TypeInt,
Computed: true,
Description: "Amount of SSD storage in GB.",
},
},
},
},
"public_ips": {
Type: schema.TypeList,
Computed: true,
Description: "List of public IP ranges assigned to this runner (only if public_ip_enabled is true).",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"enabled": {
Type: schema.TypeBool,
Computed: true,
Description: "Whether this IP range is enabled.",
},
"prefix": {
Type: schema.TypeString,
Computed: true,
Description: "IP address prefix.",
},
"length": {
Type: schema.TypeInt,
Computed: true,
Description: "Subnet length (CIDR notation).",
},
},
},
},
},
}
}

func dataSourceGithubEnterpriseActionsHostedRunnerRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
client := meta.(*Owner).v3client

enterpriseSlug := d.Get("enterprise_slug").(string)
runnerID := int64(d.Get("runner_id").(int))

// Get the specific runner by ID
runner, _, err := client.Enterprise.GetHostedRunner(ctx, enterpriseSlug, runnerID)
if err != nil {
return diag.Errorf("error reading enterprise hosted runner: %s", err.Error())
}

// Set the ID as enterprise_slug/runner_id
id, err := buildID(enterpriseSlug, strconv.FormatInt(runner.GetID(), 10))
if err != nil {
return diag.FromErr(err)
}
d.SetId(id)

runnerData := map[string]any{
"name": runner.GetName(),
"runner_group_id": int(runner.GetRunnerGroupID()),
"platform": runner.GetPlatform(),
"status": runner.GetStatus(),
"maximum_runners": int(runner.GetMaximumRunners()),
"public_ip_enabled": runner.GetPublicIPEnabled(),
"image_details": flattenHostedRunnerImage(runner.ImageDetails),
"machine_size_details": flattenHostedRunnerMachineSpec(runner.MachineSizeDetails),
"public_ips": flattenHostedRunnerPublicIPs(runner.PublicIPs),
}

if runner.LastActiveOn != nil {
runnerData["last_active_on"] = runner.LastActiveOn.Format(time.RFC3339)
}

for k, v := range runnerData {
if err := d.Set(k, v); err != nil {
return diag.FromErr(err)
}
}
Comment on lines +172 to +192
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Please simplify this structure to just use d.Set without this map. This does not improve clarity, nor does it win us anything


return nil
}
67 changes: 67 additions & 0 deletions github/data_source_github_enterprise_actions_hosted_runner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package github

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
"github.com/hashicorp/terraform-plugin-testing/statecheck"
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
)

func TestAccGithubEnterpriseActionsHostedRunnerDataSource(t *testing.T) {
t.Run("gets a specific enterprise hosted runner by ID", func(t *testing.T) {
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
config := fmt.Sprintf(`
data "github_enterprise" "enterprise" {
slug = "%s"
}

resource "github_enterprise_actions_runner_group" "test" {
enterprise_slug = data.github_enterprise.enterprise.slug
name = "%srunner-group-%s"
visibility = "all"
}

resource "github_enterprise_actions_hosted_runner" "test" {
enterprise_slug = data.github_enterprise.enterprise.slug
name = "%srunner-datasource-%s"

image {
# GitHub-owned Ubuntu Latest 24.04 image ID
# To list available images: GET /enterprises/{enterprise}/actions/hosted-runners/images/github-owned
id = "2306"
Comment thread
nico34638 marked this conversation as resolved.
source = "github"
}

size = "4-core"
runner_group_id = github_enterprise_actions_runner_group.test.id
}

data "github_enterprise_actions_hosted_runner" "test" {
enterprise_slug = data.github_enterprise.enterprise.slug
runner_id = github_enterprise_actions_hosted_runner.test.runner_id
}
`, testAccConf.enterpriseSlug, testResourcePrefix, randomID, testResourcePrefix, randomID)

resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessMode(t, enterprise) },
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
PreCheck: func() { skipUnlessMode(t, enterprise) },
PreCheck: func() { skipUnlessEnterprise(t) },

ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: config,
ConfigStateChecks: []statecheck.StateCheck{
statecheck.ExpectKnownValue("data.github_enterprise_actions_hosted_runner.test", tfjsonpath.New("name"), knownvalue.StringExact(fmt.Sprintf("%srunner-datasource-%s", testResourcePrefix, randomID))),
statecheck.ExpectKnownValue("data.github_enterprise_actions_hosted_runner.test", tfjsonpath.New("runner_id"), knownvalue.NotNull()),
statecheck.ExpectKnownValue("data.github_enterprise_actions_hosted_runner.test", tfjsonpath.New("status"), knownvalue.NotNull()),
statecheck.ExpectKnownValue("data.github_enterprise_actions_hosted_runner.test", tfjsonpath.New("platform"), knownvalue.NotNull()),
statecheck.ExpectKnownValue("data.github_enterprise_actions_hosted_runner.test", tfjsonpath.New("image_details").AtSliceIndex(0).AtMapKey("id"), knownvalue.StringExact("2306")),
statecheck.ExpectKnownValue("data.github_enterprise_actions_hosted_runner.test", tfjsonpath.New("machine_size_details").AtSliceIndex(0).AtMapKey("id"), knownvalue.StringExact("4-core")),
},
},
},
})
})
}
Loading