cleanup PR + add todos

This commit is contained in:
Adrian Stobbe 2023-07-17 15:13:49 +02:00
parent 7eca66b5eb
commit 93ee733a80
23 changed files with 82 additions and 164 deletions

View File

@ -110,11 +110,13 @@ func (u *upgradeApplyCmd) upgradeApply(cmd *cobra.Command, fileHandler file.Hand
if err := u.upgradeAttestConfigIfDiff(cmd, conf.GetAttestationConfig(), flags); err != nil {
return fmt.Errorf("upgrading measurements: %w", err)
}
// TODO refactor to place updateID creation outside of upgrader and then remove this method
tfClient, err := u.upgrader.GetTerraformUpgrader(cmd.Context(), constants.TerraformIAMUpgradeWorkingDir)
if err != nil {
return fmt.Errorf("getting terraform client: %w", err)
}
migrateIAM := getIAMMigrateCmd(cmd, tfClient, conf, flags, u.upgrader.GetUpgradeID())
// TODO put terraform migration into cmd as well
if err := u.executeMigration(cmd, fileHandler, migrateIAM, flags); err != nil {
return fmt.Errorf("executing IAM migration: %w", err)
}

View File

@ -380,8 +380,6 @@ go_library(
"charts/aws-load-balancer-controller/.helmignore",
"charts/aws-load-balancer-controller/Chart.yaml",
"charts/aws-load-balancer-controller/README.md",
"charts/aws-load-balancer-controller/ci/extra_args",
"charts/aws-load-balancer-controller/ci/values.yaml",
"charts/aws-load-balancer-controller/crds/crds.yaml",
"charts/aws-load-balancer-controller/templates/NOTES.txt",
"charts/aws-load-balancer-controller/templates/_helpers.tpl",

View File

@ -1 +0,0 @@
--set clusterName=k8s-ci-cluster

View File

@ -1,7 +0,0 @@
# CI testing values for aws-load-balancer-controller
region: us-west-2
image:
repository: public.ecr.aws/eks/aws-load-balancer-controller
tag: v2.4.5
pullPolicy: Always

View File

@ -21,6 +21,3 @@
.idea/
*.tmproj
.vscode/
#charts/aws-load-balancer-controller/crds/kustomization.yaml
#charts/aws-load-balancer-controller/test.yaml

View File

@ -1,6 +1,3 @@
#aws-load-balancer-controller:
#fullnameOverride: aws-load-balancer-controller
global:
# Port on which the KeyService will listen. Global since join-service also uses the value.
keyServicePort: 9000

View File

@ -10,7 +10,6 @@ import (
"context"
"errors"
"fmt"
"os"
"strings"
"time"
@ -56,7 +55,7 @@ type Client struct {
// NewClient returns a new initializes client for the namespace Client.
func NewClient(client crdClient, kubeConfigPath, helmNamespace string, log debugLog) (*Client, error) {
settings := cli.New()
settings.KubeConfig = kubeConfigPath // constants.AdminConfFilename
settings.KubeConfig = kubeConfigPath
actionConfig := &action.Configuration{}
if err := actionConfig.Init(settings.RESTClientGetter(), helmNamespace, "secret", log.Debugf); err != nil {
@ -114,13 +113,13 @@ func (c *Client) Upgrade(ctx context.Context, config *config.Config, idFile clus
// TODO refactor to GetCharts(provider) ?
if config.GetProvider() == cloudprovider.AWS {
svcVersions, err := c.Versions()
c.log.Debugf("Apply %s", svcVersions.awsLoadBalancerController)
if err != nil {
return fmt.Errorf("getting versions: %w", err)
}
c.log.Debugf("Upgrade %s", svcVersions.awsLoadBalancerController)
// install instead of upgrade if the awsLoadBalancerController is not installed yet
if svcVersions.awsLoadBalancerController == "" {
c.log.Debugf("installing aws load balancer controller")
c.log.Debugf("Installing aws-load-balancer-controller")
k8sVersion, err := versions.NewValidK8sVersion(config.KubernetesVersion, false)
if err != nil {
return fmt.Errorf("validating k8s version: %s", config.KubernetesVersion)
@ -131,11 +130,11 @@ func (c *Client) Upgrade(ctx context.Context, config *config.Config, idFile clus
i: loader,
}
builder.AddChart(awsInfo)
release, err := builder.Load(helm.WaitModeAtomic) // TODO configurable
release, err := builder.Load(helm.WaitModeAtomic) // TODO make configurable
if err != nil {
return fmt.Errorf("loading chart: %w", err)
}
kubeconfig := os.Getenv("KUBECONFIG") // TODO
kubeconfig := constants.AdminConfFilename // TODO: get path as arg ,os.Getenv("KUBECONFIG")
installer, err := New(logger.New(logger.PlainLog, -1), kubeconfig)
if err != nil {
return fmt.Errorf("creating installer: %w", err)
@ -235,7 +234,6 @@ func (c *Client) Versions() (ServiceVersions, error) {
if err != nil {
var releaseNotFoundError *ReleaseNotFoundError
if !errors.As(err, &releaseNotFoundError) {
fmt.Println("IS THIS THE PROBLEM?")
return ServiceVersions{}, fmt.Errorf("getting %s version: %w", awsInfo.releaseName, err)
}
}
@ -248,10 +246,12 @@ func (c *Client) Versions() (ServiceVersions, error) {
}, nil
}
// ReleaseNotFoundError is returned when a helm release is not found.
type ReleaseNotFoundError struct {
ReleaseName string
}
// Error returns the error message.
func (e *ReleaseNotFoundError) Error() string {
return fmt.Sprintf("release %s not found", e.ReleaseName)
}
@ -326,7 +326,7 @@ func (c *Client) upgradeRelease(
return fmt.Errorf("validating k8s version: %s", conf.KubernetesVersion)
}
c.log.Debugf("Checking cluster ID file")
c.log.Debugf("Checking cluster ID file to determine cluster name")
clusterName := clusterid.GetClusterName(conf.Name, idFile)
loader := NewLoader(conf.GetProvider(), k8sVersion, clusterName)

View File

@ -23,6 +23,9 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
)
// TODO clenaup once agreed on design
// TODO delete only used for manual test
func Install(kubeconfig string) {
loader := NewLoader(cloudprovider.AWS, "v1.26.6", "constell-aws")
builder := ChartBuilder{
@ -54,12 +57,6 @@ func Install(kubeconfig string) {
}
}
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
const (
// timeout is the maximum time given to the helm Installer.
timeout = 5 * time.Minute

View File

@ -114,6 +114,7 @@ func (b *ChartBuilder) AddChart(info chartInfo) {
b.charts = append(b.charts, info)
}
// TODO only supports AWS for now (discuss design first)
func (b *ChartBuilder) Load(helmWaitMode helm.WaitMode) (helm.Releases, error) {
var releases helm.Releases
for _, info := range b.charts {
@ -126,8 +127,6 @@ func (b *ChartBuilder) Load(helmWaitMode helm.WaitMode) (helm.Releases, error) {
return releases, nil
}
type HelmInstaller struct{}
// Load the embedded helm charts.
func (i *ChartLoader) Load(config *config.Config, conformanceMode bool, helmWaitMode helm.WaitMode, masterSecret, salt []byte) ([]byte, error) {
ciliumRelease, err := i.loadRelease(ciliumInfo, helmWaitMode)
@ -456,6 +455,7 @@ func (i *ChartLoader) loadConstellationServicesValues() (map[string]any, error)
"AWS": true,
}
values["aws-load-balancer-controller"] = map[string]any{
// TODO: nodeSelector is already set in (customized) values.yaml. Should we have a custom values.yaml instead of configuring here for easier testing?
"nodeSelector": map[string]any{
"node-role.kubernetes.io/control-plane": "",
},

View File

@ -51,6 +51,7 @@ func TestLoad(t *testing.T) {
assert.NotNil(chart.Dependencies())
}
// TODO discuss: this test passes with current code only since we delete crds/kustomization.yaml in update-aws-load-balancer-controller.sh . Our current implementation does not support this!
func TestIgnoreFilesInSubdirectory(t *testing.T) {
fileToIgnore := "crds/kustomization.yaml"
chart, err := loadChartsDir(helmFS, awsInfo.path)
@ -62,6 +63,7 @@ func TestIgnoreFilesInSubdirectory(t *testing.T) {
}
}
// TODO discuss: this works in test but fails in real code when using newer symwalk implementation
func TestLoadChartYaml(t *testing.T) {
expectToLoad := "Chart.yaml"
chart, err := loadChartsDir(helmFS, ciliumInfo.path)
@ -180,14 +182,8 @@ func TestConstellationServices(t *testing.T) {
gcpGuestAgentImage: "gcpGuestAgentImage",
clusterName: "testCluster",
}
chart, err := loadChartsDir(helmFS, constellationServicesInfo.path) // helmFS, "./charts/edgeless/constellation-services/charts/aws-load-balancer-controller") //
chart, err := loadChartsDir(helmFS, constellationServicesInfo.path)
require.NoError(err)
for _, f := range chart.Raw {
// fmt.Println("UNFILTERED", f.Name)
if strings.Contains(f.Name, "crds") {
fmt.Println("FOUND", f.Name)
}
}
values, err := chartLoader.loadConstellationServicesValues()
require.NoError(err)
err = extendConstellationServicesValues(values, tc.config, []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))

View File

@ -1,15 +0,0 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "main_lib",
srcs = ["main.go"],
importpath = "github.com/edgelesssys/constellation/v2/cli/internal/helm/main",
visibility = ["//visibility:private"],
deps = ["//cli/internal/helm"],
)
go_binary(
name = "main",
embed = [":main_lib"],
visibility = ["//cli:__subpackages__"],
)

View File

@ -1,11 +0,0 @@
package main
import (
"os"
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
)
func main() {
helm.Install(os.Getenv("KUBECONFIG")) // constants.ControlPlaneAdminConfFilename)
}

View File

@ -6,6 +6,8 @@ SPDX-License-Identifier: AGPL-3.0-only
package helm
// TODO discuss if we want newer implementation with subdir support for .helmignore
import (
"log"
"os"

View File

@ -39,6 +39,7 @@ cd "${callDir}"
# remove values.yaml from upstream chart
rm "${repo_tmp_dir}/${chart_dir}/values.yaml"
# remoe files being ignored in .helmignore due to wrong import of .helmignore in current implementation
rm -r "${repo_tmp_dir}/${chart_dir}/ci"
rm "${repo_tmp_dir}/${chart_dir}/crds/kustomization.yaml"
rm "${repo_tmp_dir}/${chart_dir}/test.yaml"

View File

@ -153,6 +153,7 @@ func NewUpgrader(ctx context.Context, outWriter io.Writer, log debugLog, upgrade
return u, nil
}
// TODO discuss: remove
func (u *Upgrader) GetTerraformUpgrader(ctx context.Context, terraformDir string) (*terraform.Client, error) {
tfClient, err := terraform.New(ctx, filepath.Join(constants.UpgradeDir, u.upgradeID, terraformDir))
if err != nil {
@ -161,6 +162,7 @@ func (u *Upgrader) GetTerraformUpgrader(ctx context.Context, terraformDir string
return tfClient, nil
}
// TODO remove
func (u *Upgrader) GetUpgradeID() string {
return u.upgradeID
}

View File

@ -25,12 +25,14 @@ type tfClient interface {
CreateIAMConfig(ctx context.Context, csp cloudprovider.Provider, logLevel LogLevel) (IAMOutput, error)
}
// MigrationCmd is an interface for all terraform upgrade / migration commands.
type MigrationCmd interface {
Plan(ctx context.Context) (bool, error)
Apply(ctx context.Context, fileHandler file.Handler) error
String() string
}
// IAMMigrateCmd is a terraform migration command for IAM.
type IAMMigrateCmd struct {
tf tfClient
upgradeID string
@ -39,6 +41,7 @@ type IAMMigrateCmd struct {
outWriter io.Writer
}
// NewIAMMigrateCmd creates a new IAMMigrateCmd.
func NewIAMMigrateCmd(tf tfClient, upgradeID string, csp cloudprovider.Provider, logLevel LogLevel, outWriter io.Writer) *IAMMigrateCmd {
return &IAMMigrateCmd{
tf: tf,
@ -49,17 +52,20 @@ func NewIAMMigrateCmd(tf tfClient, upgradeID string, csp cloudprovider.Provider,
}
}
// String returns the name of the command.
func (c *IAMMigrateCmd) String() string {
return "iam migration"
}
// Plan prepares the upgrade workspace and plans the Terraform migrations for the Constellation upgrade, writing the plan to the outWriter.
// TODO put outWriter as argument
func (c *IAMMigrateCmd) Plan(ctx context.Context) (bool, error) {
templateDir := filepath.Join("terraform", "iam", strings.ToLower(c.csp.String()))
err := c.tf.PrepareIAMUpgradeWorkspace(
templateDir,
constants.TerraformIAMWorkingDir,
filepath.Join(constants.UpgradeDir, c.upgradeID, constants.TerraformIAMUpgradeWorkingDir),
filepath.Join(constants.UpgradeDir, c.upgradeID, constants.TerraformIAMUpgradeBackupDir), // TODO: use IAM backup dir
filepath.Join(constants.UpgradeDir, c.upgradeID, constants.TerraformIAMUpgradeBackupDir),
)
if err != nil {
return false, fmt.Errorf("preparing terraform workspace: %w", err)
@ -67,7 +73,7 @@ func (c *IAMMigrateCmd) Plan(ctx context.Context) (bool, error) {
hasDiff, err := c.tf.Plan(ctx, c.logLevel, constants.TerraformUpgradePlanFile)
if err != nil {
return false, fmt.Errorf("terraform plan 1: %w", err)
return false, fmt.Errorf("terraform plan: %w", err)
}
if hasDiff {
@ -79,11 +85,11 @@ func (c *IAMMigrateCmd) Plan(ctx context.Context) (bool, error) {
return hasDiff, nil
}
// Apply applies the Terraform IAM migrations for the Constellation upgrade.
func (c *IAMMigrateCmd) Apply(ctx context.Context, fileHandler file.Handler) error {
_, err := c.tf.CreateIAMConfig(ctx, c.csp, c.logLevel)
// TODO: put in template?
_, err := c.tf.CreateIAMConfig(ctx, c.csp, c.logLevel) // TODO rename CreateIAMConfig to ApplyIAMConfig to reflect usage for migration too
// TODO: put in template, since moving files is also done in other TF migrations
if err := fileHandler.RemoveAll(constants.TerraformIAMWorkingDir); err != nil {
return fmt.Errorf("removing old terraform directory: %w", err)
}

View File

@ -22,58 +22,62 @@ import (
)
func TestIAMMigrate(t *testing.T) {
// plan should copy the terraform files to the upgrade directory
// create upgrade dir
// show plan changes in outWriter
upgradeID := "test-upgrade"
upgradeDir := filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformIAMUpgradeWorkingDir)
tfClient, err := New(context.Background(), filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeWorkingDir))
require.NoError(t, err)
// prep fs
fs := afero.NewMemMapFs()
file := file.NewHandler(fs)
err = file.MkdirAll(constants.TerraformIAMWorkingDir)
require.NoError(t, err)
err = file.Write(filepath.Join(constants.TerraformIAMWorkingDir, "terraform.tfvars"), []byte("OLD"))
require.NoError(t, err)
err = file.Write(filepath.Join(constants.TerraformIAMWorkingDir, "terraform.tfstate"), []byte("OLD"))
require.NoError(t, err)
fs, file := setupMemFSAndFileHandler(t, []string{"terraform.tfvars", "terraform.tfstate"}, []byte("OLD"))
tfClient.file = file
writer := bytes.NewBuffer(nil)
// act
fakeTfClient := &tfClientStub{tfClient, upgradeID}
sut := NewIAMMigrateCmd(fakeTfClient, upgradeID, cloudprovider.AWS, LogLevelDebug, writer)
sut := NewIAMMigrateCmd(fakeTfClient, upgradeID, cloudprovider.AWS, LogLevelDebug, bytes.NewBuffer(nil))
hasDiff, err := sut.Plan(context.Background())
// assert
assert.NoError(t, err)
assert.False(t, hasDiff)
// check that files are copied
res, err := fs.Stat(filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformIAMUpgradeWorkingDir, "terraform.tfvars"))
assertFileExists(fs, filepath.Join(upgradeDir, "terraform.tfvars"), t)
assertFileExists(fs, filepath.Join(upgradeDir, "terraform.tfstate"), t)
assert.NoError(t, err)
assert.NotNil(t, res)
res, err = fs.Stat(filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformIAMUpgradeWorkingDir, "terraform.tfstate"))
assert.NoError(t, err)
assert.NotNil(t, res)
// apply
// act
err = sut.Apply(context.Background(), file)
assert.NoError(t, err)
// check that files are copied
bt, err := file.Read(filepath.Join(constants.TerraformIAMWorkingDir, "terraform.tfvars"))
assert.NoError(t, err)
assert.Equal(t, "NEW", string(bt))
bt, err = file.Read(filepath.Join(constants.TerraformIAMWorkingDir, "terraform.tfstate"))
assert.NoError(t, err)
assert.Equal(t, "NEW", string(bt))
// assert
assertFileReadsContent(file, filepath.Join(constants.TerraformIAMWorkingDir, "terraform.tfvars"), "NEW", t)
assertFileReadsContent(file, filepath.Join(constants.TerraformIAMWorkingDir, "terraform.tfstate"), "NEW", t)
assertFileDoesntExist(fs, filepath.Join(upgradeDir), t)
}
// upgrade dir should be removed
res, err = fs.Stat(filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformIAMUpgradeWorkingDir))
func assertFileReadsContent(file file.Handler, path string, expectedContent string, t *testing.T) {
bt, err := file.Read(path)
assert.NoError(t, err)
assert.Equal(t, expectedContent, string(bt))
}
func assertFileExists(fs afero.Fs, path string, t *testing.T) {
res, err := fs.Stat(path)
assert.NoError(t, err)
assert.NotNil(t, res)
}
func assertFileDoesntExist(fs afero.Fs, path string, t *testing.T) {
res, err := fs.Stat(path)
assert.Error(t, err)
assert.Nil(t, res)
}
res, err = fs.Stat(filepath.Join(constants.UpgradeDir, upgradeID, constants.TerraformUpgradeBackupDir))
assert.Error(t, err)
assert.Nil(t, res)
// setupMemFSAndFileHandler sets up a file handler with a memory file system and writes the given files with the given content.
func setupMemFSAndFileHandler(t *testing.T, files []string, content []byte) (afero.Fs, file.Handler) {
fs := afero.NewMemMapFs()
file := file.NewHandler(fs)
err := file.MkdirAll(constants.TerraformIAMWorkingDir)
require.NoError(t, err)
for _, f := range files {
err := file.Write(filepath.Join(constants.TerraformIAMWorkingDir, f), content)
require.NoError(t, err)
}
return fs, file
}
type tfClientStub struct {
@ -85,15 +89,15 @@ func (t *tfClientStub) PrepareIAMUpgradeWorkspace(rootDir, workingDir, newWorkin
return t.realClient.PrepareIAMUpgradeWorkspace(rootDir, workingDir, newWorkingDir, backupDir)
}
func (t *tfClientStub) Plan(ctx context.Context, logLevel LogLevel, planFile string) (bool, error) {
func (t *tfClientStub) Plan(_ context.Context, _ LogLevel, _ string) (bool, error) {
return false, nil
}
func (t *tfClientStub) ShowPlan(ctx context.Context, logLevel LogLevel, planFile string, outWriter io.Writer) error {
func (t *tfClientStub) ShowPlan(_ context.Context, _ LogLevel, _ string, _ io.Writer) error {
return nil
}
func (t *tfClientStub) CreateIAMConfig(ctx context.Context, csp cloudprovider.Provider, logLevel LogLevel) (IAMOutput, error) {
func (t *tfClientStub) CreateIAMConfig(_ context.Context, _ cloudprovider.Provider, _ LogLevel) (IAMOutput, error) {
upgradeDir := filepath.Join(constants.UpgradeDir, t.upgradeID, constants.TerraformIAMUpgradeWorkingDir)
err := t.realClient.file.Remove(filepath.Join(upgradeDir, "terraform.tfvars"))
if err != nil {

View File

@ -103,6 +103,7 @@ func (c *Client) PrepareUpgradeWorkspace(path, oldWorkingDir, newWorkingDir, bac
}
// PrepareIAMUpgradeWorkspace prepares a Terraform workspace for a Constellation IAM upgrade.
// TODO should be inside IAMMigrateCmd
func (c *Client) PrepareIAMUpgradeWorkspace(path, oldWorkingDir, newWorkingDir, backupDir string) error {
if err := prepareUpgradeWorkspace(path, c.file, oldWorkingDir, newWorkingDir, backupDir); err != nil {
return fmt.Errorf("prepare upgrade workspace: %w", err)

View File

@ -52,7 +52,7 @@ resource "aws_subnet" "private" {
vpc_id = var.vpc_id
cidr_block = cidrsubnet(var.cidr_vpc_subnet_nodes, 4, local.az_number[each.value.name_suffix])
availability_zone = each.key
tags = merge(var.tags, { Name = "${var.name}-subnet-nodes" }, { "kubernetes.io/role/internal-elb" = 1 })
tags = merge(var.tags, { Name = "${var.name}-subnet-nodes" }, { "kubernetes.io/role/internal-elb" = 1 }) # aws-load-balancer-controller needs role annotation
lifecycle {
ignore_changes = [
cidr_block, # required. Legacy subnets used fixed cidr blocks for the single zone that don't match the new scheme.
@ -65,7 +65,7 @@ resource "aws_subnet" "public" {
vpc_id = var.vpc_id
cidr_block = cidrsubnet(var.cidr_vpc_subnet_internet, 4, local.az_number[each.value.name_suffix])
availability_zone = each.key
tags = merge(var.tags, { Name = "${var.name}-subnet-internet" }, { "kubernetes.io/role/elb" = 1 })
tags = merge(var.tags, { Name = "${var.name}-subnet-internet" }, { "kubernetes.io/role/elb" = 1 }) # aws-load-balancer-controller needs role annotation
lifecycle {
ignore_changes = [
cidr_block, # required. Legacy subnets used fixed cidr blocks for the single zone that don't match the new scheme.

View File

@ -51,6 +51,7 @@ resource "aws_iam_policy" "control_plane_policy" {
{
"Effect": "Allow",
"Action": [
# roles for aws-load-balancer-controller
"ec2:DescribeSecurityGroups",
"ec2:DescribeInstances",
"elasticloadbalancing:DescribeTargetGroups",
@ -64,6 +65,7 @@ resource "aws_iam_policy" "control_plane_policy" {
"elasticloadbalancing:RegisterTargets",
"elasticloadbalancing:DeregisterTargets",
"elasticloadbalancing:DescribeTags",
# rest
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeLaunchConfigurations",
"autoscaling:DescribeTags",

View File

@ -1,19 +0,0 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "main_lib",
srcs = ["main.go"],
importpath = "github.com/edgelesssys/constellation/v2/cli/internal/upgrade/main",
visibility = ["//visibility:private"],
deps = [
"//cli/internal/terraform",
"//cli/internal/upgrade",
"//internal/constants",
],
)
go_binary(
name = "main",
embed = [":main_lib"],
visibility = ["//cli:__subpackages__"],
)

Binary file not shown.

View File

@ -1,34 +0,0 @@
package main
import (
"bytes"
"context"
"fmt"
"path/filepath"
"github.com/edgelesssys/constellation/v2/cli/internal/terraform"
"github.com/edgelesssys/constellation/v2/cli/internal/upgrade"
"github.com/edgelesssys/constellation/v2/internal/constants"
)
func main() {
ctx := context.Background()
tfClient, err := terraform.New(ctx, filepath.Join(constants.UpgradeDir, "test", constants.TerraformUpgradeWorkingDir))
if err != nil {
panic(fmt.Errorf("setting up terraform client: %w", err))
}
// give me a writer
outWriter := bytes.NewBuffer(nil)
tfUpgrader, err := upgrade.NewTerraformUpgrader(tfClient, outWriter)
if err != nil {
panic(fmt.Errorf("setting up terraform upgrader: %w", err))
}
//diff, err := tfUpgrader.PlanIAMMigration(ctx, upgrade.TerraformUpgradeOptions{
// CSP: cloudprovider.AWS,
// LogLevel: terraform.LogLevelDebug,
//}, "test")
//if err != nil {
// panic(fmt.Errorf("planning terraform migrations: %w", err))
//}
//fmt.Println(diff)
}