245 lines
6.3 KiB
Go
245 lines
6.3 KiB
Go
// Copyright IBM Corp. 2020, 2026
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package provider
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"repo.anhonesthost.net/CyberCoveLLC/threshold/api"
|
|
"repo.anhonesthost.net/CyberCoveLLC/threshold/api/scopes"
|
|
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
|
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
|
|
)
|
|
|
|
const (
|
|
aliasSuffixKey = "alias_suffix"
|
|
)
|
|
|
|
func resourceScopeAliasSuffix() *schema.Resource {
|
|
return &schema.Resource{
|
|
Description: "The scope alias suffix resource allows you to set an alias suffix for an org or project scope. " +
|
|
"Global scopes are not valid for alias suffix operations.",
|
|
|
|
CreateContext: resourceScopeAliasSuffixCreate,
|
|
UpdateWithoutTimeout: resourceScopeAliasSuffixUpdate,
|
|
ReadWithoutTimeout: resourceScopeAliasSuffixRead,
|
|
DeleteWithoutTimeout: resourceScopeAliasSuffixDelete,
|
|
|
|
Importer: &schema.ResourceImporter{
|
|
StateContext: schema.ImportStatePassthroughContext,
|
|
},
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
ScopeIdKey: {
|
|
Description: "The scope ID. Alias suffixes are supported for org and project scopes.",
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
aliasSuffixKey: {
|
|
Description: "The alias suffix value for this scope.",
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func resourceScopeAliasSuffixCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
|
md := meta.(*metaData)
|
|
scp := scopes.NewClient(md.client)
|
|
opts := []scopes.Option{scopes.WithAutomaticVersioning(true)}
|
|
|
|
scopeId, err := scopeIdFromAliasSuffixResourceData(d)
|
|
if err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
if err := validateAliasSuffixScope(scopeId); err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
var aliasSuffix string
|
|
if aliasSuffixVal, ok := d.GetOk(aliasSuffixKey); ok {
|
|
aliasSuffix = aliasSuffixVal.(string)
|
|
} else {
|
|
return diag.Errorf("no alias suffix provided")
|
|
}
|
|
|
|
if _, err := scp.SetAliasSuffix(ctx, scopeId, 0, aliasSuffix, opts...); err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
if err := setScopeAliasSuffixState(d, scopeId, aliasSuffix); err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func resourceScopeAliasSuffixRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
|
md := meta.(*metaData)
|
|
scp := scopes.NewClient(md.client)
|
|
|
|
scopeId, err := scopeIdFromAliasSuffixResourceData(d)
|
|
if err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
s, err := scp.Read(ctx, scopeId)
|
|
if err != nil {
|
|
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound {
|
|
// the scope is gone, destroy this resource
|
|
d.SetId("")
|
|
return nil
|
|
}
|
|
return diag.Errorf("error reading scope: %v", err)
|
|
}
|
|
if s == nil {
|
|
return diag.Errorf("scope nil after read")
|
|
}
|
|
if s.GetResponse() == nil {
|
|
return diag.Errorf("scope response nil after read")
|
|
}
|
|
|
|
serverAliasSuffix, err := aliasSuffixFromScopeResponseMap(s.GetResponse().Map)
|
|
if err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
if serverAliasSuffix == "" {
|
|
// no alias suffix is currently set on this scope, destroy this resource
|
|
d.SetId("")
|
|
return nil
|
|
}
|
|
|
|
if err := setScopeAliasSuffixState(d, scopeId, serverAliasSuffix); err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func resourceScopeAliasSuffixUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
|
md := meta.(*metaData)
|
|
scp := scopes.NewClient(md.client)
|
|
opts := []scopes.Option{scopes.WithAutomaticVersioning(true)}
|
|
|
|
scopeId, err := scopeIdFromAliasSuffixResourceData(d)
|
|
if err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
if err := validateAliasSuffixScope(scopeId); err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
var aliasSuffix string
|
|
if aliasSuffixVal, ok := d.GetOk(aliasSuffixKey); ok {
|
|
aliasSuffix = aliasSuffixVal.(string)
|
|
} else {
|
|
return diag.Errorf("no alias suffix provided")
|
|
}
|
|
|
|
if _, err := scp.SetAliasSuffix(ctx, scopeId, 0, aliasSuffix, opts...); err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
if err := setScopeAliasSuffixState(d, scopeId, aliasSuffix); err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func resourceScopeAliasSuffixDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
|
md := meta.(*metaData)
|
|
scp := scopes.NewClient(md.client)
|
|
opts := []scopes.Option{scopes.WithAutomaticVersioning(true)}
|
|
|
|
scopeId, err := scopeIdFromAliasSuffixResourceData(d)
|
|
if err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
if err := validateAliasSuffixScope(scopeId); err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
if _, err := scp.RemoveAliasSuffix(ctx, scopeId, 0, opts...); err != nil {
|
|
return diag.FromErr(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func aliasSuffixFromScopeResponseMap(raw map[string]interface{}) (string, error) {
|
|
if raw == nil {
|
|
return "", fmt.Errorf("scope response map nil after read")
|
|
}
|
|
|
|
aliasSuffixRaw, ok := raw[aliasSuffixKey]
|
|
if !ok || aliasSuffixRaw == nil {
|
|
return "", nil
|
|
}
|
|
|
|
aliasSuffix, ok := aliasSuffixRaw.(string)
|
|
if !ok {
|
|
return "", fmt.Errorf("alias suffix in scope response has unexpected type %T", aliasSuffixRaw)
|
|
}
|
|
|
|
return aliasSuffix, nil
|
|
}
|
|
|
|
func setScopeAliasSuffixState(d *schema.ResourceData, scopeId, aliasSuffix string) error {
|
|
if err := d.Set(ScopeIdKey, scopeId); err != nil {
|
|
return err
|
|
}
|
|
if err := d.Set(aliasSuffixKey, aliasSuffix); err != nil {
|
|
return err
|
|
}
|
|
|
|
// One alias suffix may be set per scope, so scope ID is the stable TF ID.
|
|
d.SetId(scopeId)
|
|
|
|
return nil
|
|
}
|
|
|
|
func validateAliasSuffixScope(scopeId string) error {
|
|
switch {
|
|
case strings.HasPrefix(scopeId, orgScopePrefix):
|
|
return nil
|
|
case strings.HasPrefix(scopeId, projectScopePrefix):
|
|
return nil
|
|
case scopeId == globalScopeId:
|
|
return fmt.Errorf("alias suffixes are not supported for the global scope; use an org or project scope ID")
|
|
default:
|
|
return fmt.Errorf("alias suffixes are supported only for org and project scopes")
|
|
}
|
|
}
|
|
|
|
func scopeIdFromAliasSuffixResourceData(d *schema.ResourceData) (string, error) {
|
|
if scopeIdVal, ok := d.GetOk(ScopeIdKey); ok {
|
|
scopeId := scopeIdVal.(string)
|
|
if scopeId != "" {
|
|
return scopeId, nil
|
|
}
|
|
}
|
|
|
|
id := d.Id()
|
|
if id == "" {
|
|
return "", fmt.Errorf("no scope ID provided")
|
|
}
|
|
|
|
// Backward-compatibility for any prior state that used alias_suffix:scope_id.
|
|
if index := strings.LastIndex(id, ":"); index >= 0 && index < len(id)-1 {
|
|
return id[index+1:], nil
|
|
}
|
|
|
|
return id, nil
|
|
}
|