Skip to content
Draft
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
43 changes: 43 additions & 0 deletions docs/resources/apple_silicon_runner.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
subcategory: "Apple Silicon"
page_title: "Scaleway: scaleway_apple_silicon_runner"
---

# Resource: scaleway_apple_silicon_runner

Creates and manages Scaleway Apple silicon runners.

## Example Usage

```terraform
resource "scaleway_apple_silicon_runner" "main" {
name = "my-github-runner"
ci_provider = "github"
url = "https://github.com/my-org/my-repo"
token = "my-token"
}
```

## Argument Reference

- `ci_provider` - (Required) The CI/CD provider for the runner. Must be either 'github' or 'gitlab'
- `token` - (Required) The token used to authenticate the runner to run
- `url` - (Required) The URL of the runner to run
- `name` - (Optional) The name of the runner
- `project_id` - (Optional) The project_id you want to attach the resource to
- `zone` - (Optional) The zone of the runner

## Attributes Reference

- `id` - The ID of the runner.
- `status` - The status of the runner
- `labels` - A list of labels applied to the runner. Only for github provider
- `error_message` - The error message if the runner is in error state

## Import

Runner can be imported using the `{zone}/{id}`, e.g.

```bash
terraform import scaleway_apple_silicon_runner.main fr-par-1/11111111-1111-1111-1111-111111111111
```
220 changes: 220 additions & 0 deletions internal/services/applesilicon/runner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
package applesilicon

import (
"context"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
applesilicon "github.com/scaleway/scaleway-sdk-go/api/applesilicon/v1alpha1"
"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/httperrors"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/zonal"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/account"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/types"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
)

func ResourceRunner() *schema.Resource {
return &schema.Resource{
CreateContext: ResourceAppleSiliconRunnerCreate,
ReadContext: ResourceAppleSiliconRunnerRead,
UpdateContext: ResourceAppleSiliconRunnerUpdate,
DeleteContext: ResourceAppleSiliconRunnerDelete,
Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(5 * time.Minute),
Default: schema.DefaultTimeout(5 * time.Minute),
},
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
SchemaVersion: 0,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Description: "The name of the runner",
Computed: true,
Optional: true,
},
"ci_provider": {
Type: schema.TypeString,
Required: true,
Description: "The CI/CD provider for the runner. Must be either 'github' or 'gitlab'",
ValidateDiagFunc: verify.ValidateEnum[applesilicon.RunnerConfigurationProvider](),
},
"url": {
Type: schema.TypeString,
Required: true,
Description: "The URL of the runner to run",
},
"token": {
Type: schema.TypeString,
Sensitive: true,
Required: true,
Description: "The token used to authenticate the runner to run",
},
"labels": {
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Computed: true,
Description: "A list of labels that should be applied to the runner.",
},
"status": {
Type: schema.TypeString,
Computed: true,
Description: "The status of the runner",
},
"error_message": {
Type: schema.TypeString,
Computed: true,
Description: "The error message of the runner",
},
"zone": zonal.Schema(),
"project_id": account.ProjectIDSchema(),
},
}
}

func ResourceAppleSiliconRunnerCreate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
asAPI, zone, err := newAPIWithZone(d, m)
if err != nil {
return diag.FromErr(err)
}

provider := d.Get("ci_provider").(string)

runnerConfig := &applesilicon.RunnerConfigurationV2{
Name: d.Get("name").(string),
Provider: applesilicon.RunnerConfigurationV2Provider(provider),
GithubConfiguration: nil,
GitlabConfiguration: nil,
}

if provider == "github" {
runnerConfig.GithubConfiguration = &applesilicon.GithubRunnerConfiguration{
URL: d.Get("url").(string),
Token: d.Get("token").(string),
Labels: nil,
}
}

if provider == "gitlab" {
runnerConfig.GitlabConfiguration = &applesilicon.GitlabRunnerConfiguration{
URL: d.Get("url").(string),
Token: d.Get("token").(string),
}
}

createRunnerReq := &applesilicon.CreateRunnerRequest{
Zone: zone,
ProjectID: d.Get("project_id").(string),
RunnerConfiguration: runnerConfig,
}

runner, err := asAPI.CreateRunner(createRunnerReq, scw.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}

d.SetId(zonal.NewIDString(zone, runner.ID))

return ResourceAppleSiliconRunnerRead(ctx, d, m)
}

func ResourceAppleSiliconRunnerRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
asAPI, zone, ID, err := NewAPIWithZoneAndID(m, d.Id())
if err != nil {
return diag.FromErr(err)
}

runner, err := asAPI.GetRunner(&applesilicon.GetRunnerRequest{
Zone: zone,
RunnerID: ID,
}, scw.WithContext(ctx))
if err != nil {
if httperrors.Is404(err) {
d.SetId("")

return nil
}
return diag.FromErr(err)
}

_ = d.Set("name", runner.Configuration.Name)
_ = d.Set("ci_provider", runner.Configuration.Provider)
_ = d.Set("status", runner.Status)
_ = d.Set("error_message", runner.ErrorMessage)

if runner.Configuration.Provider == "github" {
_ = d.Set("url", runner.Configuration.GithubConfiguration.URL)
_ = d.Set("labels", runner.Configuration.GithubConfiguration.Labels)
}

