diff --git a/go.mod b/go.mod index 7d0170e..60cca6e 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 github.com/hashicorp/terraform-plugin-log v0.9.0 github.com/mitchellh/go-homedir v1.1.0 - github.com/pluralsh/console-client-go v0.1.16 + github.com/pluralsh/console-client-go v0.1.17 github.com/pluralsh/plural-cli v0.8.5-0.20240216094552-efc34ee6de37 github.com/pluralsh/polly v0.1.7 github.com/samber/lo v1.38.1 diff --git a/go.sum b/go.sum index f66519a..dcdc0a2 100644 --- a/go.sum +++ b/go.sum @@ -856,8 +856,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pluralsh/console-client-go v0.1.16 h1:f+d4ah3r+dAJ6hSMFsAmTlps4IsmExCzkCOwUpSYkbs= -github.com/pluralsh/console-client-go v0.1.16/go.mod h1:eyCiLA44YbXiYyJh8303jk5JdPkt9McgCo5kBjk4lKo= +github.com/pluralsh/console-client-go v0.1.17 h1:QMtnWdRvV13/sND/CFjFBUR8nyg3JJgwXReSyM6bK7A= +github.com/pluralsh/console-client-go v0.1.17/go.mod h1:eyCiLA44YbXiYyJh8303jk5JdPkt9McgCo5kBjk4lKo= github.com/pluralsh/gqlclient v1.11.0 h1:FfXW7FiEJLHOfTAa7NxDb8jb3aMZNIpCAcG+bg8uHYA= github.com/pluralsh/gqlclient v1.11.0/go.mod h1:qSXKUlio1F2DRPy8el4oFYsmpKbkUYspgPB87T4it5I= github.com/pluralsh/plural-cli v0.8.5-0.20240216094552-efc34ee6de37 h1:DBnaKvKmbTbKwbkrh/2gJBwyHYfaXdxeT3UGh+94K4g= diff --git a/internal/resource/cluster.go b/internal/resource/cluster.go index 26ce893..05e9d99 100644 --- a/internal/resource/cluster.go +++ b/internal/resource/cluster.go @@ -71,7 +71,7 @@ func (r *clusterResource) Create(ctx context.Context, req resource.CreateRequest return } - handler, err := NewOperatorHandler(ctx, data.GetKubeconfig(), data.HelmRepoUrl.ValueString(), data.HelmValues.ValueStringPointer(), r.consoleUrl) + handler, err := NewOperatorHandler(ctx, r.client, data.GetKubeconfig(), data.HelmRepoUrl.ValueString(), data.HelmValues.ValueStringPointer(), r.consoleUrl) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to init operator handler, got error: %s", err)) return diff --git a/internal/resource/cluster_kubeconfig.go b/internal/resource/cluster_kubeconfig.go index f94d91d..f1cc462 100644 --- a/internal/resource/cluster_kubeconfig.go +++ b/internal/resource/cluster_kubeconfig.go @@ -8,15 +8,15 @@ import ( "time" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/pluralsh/polly/algorithms" - "github.com/samber/lo" - "k8s.io/client-go/discovery/cached/disk" - "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/mitchellh/go-homedir" + "github.com/pluralsh/polly/algorithms" + "github.com/samber/lo" "k8s.io/apimachinery/pkg/api/meta" apimachineryschema "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/discovery" + "k8s.io/client-go/discovery/cached/disk" + "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/restmapper" "k8s.io/client-go/tools/clientcmd" @@ -27,6 +27,14 @@ type KubeConfig struct { ClientConfig clientcmd.ClientConfig } +func (k *KubeConfig) ToClientSet() (*kubernetes.Clientset, error) { + config, err := k.ToRawKubeConfigLoader().ClientConfig() + if err != nil { + return nil, err + } + return kubernetes.NewForConfig(config) +} + func (k *KubeConfig) ToRESTConfig() (*rest.Config, error) { return k.ToRawKubeConfigLoader().ClientConfig() } diff --git a/internal/resource/cluster_operator_handler.go b/internal/resource/cluster_operator_handler.go index fdb8b36..4cc0efe 100644 --- a/internal/resource/cluster_operator_handler.go +++ b/internal/resource/cluster_operator_handler.go @@ -5,6 +5,8 @@ import ( "fmt" "time" + "terraform-provider-plural/internal/client" + "github.com/pluralsh/plural-cli/pkg/console" "github.com/pluralsh/plural-cli/pkg/helm" "github.com/pluralsh/polly/algorithms" @@ -15,10 +17,17 @@ import ( "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/release" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" "sigs.k8s.io/yaml" ) type OperatorHandler struct { + client *client.Client + + kube *kubernetes.Clientset + ctx context.Context // kubeconfig is a model.Kubeconfig data model read from terraform @@ -48,6 +57,11 @@ func (oh *OperatorHandler) init() error { if err != nil { return err } + kube, err := kubeconfig.ToClientSet() + if err != nil { + return err + } + oh.kube = kube err = oh.configuration.Init(kubeconfig, console.OperatorNamespace, "", logrus.Debugf) if err != nil { @@ -138,17 +152,50 @@ func (oh *OperatorHandler) listReleases(state action.ListStates) ([]*release.Rel return client.Run() } -func (oh *OperatorHandler) values(token string) map[string]interface{} { +func (oh *OperatorHandler) values(token string) (map[string]interface{}, error) { + globalVals := map[string]interface{}{} vals := map[string]interface{}{ "secrets": map[string]string{ "deployToken": token, }, "consoleUrl": fmt.Sprintf("%s/ext/gql", oh.url), } - return algorithms.Merge(vals, oh.vals) + + setting, err := oh.client.GetDeploymentSettings(oh.ctx) + if err != nil { + return nil, err + } + if setting != nil && setting.DeploymentSettings != nil && setting.DeploymentSettings.AgentHelmValues != nil { + if err := yaml.Unmarshal([]byte(*setting.DeploymentSettings.AgentHelmValues), &globalVals); err != nil { + return nil, err + } + } + return algorithms.Merge(vals, oh.vals, globalVals), nil +} + +func (oh *OperatorHandler) UpsertNamespace() error { + _, err := oh.kube.CoreV1().Namespaces().Get(oh.ctx, console.OperatorNamespace, metav1.GetOptions{}) + if err == nil { + return nil + } + + _, err = oh.kube.CoreV1().Namespaces().Create(oh.ctx, &v1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: console.OperatorNamespace, + Labels: map[string]string{ + "app.kubernetes.io/managed-by": "plural", + "app.plural.sh/name": console.OperatorNamespace, + }, + }, + }, metav1.CreateOptions{}) + + return err } func (oh *OperatorHandler) InstallOrUpgrade(token string) error { + if err := oh.UpsertNamespace(); err != nil { + return err + } exists, err := oh.chartExists() if err != nil { return err @@ -162,12 +209,20 @@ func (oh *OperatorHandler) InstallOrUpgrade(token string) error { } func (oh *OperatorHandler) Install(token string) error { - _, err := oh.install.Run(oh.chart, oh.values(token)) + values, err := oh.values(token) + if err != nil { + return err + } + _, err = oh.install.Run(oh.chart, values) return err } func (oh *OperatorHandler) Upgrade(token string) error { - _, err := oh.upgrade.Run(console.ReleaseName, oh.chart, oh.values(token)) + values, err := oh.values(token) + if err != nil { + return err + } + _, err = oh.upgrade.Run(console.ReleaseName, oh.chart, values) return err } @@ -176,7 +231,7 @@ func (oh *OperatorHandler) Uninstall() error { return err } -func NewOperatorHandler(ctx context.Context, kubeconfig *Kubeconfig, repoUrl string, values *string, consoleUrl string) (*OperatorHandler, error) { +func NewOperatorHandler(ctx context.Context, client *client.Client, kubeconfig *Kubeconfig, repoUrl string, values *string, consoleUrl string) (*OperatorHandler, error) { vals := map[string]interface{}{} if values != nil { if err := yaml.Unmarshal([]byte(*values), &vals); err != nil { @@ -185,6 +240,7 @@ func NewOperatorHandler(ctx context.Context, kubeconfig *Kubeconfig, repoUrl str } handler := &OperatorHandler{ + client: client, ctx: ctx, kubeconfig: kubeconfig, repoUrl: repoUrl,