if runner.Configuration.Provider == "gitlab" {
_ = d.Set("url", runner.Configuration.GitlabConfiguration.URL)
}

return nil
}

func ResourceAppleSiliconRunnerUpdate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
asAPI, zone, ID, err := NewAPIWithZoneAndID(m, d.Id())
if err != nil {
return diag.FromErr(err)
}

provider := d.Get("ci_provider").(string)

runnerConfig := &applesilicon.RunnerConfigurationV2{
Name: d.Get("name").(string),
Provider: applesilicon.RunnerConfigurationV2Provider(provider),
GithubConfiguration: nil,
GitlabConfiguration: nil,
}

if provider == "github" {
runnerConfig.GithubConfiguration = &applesilicon.GithubRunnerConfiguration{
URL: d.Get("url").(string),
Token: d.Get("token").(string),
Labels: types.ExpandStrings(d.Get("labels")),
}
}

if provider == "gitlab" {
runnerConfig.GitlabConfiguration = &applesilicon.GitlabRunnerConfiguration{
URL: d.Get("url").(string),
Token: d.Get("token").(string),
}
}

updateRunnerReq := &applesilicon.UpdateRunnerRequest{
Zone: zone,
RunnerID: ID,
RunnerConfiguration: runnerConfig,
}

_, err = asAPI.UpdateRunner(updateRunnerReq, scw.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}

return ResourceAppleSiliconRunnerRead(ctx, d, m)
}

func ResourceAppleSiliconRunnerDelete(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
asAPI, zone, ID, err := NewAPIWithZoneAndID(m, d.Id())
if err != nil {
return diag.FromErr(err)
}
runnerDeleteReq := &applesilicon.DeleteRunnerRequest{
Zone: zone,
RunnerID: ID,
}
err = asAPI.DeleteRunner(runnerDeleteReq, scw.WithContext(ctx))
if err != nil && !httperrors.Is403(err) {
return diag.FromErr(err)
}
return nil
}
113 changes: 113 additions & 0 deletions internal/services/applesilicon/runner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package applesilicon_test

import (
"fmt"
"os"
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
applesiliconSDK "github.com/scaleway/scaleway-sdk-go/api/applesilicon/v1alpha1"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/acctest"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/httperrors"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/applesilicon"
)

func TestAccRunner_BasicGithub(t *testing.T) {
tt := acctest.NewTestTools(t)
defer tt.Cleanup()
t.Skip("can not register this cassette for security issue")
var githubUrl = os.Getenv("GITHUB_URL_AS")
var githubToken = os.Getenv("GITHUB_TOKEN_AS")

resource.ParallelTest(t, resource.TestCase{
ProtoV6ProviderFactories: tt.ProviderFactories,
CheckDestroy: isRunnerDestroyed(tt),
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource "scaleway_apple_silicon_runner" "main" {
name = "TestAccRunnerGithub"
ci_provider = "github"
url = "%s"
token = "%s"
}
`, githubUrl, githubToken),
Check: resource.ComposeTestCheckFunc(
isRunnerPresent(tt, "scaleway_apple_silicon_runner.main"),
resource.TestCheckResourceAttr("scaleway_apple_silicon_runner.main", "name", "TestAccRunnerGithub"),
resource.TestCheckResourceAttr("scaleway_apple_silicon_runner.main", "ci_provider", "github"),
resource.TestCheckResourceAttr("scaleway_apple_silicon_runner.main", "url", githubUrl),

// Computed
resource.TestCheckResourceAttrSet("scaleway_apple_silicon_runner.main", "status"),
),
},
{
Config: fmt.Sprintf(`
resource "scaleway_apple_silicon_runner" "main" {
name = "TestAccRunnerGithubUpdated"
ci_provider = "github"
url = "%s"
token = "%s"
}
`, githubUrl, githubToken),
Check: resource.ComposeTestCheckFunc(
isRunnerPresent(tt, "scaleway_apple_silicon_runner.main"),
resource.TestCheckResourceAttr("scaleway_apple_silicon_runner.main", "name", "TestAccRunnerGithubUpdated"),
),
},
},
})
}

func isRunnerPresent(tt *acctest.TestTools, resourceName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return fmt.Errorf("resource not found: %s", resourceName)
}

api, zone, id, err := applesilicon.NewAPIWithZoneAndID(tt.Meta, rs.Primary.ID)
if err != nil {
return err
}

_, err = api.GetRunner(&applesiliconSDK.GetRunnerRequest{
Zone: zone,
RunnerID: id,
})

return err
}
}

func isRunnerDestroyed(tt *acctest.TestTools) resource.TestCheckFunc {
return func(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
if rs.Type != "scaleway_apple_silicon_runner" {
continue
}

api, zone, id, err := applesilicon.NewAPIWithZoneAndID(tt.Meta, rs.Primary.ID)
if err != nil {
return err
}

_, err = api.GetRunner(&applesiliconSDK.GetRunnerRequest{
Zone: zone,
RunnerID: id,
})

if err == nil {
return fmt.Errorf("runner still exists: %s", rs.Primary.ID)
}

if !httperrors.Is403(err) {
return fmt.Errorf("unexpected error: %s", err)
}
}

return nil
}
}
Loading
Loading