From e2bce47928ac79438547b10ddabf5a7a6a50cae3 Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Tue, 28 Nov 2023 09:32:24 +0100 Subject: [PATCH 01/26] Implement 'aws_ssm' connection type #26 --- internal/client/client_manager.go | 4 ++-- internal/client/connection_aws_ssm.go | 24 +++++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/internal/client/client_manager.go b/internal/client/client_manager.go index f76c463..386cb31 100644 --- a/internal/client/client_manager.go +++ b/internal/client/client_manager.go @@ -40,8 +40,8 @@ func (c ClientManager) connection(typeName string, settings map[string]string) ( }, nil case "aws-ssm": return &AWSSSMConnection{ - InstanceID: settings["instance_id"], - Region: settings["region"], + instanceId: settings["instance_id"], + region: settings["region"], }, nil } return nil, fmt.Errorf("unknown AEM client type: %s", typeName) diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index 1644c4a..1ec44bb 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -1,38 +1,40 @@ package client -import "github.com/melbahja/goph" +import ( + "fmt" + "github.com/melbahja/goph" +) type AWSSSMConnection struct { - InstanceID string - Region string + instanceId string + region string } -func (A AWSSSMConnection) Info() string { - //TODO implement me - panic("implement me") +func (a *AWSSSMConnection) Info() string { + return fmt.Sprintf("ssm: instance='%s', region='%s'", a.instanceId, a.region) } -func (A AWSSSMConnection) User() string { +func (a *AWSSSMConnection) User() string { //TODO implement me panic("implement me") } -func (A AWSSSMConnection) Connect() error { +func (a *AWSSSMConnection) Connect() error { //TODO implement me panic("implement me") } -func (A AWSSSMConnection) Disconnect() error { +func (a *AWSSSMConnection) Disconnect() error { //TODO implement me panic("implement me") } -func (A AWSSSMConnection) Command(cmdLine []string) (*goph.Cmd, error) { +func (a *AWSSSMConnection) Command(cmdLine []string) (*goph.Cmd, error) { //TODO implement me panic("implement me") } -func (A AWSSSMConnection) CopyFile(localPath string, remotePath string) error { +func (a *AWSSSMConnection) CopyFile(localPath string, remotePath string) error { //TODO implement me panic("implement me") } From 7b05f6dc6a371dcc23c2b7c952a9ffdb48c4b25a Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Tue, 5 Dec 2023 12:12:31 +0100 Subject: [PATCH 02/26] Implement 'aws_ssm' connection type #26 --- internal/client/connection_aws_ssm.go | 118 +++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 11 deletions(-) diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index 1ec44bb..e8dd434 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -2,12 +2,19 @@ package client import ( "fmt" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ssm" "github.com/melbahja/goph" + "os" + "strings" ) type AWSSSMConnection struct { instanceId string region string + ssmClient *ssm.SSM + sessionId *string } func (a *AWSSSMConnection) Info() string { @@ -15,26 +22,115 @@ func (a *AWSSSMConnection) Info() string { } func (a *AWSSSMConnection) User() string { - //TODO implement me - panic("implement me") + return "aem" // does not impact the connection, used as default user for systemd only } - func (a *AWSSSMConnection) Connect() error { - //TODO implement me - panic("implement me") + // Create an AWS session + sess, err := session.NewSession(&aws.Config{ + Region: aws.String(a.region), + }) + if err != nil { + return fmt.Errorf("ssm: error creating AWS session: %v", err) + } + + // Connect to AWS instance using SSM + ssmClient := ssm.New(sess) + startSessionInput := &ssm.StartSessionInput{ + Target: aws.String(a.instanceId), + } + + startSessionOutput, err := ssmClient.StartSession(startSessionInput) + if err != nil { + return fmt.Errorf("ssm: error starting session: %v", err) + } + + a.ssmClient = ssmClient + a.sessionId = startSessionOutput.SessionId + + return nil } func (a *AWSSSMConnection) Disconnect() error { - //TODO implement me - panic("implement me") + // Disconnect from the session + terminateSessionInput := &ssm.TerminateSessionInput{ + SessionId: a.sessionId, + } + + _, err := a.ssmClient.TerminateSession(terminateSessionInput) + if err != nil { + return fmt.Errorf("ssm: error terminating session: %v", err) + } + + return nil } func (a *AWSSSMConnection) Command(cmdLine []string) (*goph.Cmd, error) { - //TODO implement me - panic("implement me") + // Execute command on the remote instance + runCommandInput := &ssm.SendCommandInput{ + DocumentName: aws.String("AWS-RunShellScript"), + InstanceIds: []*string{aws.String(a.instanceId)}, + Parameters: map[string][]*string{ + "commands": aws.StringSlice(cmdLine), + }, + } + + runCommandOutput, err := a.ssmClient.SendCommand(runCommandInput) + if err != nil { + return nil, fmt.Errorf("ssm: error executing command: %v", err) + } + + commandId := runCommandOutput.Command.CommandId + + // Wait for command completion + err = a.ssmClient.WaitUntilCommandExecuted(&ssm.GetCommandInvocationInput{ + CommandId: commandId, + InstanceId: aws.String(a.instanceId), + }) + if err != nil { + return nil, fmt.Errorf("ssm: error executing command: %v", err) + } + + getCommandOutput, err := a.ssmClient.GetCommandInvocation(&ssm.GetCommandInvocationInput{ + CommandId: commandId, + InstanceId: aws.String(a.instanceId), + }) + if err != nil { + return nil, fmt.Errorf("ssm: error executing command: %v", err) + } + + // Transform the SSM command output into a goph.Cmd structure + parts := strings.Fields(*getCommandOutput.StandardOutputContent) + if len(parts) < 2 { + return nil, fmt.Errorf("ssm: unexpected command output format") + } + + gophCommand := goph.Cmd{ + Path: parts[0], + Args: parts[1:], + Env: os.Environ(), + } + + return &gophCommand, nil } func (a *AWSSSMConnection) CopyFile(localPath string, remotePath string) error { - //TODO implement me - panic("implement me") + // Upload file to the remote instance using SSM Parameter Store + fileContent, err := os.ReadFile(localPath) + if err != nil { + return fmt.Errorf("ssm: error reading local file: %v", err) + } + + putParameterInput := &ssm.PutParameterInput{ + Name: aws.String(remotePath), + Value: aws.String(string(fileContent)), + Type: aws.String("SecureString"), + Overwrite: aws.Bool(true), + } + + _, err = a.ssmClient.PutParameter(putParameterInput) + if err != nil { + return fmt.Errorf("ssm: error uploading file to the instance: %v", err) + } + + return nil } From 81cb27140e7064a957533b1204b34c6cad187a1c Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Tue, 5 Dec 2023 12:53:51 +0100 Subject: [PATCH 03/26] Implement 'aws_ssm' connection type #26 --- go.mod | 2 ++ go.sum | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/go.mod b/go.mod index 5d1514f..884e4c5 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect + github.com/aws/aws-sdk-go v1.48.12 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/cloudflare/circl v1.3.3 // indirect github.com/fatih/color v1.16.0 // indirect @@ -42,6 +43,7 @@ require ( github.com/hashicorp/yamux v0.1.1 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.13 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kr/fs v0.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/go.sum b/go.sum index b978bdc..7687308 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,8 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkE github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aws/aws-sdk-go v1.48.12 h1:n+eGzflzzvYubu2cOjqpVll7lF+Ci0ThyCpg5kzfzbo= +github.com/aws/aws-sdk-go v1.48.12/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= @@ -91,6 +93,9 @@ github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -237,6 +242,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 3c0d3b4db86defac12d814658d8c0a8759b0e35c Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Tue, 5 Dec 2023 12:57:02 +0100 Subject: [PATCH 04/26] Implement 'aws_ssm' connection type #26 --- examples/aws_ssh/aws.tf | 4 ++-- examples/aws_ssm/aws.tf | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/aws_ssh/aws.tf b/examples/aws_ssh/aws.tf index e7cf16d..7132fdd 100644 --- a/examples/aws_ssh/aws.tf +++ b/examples/aws_ssh/aws.tf @@ -37,7 +37,7 @@ resource "aws_iam_instance_profile" "aem_ec2" { } resource "aws_iam_role" "aem_ec2" { - name = "${local.workspace}_aem_ec2" + name = "${local.workspace}_aem_ec2" assume_role_policy = trimspace(< Date: Thu, 14 Dec 2023 16:19:19 +0100 Subject: [PATCH 05/26] Implement 'aws_ssm' connection type #26 --- internal/client/client.go | 12 ++------- internal/client/connection.go | 6 +---- internal/client/connection_aws_ssm.go | 38 ++++++--------------------- internal/client/connection_ssh.go | 11 ++++++-- 4 files changed, 20 insertions(+), 47 deletions(-) diff --git a/internal/client/client.go b/internal/client/client.go index 6e3dc58..2058954 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -3,7 +3,6 @@ package client import ( "context" "fmt" - "github.com/melbahja/goph" "github.com/wttech/terraform-provider-aem/internal/utils" "os" "path/filepath" @@ -68,7 +67,7 @@ func (c Client) Connection() Connection { return c.connection } -func (c Client) Command(cmdLine []string) (*goph.Cmd, error) { +func (c Client) Command(cmdLine []string) ([]byte, error) { return c.connection.Command(cmdLine) } @@ -110,17 +109,10 @@ func (c Client) RunShellPurely(cmd string) ([]byte, error) { } else { cmdLine = []string{"sh", "-c", "\"" + cmd + "\""} } - cmdObj, err := c.connection.Command(cmdLine) + out, err := c.connection.Command(cmdLine) if err != nil { return nil, fmt.Errorf("cannot create command '%s': %w", cmd, err) } - out, err := cmdObj.CombinedOutput() - if err != nil { - if len(out) > 0 { - return nil, fmt.Errorf("cannot run command '%s': %w\n\n%s", cmdObj, err, string(out)) - } - return nil, err - } return out, nil } diff --git a/internal/client/connection.go b/internal/client/connection.go index 77421a7..7b1f772 100644 --- a/internal/client/connection.go +++ b/internal/client/connection.go @@ -1,14 +1,10 @@ package client -import ( - "github.com/melbahja/goph" -) - type Connection interface { Info() string User() string Connect() error Disconnect() error - Command(cmdLine []string) (*goph.Cmd, error) + Command(cmdLine []string) ([]byte, error) CopyFile(localPath string, remotePath string) error } diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index e8dd434..5b53fcd 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -1,11 +1,11 @@ package client import ( + "encoding/base64" "fmt" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/ssm" - "github.com/melbahja/goph" "os" "strings" ) @@ -64,13 +64,13 @@ func (a *AWSSSMConnection) Disconnect() error { return nil } -func (a *AWSSSMConnection) Command(cmdLine []string) (*goph.Cmd, error) { +func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { // Execute command on the remote instance runCommandInput := &ssm.SendCommandInput{ DocumentName: aws.String("AWS-RunShellScript"), InstanceIds: []*string{aws.String(a.instanceId)}, Parameters: map[string][]*string{ - "commands": aws.StringSlice(cmdLine), + "commands": {aws.String(strings.Join(cmdLine, " "))}, }, } @@ -98,39 +98,17 @@ func (a *AWSSSMConnection) Command(cmdLine []string) (*goph.Cmd, error) { return nil, fmt.Errorf("ssm: error executing command: %v", err) } - // Transform the SSM command output into a goph.Cmd structure - parts := strings.Fields(*getCommandOutput.StandardOutputContent) - if len(parts) < 2 { - return nil, fmt.Errorf("ssm: unexpected command output format") - } - - gophCommand := goph.Cmd{ - Path: parts[0], - Args: parts[1:], - Env: os.Environ(), - } - - return &gophCommand, nil + return []byte(*getCommandOutput.StandardOutputContent), nil } func (a *AWSSSMConnection) CopyFile(localPath string, remotePath string) error { - // Upload file to the remote instance using SSM Parameter Store fileContent, err := os.ReadFile(localPath) if err != nil { return fmt.Errorf("ssm: error reading local file: %v", err) } + encodedContent := base64.StdEncoding.EncodeToString(fileContent) - putParameterInput := &ssm.PutParameterInput{ - Name: aws.String(remotePath), - Value: aws.String(string(fileContent)), - Type: aws.String("SecureString"), - Overwrite: aws.Bool(true), - } - - _, err = a.ssmClient.PutParameter(putParameterInput) - if err != nil { - return fmt.Errorf("ssm: error uploading file to the instance: %v", err) - } - - return nil + command := fmt.Sprintf("echo -n %s | base64 -d > %s", encodedContent, remotePath) + _, err = a.Command(strings.Split(command, " ")) + return err } diff --git a/internal/client/connection_ssh.go b/internal/client/connection_ssh.go index 958e972..c7baa18 100644 --- a/internal/client/connection_ssh.go +++ b/internal/client/connection_ssh.go @@ -87,13 +87,20 @@ func (s *SSHConnection) Disconnect() error { return nil } -func (s *SSHConnection) Command(cmdLine []string) (*goph.Cmd, error) { +func (s *SSHConnection) Command(cmdLine []string) ([]byte, error) { name, args := s.splitCommandLine(cmdLine) cmd, err := s.client.Command(name, args...) if err != nil { return nil, fmt.Errorf("ssh: cannot create command '%s' for host '%s': %w", strings.Join(cmdLine, " "), s.host, err) } - return cmd, nil + out, err := cmd.CombinedOutput() + if err != nil { + if len(out) > 0 { + return nil, fmt.Errorf("ssh: cannot run command '%s': %w\n\n%s", cmd, err, string(out)) + } + return nil, err + } + return out, nil } func (s *SSHConnection) splitCommandLine(cmdLine []string) (string, []string) { From 92bc821891c8e436abaa1321f5e545e2133b2b00 Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Fri, 15 Dec 2023 18:13:52 +0100 Subject: [PATCH 06/26] Implement 'aws_ssm' connection type #26 --- examples/aws_ssm/aem.tf | 19 +++++++++---------- examples/aws_ssm/aws.tf | 2 +- examples/aws_ssm/main.tf | 3 +-- internal/client/connection_aws_ssm.go | 3 ++- internal/provider/instance/systemd.conf | 6 +++--- internal/provider/instance_client.go | 5 ++++- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/examples/aws_ssm/aem.tf b/examples/aws_ssm/aem.tf index 332828e..d6cf5bc 100644 --- a/examples/aws_ssm/aem.tf +++ b/examples/aws_ssm/aem.tf @@ -2,7 +2,7 @@ resource "aem_instance" "single" { depends_on = [aws_instance.aem_single, aws_volume_attachment.aem_single_data] client { - type = "aws_ssm" + type = "aws-ssm" settings = { instance_id = aws_instance.aem_single.id region = "eu-central-1" // TODO infer from AWS provider config @@ -17,21 +17,13 @@ resource "aem_instance" "single" { "sudo mkfs -t ext4 ${local.aem_single_data_device}", "sudo mkdir -p ${local.aem_single_data_dir}", "sudo mount ${local.aem_single_data_device} ${local.aem_single_data_dir}", - "sudo chown -R ${local.ssh_user} ${local.aem_single_data_dir}", + "sudo chown -R ${local.ssm_user} ${local.aem_single_data_dir}", "echo '${local.aem_single_data_device} ${local.aem_single_data_dir} ext4 defaults 0 0' | sudo tee -a /etc/fstab", - // installing AWS CLI: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html - "sudo yum install -y unzip", - "curl 'https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip' -o 'awscliv2.zip'", - "unzip -q awscliv2.zip", - "sudo ./aws/install --update", - // installing AWS SSM agent: https://docs.aws.amazon.com/systems-manager/latest/userguide/agent-install-rhel-8-9.html - "sudo dnf install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm", ] } } compose { - config = file("aem.yml") // use templating here if needed: https://developer.hashicorp.com/terraform/language/functions/templatefile create = { inline = [ "mkdir -p '${local.aem_single_compose_dir}/aem/home/lib'", @@ -40,6 +32,13 @@ resource "aem_instance" "single" { "sh aemw instance create", ] } + configure = { + inline = [ + "sh aemw osgi config save --pid 'org.apache.sling.jcr.davex.impl.servlets.SlingDavExServlet' --input-string 'alias: /crx/server'", + "sh aemw repl agent setup -A --location 'author' --name 'publish' --input-string '{enabled: true, transportUri: \"http://localhost:4503/bin/receive?sling:authRequestLogin=1\", transportUser: admin, transportPassword: admin, userId: admin}'", + "sh aemw package deploy --file 'aem/home/lib/aem-service-pkg-6.5.*.0.zip'", + ] + } } } diff --git a/examples/aws_ssm/aws.tf b/examples/aws_ssm/aws.tf index d0d6fb9..5bf3381 100644 --- a/examples/aws_ssm/aws.tf +++ b/examples/aws_ssm/aws.tf @@ -1,5 +1,5 @@ resource "aws_instance" "aem_single" { - ami = "ami-043e06a423cbdca17" // RHEL 8 + ami = "ami-064e3c165b1ba0bb3" // Amazon Linux 2 AMI (HVM), SSD Volume Type instance_type = "m5.xlarge" iam_instance_profile = aws_iam_instance_profile.aem_ec2.name tags = local.tags diff --git a/examples/aws_ssm/main.tf b/examples/aws_ssm/main.tf index e0eba14..b1ab01e 100644 --- a/examples/aws_ssm/main.tf +++ b/examples/aws_ssm/main.tf @@ -18,8 +18,7 @@ locals { env_type = "aem-single" host = "aem_single" - ssh_user = "ec2-user" - ssh_private_key = abspath("ec2-key.cer") + ssm_user = "ssm-user" tags = { Workspace = "aemc" diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index 5b53fcd..d9de852 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -66,11 +66,12 @@ func (a *AWSSSMConnection) Disconnect() error { func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { // Execute command on the remote instance + command := aws.String(strings.Join(cmdLine, " ")) runCommandInput := &ssm.SendCommandInput{ DocumentName: aws.String("AWS-RunShellScript"), InstanceIds: []*string{aws.String(a.instanceId)}, Parameters: map[string][]*string{ - "commands": {aws.String(strings.Join(cmdLine, " "))}, + "commands": {command}, }, } diff --git a/internal/provider/instance/systemd.conf b/internal/provider/instance/systemd.conf index 489215b..ff5bafd 100644 --- a/internal/provider/instance/systemd.conf +++ b/internal/provider/instance/systemd.conf @@ -7,9 +7,9 @@ After=cloud-final.service Type=forking User=[[.USER]] -ExecStart=sh -c ". /etc/profile && cd [[.DATA_DIR]] && sh aemw instance start" -ExecStop=sh -c ". /etc/profile && cd [[.DATA_DIR]] && sh aemw instance stop" -ExecReload=sh -c ". /etc/profile && cd [[.DATA_DIR]] && sh aemw instance restart" +ExecStart=sudo sh -c ". /etc/profile && cd [[.DATA_DIR]] && sh aemw instance start" +ExecStop=sudo sh -c ". /etc/profile && cd [[.DATA_DIR]] && sh aemw instance stop" +ExecReload=sudo sh -c ". /etc/profile && cd [[.DATA_DIR]] && sh aemw instance restart" KillMode=process RemainAfterExit=yes TimeoutStartSec=1810 diff --git a/internal/provider/instance_client.go b/internal/provider/instance_client.go index fab7aa9..0b29396 100644 --- a/internal/provider/instance_client.go +++ b/internal/provider/instance_client.go @@ -42,7 +42,7 @@ func (ic *InstanceClient) installComposeCLI() error { } if !exists { tflog.Info(ic.ctx, "Downloading AEM Compose CLI wrapper") - out, err := ic.cl.RunShellCommand("curl -s 'https://raw.githubusercontent.com/wttech/aemc/main/pkg/project/common/aemw' -o 'aemw'", ic.dataDir()) + out, err := ic.cl.RunShellCommand("curl -s 'https://raw.githubusercontent.com/wttech/aemc/main/pkg/project/common/aemw' -o 'aemw' && chmod +x 'aemw'", ic.dataDir()) tflog.Info(ic.ctx, string(out)) if err != nil { return fmt.Errorf("cannot download AEM Compose CLI wrapper: %w", err) @@ -126,6 +126,9 @@ func (ic *InstanceClient) configureService() error { if err := ic.cl.FileWrite(serviceFile, serviceTemplated); err != nil { return fmt.Errorf("unable to write AEM system service definition '%s': %w", serviceFile, err) } + if err := ic.cl.FileMakeExecutable(serviceFile); err != nil { + return fmt.Errorf("unable to make executable AEM system service definition '%s': %w", serviceFile, err) + } if err := ic.runServiceAction("enable"); err != nil { return err From 6c418ebe457605a737c135123cc3019146b72cf2 Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Thu, 11 Jan 2024 19:49:38 +0100 Subject: [PATCH 07/26] Implement 'aws_ssm' connection type #26 --- examples/aws_ssm/aem.tf | 1 + examples/aws_ssm/aws.tf | 2 +- examples/aws_ssm/main.tf | 2 +- internal/client/client_manager.go | 1 + internal/client/connection_aws_ssm.go | 3 ++- internal/provider/instance/systemd.conf | 2 +- 6 files changed, 7 insertions(+), 4 deletions(-) diff --git a/examples/aws_ssm/aem.tf b/examples/aws_ssm/aem.tf index d6cf5bc..82054d3 100644 --- a/examples/aws_ssm/aem.tf +++ b/examples/aws_ssm/aem.tf @@ -4,6 +4,7 @@ resource "aem_instance" "single" { client { type = "aws-ssm" settings = { + user = local.ssm_user instance_id = aws_instance.aem_single.id region = "eu-central-1" // TODO infer from AWS provider config } diff --git a/examples/aws_ssm/aws.tf b/examples/aws_ssm/aws.tf index 5bf3381..c43fe84 100644 --- a/examples/aws_ssm/aws.tf +++ b/examples/aws_ssm/aws.tf @@ -1,5 +1,5 @@ resource "aws_instance" "aem_single" { - ami = "ami-064e3c165b1ba0bb3" // Amazon Linux 2 AMI (HVM), SSD Volume Type + ami = "ami-025a6a5beb74db87b" // Amazon Linux 2023 AMI instance_type = "m5.xlarge" iam_instance_profile = aws_iam_instance_profile.aem_ec2.name tags = local.tags diff --git a/examples/aws_ssm/main.tf b/examples/aws_ssm/main.tf index b1ab01e..e846116 100644 --- a/examples/aws_ssm/main.tf +++ b/examples/aws_ssm/main.tf @@ -18,7 +18,7 @@ locals { env_type = "aem-single" host = "aem_single" - ssm_user = "ssm-user" + ssm_user = "ec2-user" tags = { Workspace = "aemc" diff --git a/internal/client/client_manager.go b/internal/client/client_manager.go index 386cb31..e25e05e 100644 --- a/internal/client/client_manager.go +++ b/internal/client/client_manager.go @@ -40,6 +40,7 @@ func (c ClientManager) connection(typeName string, settings map[string]string) ( }, nil case "aws-ssm": return &AWSSSMConnection{ + user: settings["user"], instanceId: settings["instance_id"], region: settings["region"], }, nil diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index d9de852..c4e7dcc 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -11,6 +11,7 @@ import ( ) type AWSSSMConnection struct { + user string instanceId string region string ssmClient *ssm.SSM @@ -22,7 +23,7 @@ func (a *AWSSSMConnection) Info() string { } func (a *AWSSSMConnection) User() string { - return "aem" // does not impact the connection, used as default user for systemd only + return a.user } func (a *AWSSSMConnection) Connect() error { // Create an AWS session diff --git a/internal/provider/instance/systemd.conf b/internal/provider/instance/systemd.conf index ff5bafd..2a856e9 100644 --- a/internal/provider/instance/systemd.conf +++ b/internal/provider/instance/systemd.conf @@ -1,6 +1,6 @@ [Unit] Description=AEM Instances -Requires=network.target +Requires=network.target multi-user.target After=cloud-final.service [Service] From 681999e6756975850f62dee4b95d68c50c6c04f8 Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Thu, 18 Jan 2024 22:39:58 +0100 Subject: [PATCH 08/26] Implement 'aws_ssm' connection type #26 --- examples/aws_ssm/aem.tf | 6 ++++++ examples/aws_ssm/aws.tf | 7 ++++++- examples/aws_ssm/systemd.conf | 20 ++++++++++++++++++++ internal/provider/instance/systemd.conf | 6 +++--- internal/provider/instance_client.go | 5 +---- 5 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 examples/aws_ssm/systemd.conf diff --git a/examples/aws_ssm/aem.tf b/examples/aws_ssm/aem.tf index 82054d3..5be9b21 100644 --- a/examples/aws_ssm/aem.tf +++ b/examples/aws_ssm/aem.tf @@ -11,6 +11,7 @@ resource "aem_instance" "single" { } system { + service_config = file("systemd.conf") data_dir = local.aem_single_compose_dir bootstrap = { inline = [ @@ -20,6 +21,11 @@ resource "aem_instance" "single" { "sudo mount ${local.aem_single_data_device} ${local.aem_single_data_dir}", "sudo chown -R ${local.ssm_user} ${local.aem_single_data_dir}", "echo '${local.aem_single_data_device} ${local.aem_single_data_dir} ext4 defaults 0 0' | sudo tee -a /etc/fstab", + // installing AWS CLI + "sudo yum install -y unzip", + "curl 'https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip' -o 'awscliv2.zip'", + "unzip -q awscliv2.zip", + "sudo ./aws/install --update", ] } } diff --git a/examples/aws_ssm/aws.tf b/examples/aws_ssm/aws.tf index c43fe84..76472af 100644 --- a/examples/aws_ssm/aws.tf +++ b/examples/aws_ssm/aws.tf @@ -1,8 +1,13 @@ resource "aws_instance" "aem_single" { - ami = "ami-025a6a5beb74db87b" // Amazon Linux 2023 AMI + ami = "ami-043e06a423cbdca17" // RHEL 8 instance_type = "m5.xlarge" iam_instance_profile = aws_iam_instance_profile.aem_ec2.name tags = local.tags + user_data = trimspace(< Date: Fri, 19 Jan 2024 13:46:47 +0100 Subject: [PATCH 09/26] Implement 'aws_ssm' connection type #26 --- examples/aws_ssm/aem.tf | 1 - examples/aws_ssm/systemd.conf | 20 -------------------- 2 files changed, 21 deletions(-) delete mode 100644 examples/aws_ssm/systemd.conf diff --git a/examples/aws_ssm/aem.tf b/examples/aws_ssm/aem.tf index 5be9b21..8df8b74 100644 --- a/examples/aws_ssm/aem.tf +++ b/examples/aws_ssm/aem.tf @@ -11,7 +11,6 @@ resource "aem_instance" "single" { } system { - service_config = file("systemd.conf") data_dir = local.aem_single_compose_dir bootstrap = { inline = [ diff --git a/examples/aws_ssm/systemd.conf b/examples/aws_ssm/systemd.conf deleted file mode 100644 index 2a856e9..0000000 --- a/examples/aws_ssm/systemd.conf +++ /dev/null @@ -1,20 +0,0 @@ -[Unit] -Description=AEM Instances -Requires=network.target multi-user.target -After=cloud-final.service - -[Service] -Type=forking -User=[[.USER]] - -ExecStart=sudo sh -c ". /etc/profile && cd [[.DATA_DIR]] && sh aemw instance start" -ExecStop=sudo sh -c ". /etc/profile && cd [[.DATA_DIR]] && sh aemw instance stop" -ExecReload=sudo sh -c ". /etc/profile && cd [[.DATA_DIR]] && sh aemw instance restart" -KillMode=process -RemainAfterExit=yes -TimeoutStartSec=1810 -TimeoutStopSec=190 -LimitNOFILE=20000 - -[Install] -WantedBy=cloud-init.target From 6b05fe79a76dd7a0ec10be560962e914344758dc Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Tue, 23 Jan 2024 16:16:57 +0100 Subject: [PATCH 10/26] Implement 'aws_ssm' connection type #26 --- internal/client/client.go | 2 +- internal/client/connection.go | 2 +- internal/client/connection_aws_ssm.go | 12 +++++++++--- internal/client/connection_ssh.go | 2 +- internal/provider/instance_client.go | 2 +- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/internal/client/client.go b/internal/client/client.go index 2058954..b229425 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -206,7 +206,7 @@ func (c Client) FileCopy(localPath string, remotePath string, override bool) err return err } defer func() { _ = c.PathDelete(remoteTmpPath) }() - if err := c.connection.CopyFile(localPath, remoteTmpPath); err != nil { + if err := c.connection.CopyFile(c.Sudo, localPath, remoteTmpPath); err != nil { return err } if err := c.FileMove(remoteTmpPath, remotePath); err != nil { diff --git a/internal/client/connection.go b/internal/client/connection.go index 7b1f772..045496b 100644 --- a/internal/client/connection.go +++ b/internal/client/connection.go @@ -6,5 +6,5 @@ type Connection interface { Connect() error Disconnect() error Command(cmdLine []string) ([]byte, error) - CopyFile(localPath string, remotePath string) error + CopyFile(sudo bool, localPath string, remotePath string) error } diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index c4e7dcc..c34fb54 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -103,14 +103,20 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { return []byte(*getCommandOutput.StandardOutputContent), nil } -func (a *AWSSSMConnection) CopyFile(localPath string, remotePath string) error { +func (a *AWSSSMConnection) CopyFile(sudo bool, localPath string, remotePath string) error { fileContent, err := os.ReadFile(localPath) if err != nil { return fmt.Errorf("ssm: error reading local file: %v", err) } encodedContent := base64.StdEncoding.EncodeToString(fileContent) - command := fmt.Sprintf("echo -n %s | base64 -d > %s", encodedContent, remotePath) - _, err = a.Command(strings.Split(command, " ")) + cmd := fmt.Sprintf("echo -n %s | base64 -d > %s", encodedContent, remotePath) + var cmdLine []string + if sudo { + cmdLine = []string{"sudo", "sh", "-c", "\"" + cmd + "\""} + } else { + cmdLine = []string{"sh", "-c", "\"" + cmd + "\""} + } + _, err = a.Command(cmdLine) return err } diff --git a/internal/client/connection_ssh.go b/internal/client/connection_ssh.go index c7baa18..dc53947 100644 --- a/internal/client/connection_ssh.go +++ b/internal/client/connection_ssh.go @@ -112,7 +112,7 @@ func (s *SSHConnection) splitCommandLine(cmdLine []string) (string, []string) { return name, args } -func (s *SSHConnection) CopyFile(localPath string, remotePath string) error { +func (s *SSHConnection) CopyFile(sudo bool, localPath string, remotePath string) error { if err := s.client.Upload(localPath, remotePath); err != nil { return fmt.Errorf("ssh: cannot copy local file '%s' to remote path '%s' on host '%s': %w", localPath, remotePath, s.host, err) } diff --git a/internal/provider/instance_client.go b/internal/provider/instance_client.go index fab7aa9..6f6f78f 100644 --- a/internal/provider/instance_client.go +++ b/internal/provider/instance_client.go @@ -220,7 +220,7 @@ func (ic *InstanceClient) ReadStatus() (InstanceStatus, error) { func (ic *InstanceClient) bootstrap() error { return ic.doActionOnce("bootstrap", ic.cl.WorkDir, func() error { - return ic.runScript("bootstrap", ic.data.System.Bootstrap, ".") + return ic.runScript("bootstrap", ic.data.System.Bootstrap, ic.cl.WorkDir) }) } From b4d8d3b76ff93396bafeb4062bd514ada25ef137 Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Wed, 24 Jan 2024 10:15:57 +0100 Subject: [PATCH 11/26] Implement 'aws_ssm' connection type #26 --- examples/aws_ssm/main.tf | 2 +- go.mod | 15 ++++++- go.sum | 32 +++++++++++++- internal/client/client.go | 2 +- internal/client/connection.go | 2 +- internal/client/connection_aws_ssm.go | 59 ++++++++++++------------- internal/client/connection_ssh.go | 2 +- internal/provider/instance/systemd.conf | 2 +- 8 files changed, 78 insertions(+), 38 deletions(-) diff --git a/examples/aws_ssm/main.tf b/examples/aws_ssm/main.tf index e846116..0c674dd 100644 --- a/examples/aws_ssm/main.tf +++ b/examples/aws_ssm/main.tf @@ -18,7 +18,7 @@ locals { env_type = "aem-single" host = "aem_single" - ssm_user = "ec2-user" + ssm_user = "root" tags = { Workspace = "aemc" diff --git a/go.mod b/go.mod index 884e4c5..c458e92 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,9 @@ module github.com/wttech/terraform-provider-aem go 1.19 require ( + github.com/aws/aws-sdk-go-v2 v1.24.1 + github.com/aws/aws-sdk-go-v2/config v1.26.6 + github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 github.com/hashicorp/terraform-plugin-docs v0.16.0 github.com/hashicorp/terraform-plugin-framework v1.4.2 github.com/hashicorp/terraform-plugin-go v0.19.0 @@ -21,7 +24,17 @@ require ( github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect - github.com/aws/aws-sdk-go v1.48.12 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect + github.com/aws/smithy-go v1.19.0 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/cloudflare/circl v1.3.3 // indirect github.com/fatih/color v1.16.0 // indirect diff --git a/go.sum b/go.sum index 7687308..4466e08 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,34 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkE github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.48.12 h1:n+eGzflzzvYubu2cOjqpVll7lF+Ci0ThyCpg5kzfzbo= -github.com/aws/aws-sdk-go v1.48.12/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU= +github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= +github.com/aws/aws-sdk-go-v2/config v1.26.6 h1:Z/7w9bUqlRI0FFQpetVuFYEsjzE3h7fpU6HuGmfPL/o= +github.com/aws/aws-sdk-go-v2/config v1.26.6/go.mod h1:uKU6cnDmYCvJ+pxO9S4cWDb2yWWIH5hra+32hVh1MI4= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8= +github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 h1:n3GDfwqF2tzEkXlv5cuy4iy7LpKDtqDMcNLfZDu9rls= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino= +github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 h1:a8HvP/+ew3tKwSXqL3BCSjiuicr+XTU2eFYeogV9GJE= +github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7/go.mod h1:Q7XIWsMo0JcMpI/6TGD6XXcXcV1DbTj6e9BKNntIMIM= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U= +github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= +github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= @@ -95,6 +121,7 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= @@ -243,6 +270,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/client/client.go b/internal/client/client.go index b229425..2058954 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -206,7 +206,7 @@ func (c Client) FileCopy(localPath string, remotePath string, override bool) err return err } defer func() { _ = c.PathDelete(remoteTmpPath) }() - if err := c.connection.CopyFile(c.Sudo, localPath, remoteTmpPath); err != nil { + if err := c.connection.CopyFile(localPath, remoteTmpPath); err != nil { return err } if err := c.FileMove(remoteTmpPath, remotePath); err != nil { diff --git a/internal/client/connection.go b/internal/client/connection.go index 045496b..7b1f772 100644 --- a/internal/client/connection.go +++ b/internal/client/connection.go @@ -6,5 +6,5 @@ type Connection interface { Connect() error Disconnect() error Command(cmdLine []string) ([]byte, error) - CopyFile(sudo bool, localPath string, remotePath string) error + CopyFile(localPath string, remotePath string) error } diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index c34fb54..0fd0cff 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -1,20 +1,22 @@ package client import ( + "context" "encoding/base64" "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/ssm" "os" "strings" + "time" ) type AWSSSMConnection struct { user string instanceId string region string - ssmClient *ssm.SSM + ssmClient *ssm.Client sessionId *string } @@ -25,22 +27,25 @@ func (a *AWSSSMConnection) Info() string { func (a *AWSSSMConnection) User() string { return a.user } + func (a *AWSSSMConnection) Connect() error { - // Create an AWS session - sess, err := session.NewSession(&aws.Config{ - Region: aws.String(a.region), - }) + // Specify the AWS region + cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion(a.region)) + if err != nil { + return err + } + + // Create an SSM client + ssmClient := ssm.NewFromConfig(cfg) if err != nil { return fmt.Errorf("ssm: error creating AWS session: %v", err) } - // Connect to AWS instance using SSM - ssmClient := ssm.New(sess) startSessionInput := &ssm.StartSessionInput{ Target: aws.String(a.instanceId), } - startSessionOutput, err := ssmClient.StartSession(startSessionInput) + startSessionOutput, err := ssmClient.StartSession(context.Background(), startSessionInput) if err != nil { return fmt.Errorf("ssm: error starting session: %v", err) } @@ -57,7 +62,7 @@ func (a *AWSSSMConnection) Disconnect() error { SessionId: a.sessionId, } - _, err := a.ssmClient.TerminateSession(terminateSessionInput) + _, err := a.ssmClient.TerminateSession(context.Background(), terminateSessionInput) if err != nil { return fmt.Errorf("ssm: error terminating session: %v", err) } @@ -67,35 +72,34 @@ func (a *AWSSSMConnection) Disconnect() error { func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { // Execute command on the remote instance - command := aws.String(strings.Join(cmdLine, " ")) + command := strings.Join(cmdLine, " ") runCommandInput := &ssm.SendCommandInput{ DocumentName: aws.String("AWS-RunShellScript"), - InstanceIds: []*string{aws.String(a.instanceId)}, - Parameters: map[string][]*string{ + InstanceIds: []string{a.instanceId}, + Parameters: map[string][]string{ "commands": {command}, }, } - runCommandOutput, err := a.ssmClient.SendCommand(runCommandInput) + runCommandOutput, err := a.ssmClient.SendCommand(context.Background(), runCommandInput) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } commandId := runCommandOutput.Command.CommandId - // Wait for command completion - err = a.ssmClient.WaitUntilCommandExecuted(&ssm.GetCommandInvocationInput{ + commandInvocationInput := &ssm.GetCommandInvocationInput{ CommandId: commandId, InstanceId: aws.String(a.instanceId), - }) + } + + waiter := ssm.NewCommandExecutedWaiter(a.ssmClient) + _, err = waiter.WaitForOutput(context.Background(), commandInvocationInput, time.Hour) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } - getCommandOutput, err := a.ssmClient.GetCommandInvocation(&ssm.GetCommandInvocationInput{ - CommandId: commandId, - InstanceId: aws.String(a.instanceId), - }) + getCommandOutput, err := a.ssmClient.GetCommandInvocation(context.Background(), commandInvocationInput) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } @@ -103,7 +107,7 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { return []byte(*getCommandOutput.StandardOutputContent), nil } -func (a *AWSSSMConnection) CopyFile(sudo bool, localPath string, remotePath string) error { +func (a *AWSSSMConnection) CopyFile(localPath string, remotePath string) error { fileContent, err := os.ReadFile(localPath) if err != nil { return fmt.Errorf("ssm: error reading local file: %v", err) @@ -111,12 +115,7 @@ func (a *AWSSSMConnection) CopyFile(sudo bool, localPath string, remotePath stri encodedContent := base64.StdEncoding.EncodeToString(fileContent) cmd := fmt.Sprintf("echo -n %s | base64 -d > %s", encodedContent, remotePath) - var cmdLine []string - if sudo { - cmdLine = []string{"sudo", "sh", "-c", "\"" + cmd + "\""} - } else { - cmdLine = []string{"sh", "-c", "\"" + cmd + "\""} - } + cmdLine := []string{"sh", "-c", "\"" + cmd + "\""} _, err = a.Command(cmdLine) return err } diff --git a/internal/client/connection_ssh.go b/internal/client/connection_ssh.go index dc53947..c7baa18 100644 --- a/internal/client/connection_ssh.go +++ b/internal/client/connection_ssh.go @@ -112,7 +112,7 @@ func (s *SSHConnection) splitCommandLine(cmdLine []string) (string, []string) { return name, args } -func (s *SSHConnection) CopyFile(sudo bool, localPath string, remotePath string) error { +func (s *SSHConnection) CopyFile(localPath string, remotePath string) error { if err := s.client.Upload(localPath, remotePath); err != nil { return fmt.Errorf("ssh: cannot copy local file '%s' to remote path '%s' on host '%s': %w", localPath, remotePath, s.host, err) } diff --git a/internal/provider/instance/systemd.conf b/internal/provider/instance/systemd.conf index 9dca605..489215b 100644 --- a/internal/provider/instance/systemd.conf +++ b/internal/provider/instance/systemd.conf @@ -1,6 +1,6 @@ [Unit] Description=AEM Instances -Requires=network.target multi-user.target +Requires=network.target After=cloud-final.service [Service] From 84a7b506abefca083401d295426bc81b0f9fc7a0 Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Wed, 24 Jan 2024 12:40:54 +0100 Subject: [PATCH 12/26] Implement 'aws_ssm' connection type #26 --- examples/aws_ssm/aem.tf | 4 +--- examples/aws_ssm/main.tf | 2 -- internal/client/client_manager.go | 1 - internal/client/connection_aws_ssm.go | 3 +-- 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/examples/aws_ssm/aem.tf b/examples/aws_ssm/aem.tf index 8df8b74..10f35e3 100644 --- a/examples/aws_ssm/aem.tf +++ b/examples/aws_ssm/aem.tf @@ -4,7 +4,6 @@ resource "aem_instance" "single" { client { type = "aws-ssm" settings = { - user = local.ssm_user instance_id = aws_instance.aem_single.id region = "eu-central-1" // TODO infer from AWS provider config } @@ -18,9 +17,8 @@ resource "aem_instance" "single" { "sudo mkfs -t ext4 ${local.aem_single_data_device}", "sudo mkdir -p ${local.aem_single_data_dir}", "sudo mount ${local.aem_single_data_device} ${local.aem_single_data_dir}", - "sudo chown -R ${local.ssm_user} ${local.aem_single_data_dir}", "echo '${local.aem_single_data_device} ${local.aem_single_data_dir} ext4 defaults 0 0' | sudo tee -a /etc/fstab", - // installing AWS CLI + // installing AWS CLI: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html "sudo yum install -y unzip", "curl 'https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip' -o 'awscliv2.zip'", "unzip -q awscliv2.zip", diff --git a/examples/aws_ssm/main.tf b/examples/aws_ssm/main.tf index 0c674dd..fa739f2 100644 --- a/examples/aws_ssm/main.tf +++ b/examples/aws_ssm/main.tf @@ -18,8 +18,6 @@ locals { env_type = "aem-single" host = "aem_single" - ssm_user = "root" - tags = { Workspace = "aemc" Env = "tf-minimal" diff --git a/internal/client/client_manager.go b/internal/client/client_manager.go index e25e05e..386cb31 100644 --- a/internal/client/client_manager.go +++ b/internal/client/client_manager.go @@ -40,7 +40,6 @@ func (c ClientManager) connection(typeName string, settings map[string]string) ( }, nil case "aws-ssm": return &AWSSSMConnection{ - user: settings["user"], instanceId: settings["instance_id"], region: settings["region"], }, nil diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index 0fd0cff..79cbecf 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -13,7 +13,6 @@ import ( ) type AWSSSMConnection struct { - user string instanceId string region string ssmClient *ssm.Client @@ -25,7 +24,7 @@ func (a *AWSSSMConnection) Info() string { } func (a *AWSSSMConnection) User() string { - return a.user + return "root" } func (a *AWSSSMConnection) Connect() error { From 091eae386b88607e7c0f0e78785e9fddc730efa0 Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Wed, 24 Jan 2024 13:31:06 +0100 Subject: [PATCH 13/26] Implement 'aws_ssm' connection type #26 --- internal/client/client_manager.go | 4 +-- internal/client/connection_aws_ssm.go | 36 +++++++++++++-------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/internal/client/client_manager.go b/internal/client/client_manager.go index 386cb31..753faae 100644 --- a/internal/client/client_manager.go +++ b/internal/client/client_manager.go @@ -40,8 +40,8 @@ func (c ClientManager) connection(typeName string, settings map[string]string) ( }, nil case "aws-ssm": return &AWSSSMConnection{ - instanceId: settings["instance_id"], - region: settings["region"], + InstanceId: settings["instance_id"], + Region: settings["region"], }, nil } return nil, fmt.Errorf("unknown AEM client type: %s", typeName) diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index 79cbecf..c9e9b0f 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -13,14 +13,14 @@ import ( ) type AWSSSMConnection struct { - instanceId string - region string - ssmClient *ssm.Client - sessionId *string + InstanceId string + Region string + Client *ssm.Client + SessionId *string } func (a *AWSSSMConnection) Info() string { - return fmt.Sprintf("ssm: instance='%s', region='%s'", a.instanceId, a.region) + return fmt.Sprintf("ssm: instance='%s', region='%s'", a.InstanceId, a.Region) } func (a *AWSSSMConnection) User() string { @@ -29,28 +29,28 @@ func (a *AWSSSMConnection) User() string { func (a *AWSSSMConnection) Connect() error { // Specify the AWS region - cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion(a.region)) + cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion(a.Region)) if err != nil { return err } // Create an SSM client - ssmClient := ssm.NewFromConfig(cfg) + client := ssm.NewFromConfig(cfg) if err != nil { return fmt.Errorf("ssm: error creating AWS session: %v", err) } startSessionInput := &ssm.StartSessionInput{ - Target: aws.String(a.instanceId), + Target: aws.String(a.InstanceId), } - startSessionOutput, err := ssmClient.StartSession(context.Background(), startSessionInput) + startSessionOutput, err := client.StartSession(context.Background(), startSessionInput) if err != nil { return fmt.Errorf("ssm: error starting session: %v", err) } - a.ssmClient = ssmClient - a.sessionId = startSessionOutput.SessionId + a.Client = client + a.SessionId = startSessionOutput.SessionId return nil } @@ -58,10 +58,10 @@ func (a *AWSSSMConnection) Connect() error { func (a *AWSSSMConnection) Disconnect() error { // Disconnect from the session terminateSessionInput := &ssm.TerminateSessionInput{ - SessionId: a.sessionId, + SessionId: a.SessionId, } - _, err := a.ssmClient.TerminateSession(context.Background(), terminateSessionInput) + _, err := a.Client.TerminateSession(context.Background(), terminateSessionInput) if err != nil { return fmt.Errorf("ssm: error terminating session: %v", err) } @@ -74,13 +74,13 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { command := strings.Join(cmdLine, " ") runCommandInput := &ssm.SendCommandInput{ DocumentName: aws.String("AWS-RunShellScript"), - InstanceIds: []string{a.instanceId}, + InstanceIds: []string{a.InstanceId}, Parameters: map[string][]string{ "commands": {command}, }, } - runCommandOutput, err := a.ssmClient.SendCommand(context.Background(), runCommandInput) + runCommandOutput, err := a.Client.SendCommand(context.Background(), runCommandInput) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } @@ -89,16 +89,16 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { commandInvocationInput := &ssm.GetCommandInvocationInput{ CommandId: commandId, - InstanceId: aws.String(a.instanceId), + InstanceId: aws.String(a.InstanceId), } - waiter := ssm.NewCommandExecutedWaiter(a.ssmClient) + waiter := ssm.NewCommandExecutedWaiter(a.Client) _, err = waiter.WaitForOutput(context.Background(), commandInvocationInput, time.Hour) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } - getCommandOutput, err := a.ssmClient.GetCommandInvocation(context.Background(), commandInvocationInput) + getCommandOutput, err := a.Client.GetCommandInvocation(context.Background(), commandInvocationInput) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } From 0fdc56c8eaeddad3f609b33740e853eec25afbf8 Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Wed, 24 Jan 2024 16:14:24 +0100 Subject: [PATCH 14/26] Implement 'aws_ssm' connection type #26 --- internal/client/client_manager.go | 2 +- internal/client/connection_aws_ssm.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/client/client_manager.go b/internal/client/client_manager.go index 753faae..f76c463 100644 --- a/internal/client/client_manager.go +++ b/internal/client/client_manager.go @@ -40,7 +40,7 @@ func (c ClientManager) connection(typeName string, settings map[string]string) ( }, nil case "aws-ssm": return &AWSSSMConnection{ - InstanceId: settings["instance_id"], + InstanceID: settings["instance_id"], Region: settings["region"], }, nil } diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index c9e9b0f..5698e08 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -13,14 +13,14 @@ import ( ) type AWSSSMConnection struct { - InstanceId string + InstanceID string Region string Client *ssm.Client SessionId *string } func (a *AWSSSMConnection) Info() string { - return fmt.Sprintf("ssm: instance='%s', region='%s'", a.InstanceId, a.Region) + return fmt.Sprintf("ssm: instance='%s', region='%s'", a.InstanceID, a.Region) } func (a *AWSSSMConnection) User() string { @@ -41,7 +41,7 @@ func (a *AWSSSMConnection) Connect() error { } startSessionInput := &ssm.StartSessionInput{ - Target: aws.String(a.InstanceId), + Target: aws.String(a.InstanceID), } startSessionOutput, err := client.StartSession(context.Background(), startSessionInput) @@ -74,7 +74,7 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { command := strings.Join(cmdLine, " ") runCommandInput := &ssm.SendCommandInput{ DocumentName: aws.String("AWS-RunShellScript"), - InstanceIds: []string{a.InstanceId}, + InstanceIds: []string{a.InstanceID}, Parameters: map[string][]string{ "commands": {command}, }, @@ -89,7 +89,7 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { commandInvocationInput := &ssm.GetCommandInvocationInput{ CommandId: commandId, - InstanceId: aws.String(a.InstanceId), + InstanceId: aws.String(a.InstanceID), } waiter := ssm.NewCommandExecutedWaiter(a.Client) From c5ea9a4e81c3af7de2786cf562254ac37eb12bcc Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Wed, 24 Jan 2024 18:06:09 +0100 Subject: [PATCH 15/26] Implement 'aws_ssm' connection type #26 --- internal/client/connection_aws_ssm.go | 28 +++++++++++---------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index 5698e08..8b6c747 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -17,10 +17,11 @@ type AWSSSMConnection struct { Region string Client *ssm.Client SessionId *string + Context context.Context } func (a *AWSSSMConnection) Info() string { - return fmt.Sprintf("ssm: instance='%s', region='%s'", a.InstanceID, a.Region) + return fmt.Sprintf("ssm: instance_id='%s', region='%s'", a.InstanceID, a.Region) } func (a *AWSSSMConnection) User() string { @@ -29,22 +30,17 @@ func (a *AWSSSMConnection) User() string { func (a *AWSSSMConnection) Connect() error { // Specify the AWS region - cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion(a.Region)) + a.Context = context.Background() + cfg, err := config.LoadDefaultConfig(a.Context, config.WithRegion(a.Region)) if err != nil { return err } // Create an SSM client client := ssm.NewFromConfig(cfg) - if err != nil { - return fmt.Errorf("ssm: error creating AWS session: %v", err) - } + startSessionInput := &ssm.StartSessionInput{Target: aws.String(a.InstanceID)} - startSessionInput := &ssm.StartSessionInput{ - Target: aws.String(a.InstanceID), - } - - startSessionOutput, err := client.StartSession(context.Background(), startSessionInput) + startSessionOutput, err := client.StartSession(a.Context, startSessionInput) if err != nil { return fmt.Errorf("ssm: error starting session: %v", err) } @@ -57,11 +53,9 @@ func (a *AWSSSMConnection) Connect() error { func (a *AWSSSMConnection) Disconnect() error { // Disconnect from the session - terminateSessionInput := &ssm.TerminateSessionInput{ - SessionId: a.SessionId, - } + terminateSessionInput := &ssm.TerminateSessionInput{SessionId: a.SessionId} - _, err := a.Client.TerminateSession(context.Background(), terminateSessionInput) + _, err := a.Client.TerminateSession(a.Context, terminateSessionInput) if err != nil { return fmt.Errorf("ssm: error terminating session: %v", err) } @@ -80,7 +74,7 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { }, } - runCommandOutput, err := a.Client.SendCommand(context.Background(), runCommandInput) + runCommandOutput, err := a.Client.SendCommand(a.Context, runCommandInput) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } @@ -93,12 +87,12 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { } waiter := ssm.NewCommandExecutedWaiter(a.Client) - _, err = waiter.WaitForOutput(context.Background(), commandInvocationInput, time.Hour) + _, err = waiter.WaitForOutput(a.Context, commandInvocationInput, time.Hour) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } - getCommandOutput, err := a.Client.GetCommandInvocation(context.Background(), commandInvocationInput) + getCommandOutput, err := a.Client.GetCommandInvocation(a.Context, commandInvocationInput) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } From 8669a9fec5ef325f84f0eb0817d3fb04644794cb Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Thu, 25 Jan 2024 11:59:41 +0100 Subject: [PATCH 16/26] Implement 'aws_ssm' connection type #26 --- internal/client/connection_aws_ssm.go | 6 +++--- internal/provider/instance_client.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index 8b6c747..825410b 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -25,7 +25,8 @@ func (a *AWSSSMConnection) Info() string { } func (a *AWSSSMConnection) User() string { - return "root" + out, _ := a.Command([]string{"whoami"}) + return strings.TrimSpace(string(out)) } func (a *AWSSSMConnection) Connect() error { @@ -108,7 +109,6 @@ func (a *AWSSSMConnection) CopyFile(localPath string, remotePath string) error { encodedContent := base64.StdEncoding.EncodeToString(fileContent) cmd := fmt.Sprintf("echo -n %s | base64 -d > %s", encodedContent, remotePath) - cmdLine := []string{"sh", "-c", "\"" + cmd + "\""} - _, err = a.Command(cmdLine) + _, err = a.Command([]string{cmd}) return err } diff --git a/internal/provider/instance_client.go b/internal/provider/instance_client.go index 6f6f78f..fab7aa9 100644 --- a/internal/provider/instance_client.go +++ b/internal/provider/instance_client.go @@ -220,7 +220,7 @@ func (ic *InstanceClient) ReadStatus() (InstanceStatus, error) { func (ic *InstanceClient) bootstrap() error { return ic.doActionOnce("bootstrap", ic.cl.WorkDir, func() error { - return ic.runScript("bootstrap", ic.data.System.Bootstrap, ic.cl.WorkDir) + return ic.runScript("bootstrap", ic.data.System.Bootstrap, ".") }) } From e41d5d6358c38c5c98b5dde914b5af42aab95317 Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Thu, 25 Jan 2024 12:03:34 +0100 Subject: [PATCH 17/26] Implement 'aws_ssm' connection type #26 --- internal/client/connection_ssh.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/internal/client/connection_ssh.go b/internal/client/connection_ssh.go index c7baa18..cf57f95 100644 --- a/internal/client/connection_ssh.go +++ b/internal/client/connection_ssh.go @@ -94,11 +94,10 @@ func (s *SSHConnection) Command(cmdLine []string) ([]byte, error) { return nil, fmt.Errorf("ssh: cannot create command '%s' for host '%s': %w", strings.Join(cmdLine, " "), s.host, err) } out, err := cmd.CombinedOutput() - if err != nil { - if len(out) > 0 { - return nil, fmt.Errorf("ssh: cannot run command '%s': %w\n\n%s", cmd, err, string(out)) - } - return nil, err + if err != nil && len(out) > 0 { + return nil, fmt.Errorf("ssh: cannot run command '%s': %w\n\n%s", cmd, err, string(out)) + } else if err != nil { + return nil, fmt.Errorf("ssh: cannot run command '%s': %w", cmd, err) } return out, nil } From 96d905a165f469d92785678ae0e62c0c2f183521 Mon Sep 17 00:00:00 2001 From: Krystian Panek Date: Fri, 26 Jan 2024 08:41:52 +0100 Subject: [PATCH 18/26] Default region + error handling --- examples/aws_ssm/aem.tf | 1 - internal/client/client_manager.go | 3 +++ internal/client/connection_aws_ssm.go | 38 ++++++++++++++------------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/examples/aws_ssm/aem.tf b/examples/aws_ssm/aem.tf index 10f35e3..c4fea01 100644 --- a/examples/aws_ssm/aem.tf +++ b/examples/aws_ssm/aem.tf @@ -5,7 +5,6 @@ resource "aem_instance" "single" { type = "aws-ssm" settings = { instance_id = aws_instance.aem_single.id - region = "eu-central-1" // TODO infer from AWS provider config } } diff --git a/internal/client/client_manager.go b/internal/client/client_manager.go index f76c463..f1f686a 100644 --- a/internal/client/client_manager.go +++ b/internal/client/client_manager.go @@ -1,6 +1,7 @@ package client import ( + "context" "fmt" "github.com/spf13/cast" ) @@ -42,6 +43,8 @@ func (c ClientManager) connection(typeName string, settings map[string]string) ( return &AWSSSMConnection{ InstanceID: settings["instance_id"], Region: settings["region"], + + context: context.Background(), }, nil } return nil, fmt.Errorf("unknown AEM client type: %s", typeName) diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index 825410b..7b7b5a1 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -17,7 +17,8 @@ type AWSSSMConnection struct { Region string Client *ssm.Client SessionId *string - Context context.Context + + context context.Context } func (a *AWSSSMConnection) Info() string { @@ -25,23 +26,28 @@ func (a *AWSSSMConnection) Info() string { } func (a *AWSSSMConnection) User() string { - out, _ := a.Command([]string{"whoami"}) + out, err := a.Command([]string{"whoami"}) + if err != nil { + panic(fmt.Sprintf("ssm: cannot determine connected user: %s", err)) + } return strings.TrimSpace(string(out)) } func (a *AWSSSMConnection) Connect() error { - // Specify the AWS region - a.Context = context.Background() - cfg, err := config.LoadDefaultConfig(a.Context, config.WithRegion(a.Region)) + var optFns []func(*config.LoadOptions) error + if a.Region != "" { + optFns = append(optFns, config.WithRegion(a.Region)) + } + + cfg, err := config.LoadDefaultConfig(a.context, optFns...) if err != nil { return err } - // Create an SSM client client := ssm.NewFromConfig(cfg) startSessionInput := &ssm.StartSessionInput{Target: aws.String(a.InstanceID)} - startSessionOutput, err := client.StartSession(a.Context, startSessionInput) + startSessionOutput, err := client.StartSession(a.context, startSessionInput) if err != nil { return fmt.Errorf("ssm: error starting session: %v", err) } @@ -56,7 +62,7 @@ func (a *AWSSSMConnection) Disconnect() error { // Disconnect from the session terminateSessionInput := &ssm.TerminateSessionInput{SessionId: a.SessionId} - _, err := a.Client.TerminateSession(a.Context, terminateSessionInput) + _, err := a.Client.TerminateSession(a.context, terminateSessionInput) if err != nil { return fmt.Errorf("ssm: error terminating session: %v", err) } @@ -65,7 +71,6 @@ func (a *AWSSSMConnection) Disconnect() error { } func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { - // Execute command on the remote instance command := strings.Join(cmdLine, " ") runCommandInput := &ssm.SendCommandInput{ DocumentName: aws.String("AWS-RunShellScript"), @@ -74,31 +79,28 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { "commands": {command}, }, } - - runCommandOutput, err := a.Client.SendCommand(a.Context, runCommandInput) + runOut, err := a.Client.SendCommand(a.context, runCommandInput) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } - commandId := runCommandOutput.Command.CommandId - - commandInvocationInput := &ssm.GetCommandInvocationInput{ + commandId := runOut.Command.CommandId + invocationIn := &ssm.GetCommandInvocationInput{ CommandId: commandId, InstanceId: aws.String(a.InstanceID), } - waiter := ssm.NewCommandExecutedWaiter(a.Client) - _, err = waiter.WaitForOutput(a.Context, commandInvocationInput, time.Hour) + _, err = waiter.WaitForOutput(a.context, invocationIn, time.Hour) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } - getCommandOutput, err := a.Client.GetCommandInvocation(a.Context, commandInvocationInput) + invocationOut, err := a.Client.GetCommandInvocation(a.context, invocationIn) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } - return []byte(*getCommandOutput.StandardOutputContent), nil + return []byte(*invocationOut.StandardOutputContent), nil } func (a *AWSSSMConnection) CopyFile(localPath string, remotePath string) error { From c5dcc2397d2f472e43892606839b14d791892664 Mon Sep 17 00:00:00 2001 From: Krystian Panek Date: Fri, 26 Jan 2024 09:18:44 +0100 Subject: [PATCH 19/26] Defaults upgrade --- README.md | 4 +++ examples/aws_ssh/aem.yml | 38 +++++++++++++++++++++++++++-- internal/provider/instance/aem.yml | 38 +++++++++++++++++++++++++++-- internal/provider/instance_model.go | 2 +- 4 files changed, 77 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e29011b..0306bed 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,10 @@ For example: - `sh develop.sh examples/aws_ssh apply -auto-approve` - `sh develop.sh examples/aws_ssh destroy -auto-approve` +- `sh develop.sh examples/aws_ssm plan` +- `sh develop.sh examples/aws_ssm apply -auto-approve` +- `sh develop.sh examples/aws_ssm destroy -auto-approve` + ## Debugging the Provider 1. Run command `go run . -debug` from IDEA in debug mode and copy the value of `TF_REATTACH_PROVIDERS` from the output. diff --git a/examples/aws_ssh/aem.yml b/examples/aws_ssh/aem.yml index e397306..a897b1d 100644 --- a/examples/aws_ssh/aem.yml +++ b/examples/aws_ssh/aem.yml @@ -63,7 +63,7 @@ instance: # Time to wait for next state checking interval: 6s # Number of successful check attempts that indicates end of checking - done_threshold: 3 + done_threshold: 4 # Wait only for those instances whose state has been changed internally (unaware of external changes) await_strict: true # Max time to wait for the instance to be healthy after executing the start script or e.g deploying a package @@ -74,12 +74,15 @@ instance: timeout: 10m # Max time in which socket connection to instance should be established reachable: + skip: false timeout: 3s # Bundle state tracking bundle_stable: + skip: false symbolic_names_ignored: [] # OSGi events tracking event_stable: + skip: false # Topics indicating that instance is not stable topics_unstable: - "org/osgi/framework/ServiceEvent/*" @@ -91,8 +94,20 @@ instance: - "org.osgi.service.component.runtime.ServiceComponentRuntime" - "java.util.ResourceBundle" received_max_age: 5s + # OSGi components state tracking + component_stable: + skip: false + pids: + include: ['com.day.crx.packaging.*', 'org.apache.sling.installer.*'] + exclude: ['org.apache.sling.installer.hc.*', 'org.apache.sling.installer.core.impl.console.*'] + match: + "disabled": [] + "no config": [] + "unsatisfied (reference)": [] + "satisfied": [] # Sling Installer tracking installer: + skip: false # JMX state checking state: true # Pause Installation nodes checking @@ -100,7 +115,11 @@ instance: # Specific endpoints / paths (like login page) path_ready: timeout: 10s - + login_page: + skip: false + path: "/libs/granite/core/content/login.html" + status_code: 200 + contained_text: QUICKSTART_HOMEPAGE # Managed locally (set up automatically) local: @@ -138,6 +157,7 @@ instance: package: # Force re-uploading/installing of snapshot AEM packages (just built / unreleased) snapshot_patterns: [ "**/*-SNAPSHOT.zip" ] + snapshot_ignored: false # Use checksums to avoid re-deployments when snapshot AEM packages are unchanged snapshot_deploy_skipping: true # Disable following workflow launchers for a package deployment time only @@ -151,6 +171,16 @@ instance: console: false # Fail on case 'installed with errors' strict: true + # Number of changes after which the commit to the repository is performed + install_save_threshold: 1024 + # Allows to relax dependency handling if needed + install_dependency_handling: required + # Controls how 'rep:policy' nodes are handled during import + install_ac_handling: '' + + # 'SSL By Default' + ssl: + setup_timeout: 30s # OSGi Framework osgi: @@ -166,6 +196,10 @@ instance: crypto: key_bundle_symbolic_name: com.adobe.granite.crypto.file + # Replication + replication: + bundle_symbolic_name: com.day.cq.cq-replication + # Workflow Manager workflow: launcher: diff --git a/internal/provider/instance/aem.yml b/internal/provider/instance/aem.yml index e397306..a897b1d 100644 --- a/internal/provider/instance/aem.yml +++ b/internal/provider/instance/aem.yml @@ -63,7 +63,7 @@ instance: # Time to wait for next state checking interval: 6s # Number of successful check attempts that indicates end of checking - done_threshold: 3 + done_threshold: 4 # Wait only for those instances whose state has been changed internally (unaware of external changes) await_strict: true # Max time to wait for the instance to be healthy after executing the start script or e.g deploying a package @@ -74,12 +74,15 @@ instance: timeout: 10m # Max time in which socket connection to instance should be established reachable: + skip: false timeout: 3s # Bundle state tracking bundle_stable: + skip: false symbolic_names_ignored: [] # OSGi events tracking event_stable: + skip: false # Topics indicating that instance is not stable topics_unstable: - "org/osgi/framework/ServiceEvent/*" @@ -91,8 +94,20 @@ instance: - "org.osgi.service.component.runtime.ServiceComponentRuntime" - "java.util.ResourceBundle" received_max_age: 5s + # OSGi components state tracking + component_stable: + skip: false + pids: + include: ['com.day.crx.packaging.*', 'org.apache.sling.installer.*'] + exclude: ['org.apache.sling.installer.hc.*', 'org.apache.sling.installer.core.impl.console.*'] + match: + "disabled": [] + "no config": [] + "unsatisfied (reference)": [] + "satisfied": [] # Sling Installer tracking installer: + skip: false # JMX state checking state: true # Pause Installation nodes checking @@ -100,7 +115,11 @@ instance: # Specific endpoints / paths (like login page) path_ready: timeout: 10s - + login_page: + skip: false + path: "/libs/granite/core/content/login.html" + status_code: 200 + contained_text: QUICKSTART_HOMEPAGE # Managed locally (set up automatically) local: @@ -138,6 +157,7 @@ instance: package: # Force re-uploading/installing of snapshot AEM packages (just built / unreleased) snapshot_patterns: [ "**/*-SNAPSHOT.zip" ] + snapshot_ignored: false # Use checksums to avoid re-deployments when snapshot AEM packages are unchanged snapshot_deploy_skipping: true # Disable following workflow launchers for a package deployment time only @@ -151,6 +171,16 @@ instance: console: false # Fail on case 'installed with errors' strict: true + # Number of changes after which the commit to the repository is performed + install_save_threshold: 1024 + # Allows to relax dependency handling if needed + install_dependency_handling: required + # Controls how 'rep:policy' nodes are handled during import + install_ac_handling: '' + + # 'SSL By Default' + ssl: + setup_timeout: 30s # OSGi Framework osgi: @@ -166,6 +196,10 @@ instance: crypto: key_bundle_symbolic_name: com.adobe.granite.crypto.file + # Replication + replication: + bundle_symbolic_name: com.day.cq.cq-replication + # Workflow Manager workflow: launcher: diff --git a/internal/provider/instance_model.go b/internal/provider/instance_model.go index 815353b..c212dc9 100644 --- a/internal/provider/instance_model.go +++ b/internal/provider/instance_model.go @@ -190,7 +190,7 @@ func (r *InstanceResource) Schema(ctx context.Context, req resource.SchemaReques MarkdownDescription: "Version of AEM Compose tool to use on remote machine.", Computed: true, Optional: true, - Default: stringdefault.StaticString("1.5.9"), + Default: stringdefault.StaticString("1.6.12"), }, "config": schema.StringAttribute{ MarkdownDescription: "Contents o f the AEM Compose YML configuration file.", From 62500c71f00de4692db7a43eaa3d8f97cbf0f9a6 Mon Sep 17 00:00:00 2001 From: Krystian Panek Date: Fri, 26 Jan 2024 09:28:09 +0100 Subject: [PATCH 20/26] Private fields --- internal/client/connection_aws_ssm.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index 7b7b5a1..6e9469a 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -15,10 +15,10 @@ import ( type AWSSSMConnection struct { InstanceID string Region string - Client *ssm.Client - SessionId *string - context context.Context + client *ssm.Client + sessionId *string + context context.Context } func (a *AWSSSMConnection) Info() string { @@ -52,17 +52,17 @@ func (a *AWSSSMConnection) Connect() error { return fmt.Errorf("ssm: error starting session: %v", err) } - a.Client = client - a.SessionId = startSessionOutput.SessionId + a.client = client + a.sessionId = startSessionOutput.SessionId return nil } func (a *AWSSSMConnection) Disconnect() error { // Disconnect from the session - terminateSessionInput := &ssm.TerminateSessionInput{SessionId: a.SessionId} + terminateSessionInput := &ssm.TerminateSessionInput{SessionId: a.sessionId} - _, err := a.Client.TerminateSession(a.context, terminateSessionInput) + _, err := a.client.TerminateSession(a.context, terminateSessionInput) if err != nil { return fmt.Errorf("ssm: error terminating session: %v", err) } @@ -79,7 +79,7 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { "commands": {command}, }, } - runOut, err := a.Client.SendCommand(a.context, runCommandInput) + runOut, err := a.client.SendCommand(a.context, runCommandInput) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } @@ -89,13 +89,13 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { CommandId: commandId, InstanceId: aws.String(a.InstanceID), } - waiter := ssm.NewCommandExecutedWaiter(a.Client) + waiter := ssm.NewCommandExecutedWaiter(a.client) _, err = waiter.WaitForOutput(a.context, invocationIn, time.Hour) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } - invocationOut, err := a.Client.GetCommandInvocation(a.context, invocationIn) + invocationOut, err := a.client.GetCommandInvocation(a.context, invocationIn) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } From 8df542834b4c93f23697f2fa9a281ec17fc231f0 Mon Sep 17 00:00:00 2001 From: Krystian Panek Date: Fri, 26 Jan 2024 09:53:25 +0100 Subject: [PATCH 21/26] Minor imprs --- examples/aws_ssm/aem.tf | 1 + internal/client/client_manager.go | 8 +++---- internal/client/connection_aws_ssm.go | 34 +++++++++++++++++---------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/examples/aws_ssm/aem.tf b/examples/aws_ssm/aem.tf index c4fea01..629bda9 100644 --- a/examples/aws_ssm/aem.tf +++ b/examples/aws_ssm/aem.tf @@ -40,6 +40,7 @@ resource "aem_instance" "single" { "sh aemw osgi config save --pid 'org.apache.sling.jcr.davex.impl.servlets.SlingDavExServlet' --input-string 'alias: /crx/server'", "sh aemw repl agent setup -A --location 'author' --name 'publish' --input-string '{enabled: true, transportUri: \"http://localhost:4503/bin/receive?sling:authRequestLogin=1\", transportUser: admin, transportPassword: admin, userId: admin}'", "sh aemw package deploy --file 'aem/home/lib/aem-service-pkg-6.5.*.0.zip'", + "invalid-command" ] } } diff --git a/internal/client/client_manager.go b/internal/client/client_manager.go index f1f686a..3cae017 100644 --- a/internal/client/client_manager.go +++ b/internal/client/client_manager.go @@ -41,10 +41,10 @@ func (c ClientManager) connection(typeName string, settings map[string]string) ( }, nil case "aws-ssm": return &AWSSSMConnection{ - InstanceID: settings["instance_id"], - Region: settings["region"], - - context: context.Background(), + instanceID: settings["instance_id"], + region: settings["region"], + outputTimeout: cast.ToDuration(settings["output_timeout"]), + context: context.Background(), }, nil } return nil, fmt.Errorf("unknown AEM client type: %s", typeName) diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index 6e9469a..609a781 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -13,16 +13,20 @@ import ( ) type AWSSSMConnection struct { - InstanceID string - Region string - - client *ssm.Client - sessionId *string - context context.Context + instanceID string + region string + outputTimeout time.Duration + client *ssm.Client + sessionId *string + context context.Context } func (a *AWSSSMConnection) Info() string { - return fmt.Sprintf("ssm: instance_id='%s', region='%s'", a.InstanceID, a.Region) + region := a.region + if region == "" { + region = "" + } + return fmt.Sprintf("ssm: instance_id='%s', region='%s'", a.instanceID, region) } func (a *AWSSSMConnection) User() string { @@ -34,9 +38,13 @@ func (a *AWSSSMConnection) User() string { } func (a *AWSSSMConnection) Connect() error { + if a.outputTimeout == 0 { + a.outputTimeout = time.Hour + } + var optFns []func(*config.LoadOptions) error - if a.Region != "" { - optFns = append(optFns, config.WithRegion(a.Region)) + if a.region != "" { + optFns = append(optFns, config.WithRegion(a.region)) } cfg, err := config.LoadDefaultConfig(a.context, optFns...) @@ -45,7 +53,7 @@ func (a *AWSSSMConnection) Connect() error { } client := ssm.NewFromConfig(cfg) - startSessionInput := &ssm.StartSessionInput{Target: aws.String(a.InstanceID)} + startSessionInput := &ssm.StartSessionInput{Target: aws.String(a.instanceID)} startSessionOutput, err := client.StartSession(a.context, startSessionInput) if err != nil { @@ -74,7 +82,7 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { command := strings.Join(cmdLine, " ") runCommandInput := &ssm.SendCommandInput{ DocumentName: aws.String("AWS-RunShellScript"), - InstanceIds: []string{a.InstanceID}, + InstanceIds: []string{a.instanceID}, Parameters: map[string][]string{ "commands": {command}, }, @@ -87,10 +95,10 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { commandId := runOut.Command.CommandId invocationIn := &ssm.GetCommandInvocationInput{ CommandId: commandId, - InstanceId: aws.String(a.InstanceID), + InstanceId: aws.String(a.instanceID), } waiter := ssm.NewCommandExecutedWaiter(a.client) - _, err = waiter.WaitForOutput(a.context, invocationIn, time.Hour) + _, err = waiter.WaitForOutput(a.context, invocationIn, a.outputTimeout) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } From 43402567bfde3f248e9a8921bdb28e0e60fb24fe Mon Sep 17 00:00:00 2001 From: Krystian Panek Date: Fri, 26 Jan 2024 09:57:53 +0100 Subject: [PATCH 22/26] Deps upgrade --- go.mod | 24 ++++++++++++------------ go.sum | 52 ++++++++++++++++++++++++++-------------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/go.mod b/go.mod index c458e92..eb61f94 100644 --- a/go.mod +++ b/go.mod @@ -7,13 +7,13 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.26.6 github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 github.com/hashicorp/terraform-plugin-docs v0.16.0 - github.com/hashicorp/terraform-plugin-framework v1.4.2 - github.com/hashicorp/terraform-plugin-go v0.19.0 + github.com/hashicorp/terraform-plugin-framework v1.5.0 + github.com/hashicorp/terraform-plugin-go v0.20.0 github.com/hashicorp/terraform-plugin-log v0.9.0 github.com/melbahja/goph v1.4.0 - github.com/spf13/cast v1.5.1 - golang.org/x/crypto v0.15.0 - golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa + github.com/spf13/cast v1.6.0 + golang.org/x/crypto v0.18.0 + golang.org/x/exp v0.0.0-20240119083558-1b970713d09a gopkg.in/yaml.v3 v3.0.1 ) @@ -39,11 +39,11 @@ require ( github.com/cloudflare/circl v1.3.3 // indirect github.com/fatih/color v1.16.0 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/uuid v1.4.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-hclog v1.6.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.6.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect @@ -74,10 +74,10 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/zclconf/go-cty v1.13.2 // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.18.0 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect - google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect + google.golang.org/grpc v1.61.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect ) diff --git a/go.sum b/go.sum index 4466e08..40799d6 100644 --- a/go.sum +++ b/go.sum @@ -57,7 +57,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4= github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk= @@ -68,8 +68,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -78,8 +78,8 @@ github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuD github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I= +github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= @@ -98,10 +98,10 @@ github.com/hashicorp/terraform-json v0.17.1 h1:eMfvh/uWggKmY7Pmb3T85u86E2EQg6EQH github.com/hashicorp/terraform-json v0.17.1/go.mod h1:Huy6zt6euxaY9knPAFKjUITn8QxUFIe9VuSzb4zn/0o= github.com/hashicorp/terraform-plugin-docs v0.16.0 h1:UmxFr3AScl6Wged84jndJIfFccGyBZn52KtMNsS12dI= github.com/hashicorp/terraform-plugin-docs v0.16.0/go.mod h1:M3ZrlKBJAbPMtNOPwHicGi1c+hZUh7/g0ifT/z7TVfA= -github.com/hashicorp/terraform-plugin-framework v1.4.2 h1:P7a7VP1GZbjc4rv921Xy5OckzhoiO3ig6SGxwelD2sI= -github.com/hashicorp/terraform-plugin-framework v1.4.2/go.mod h1:GWl3InPFZi2wVQmdVnINPKys09s9mLmTZr95/ngLnbY= -github.com/hashicorp/terraform-plugin-go v0.19.0 h1:BuZx/6Cp+lkmiG0cOBk6Zps0Cb2tmqQpDM3iAtnhDQU= -github.com/hashicorp/terraform-plugin-go v0.19.0/go.mod h1:EhRSkEPNoylLQntYsk5KrDHTZJh9HQoumZXbOGOXmec= +github.com/hashicorp/terraform-plugin-framework v1.5.0 h1:8kcvqJs/x6QyOFSdeAyEgsenVOUeC/IyKpi2ul4fjTg= +github.com/hashicorp/terraform-plugin-framework v1.5.0/go.mod h1:6waavirukIlFpVpthbGd2PUNYaFedB0RwW3MDzJ/rtc= +github.com/hashicorp/terraform-plugin-go v0.20.0 h1:oqvoUlL+2EUbKNsJbIt3zqqZ7wi6lzn4ufkn/UA51xQ= +github.com/hashicorp/terraform-plugin-go v0.20.0/go.mod h1:Rr8LBdMlY53a3Z/HpP+ZU3/xCDqtKNCkeI9qOyT10QE= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI= @@ -173,8 +173,8 @@ github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5g github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -201,10 +201,10 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= +golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= @@ -215,8 +215,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -237,13 +237,13 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -257,14 +257,14 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:bQnxqljG/wqi4NTXu2+DJ3n7APcEA882QZ1JvhQAq9o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= From 2d1fbf5f9ec7e75ef3e76fd298defe1cca01d1c6 Mon Sep 17 00:00:00 2001 From: Dominik Przybyl Date: Fri, 26 Jan 2024 12:30:48 +0100 Subject: [PATCH 23/26] Performance improvement --- examples/aws_ssm/aem.tf | 1 - internal/client/client_manager.go | 2 ++ internal/client/connection_aws_ssm.go | 30 +++++++++++++++++++-------- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/examples/aws_ssm/aem.tf b/examples/aws_ssm/aem.tf index 629bda9..c4fea01 100644 --- a/examples/aws_ssm/aem.tf +++ b/examples/aws_ssm/aem.tf @@ -40,7 +40,6 @@ resource "aem_instance" "single" { "sh aemw osgi config save --pid 'org.apache.sling.jcr.davex.impl.servlets.SlingDavExServlet' --input-string 'alias: /crx/server'", "sh aemw repl agent setup -A --location 'author' --name 'publish' --input-string '{enabled: true, transportUri: \"http://localhost:4503/bin/receive?sling:authRequestLogin=1\", transportUser: admin, transportPassword: admin, userId: admin}'", "sh aemw package deploy --file 'aem/home/lib/aem-service-pkg-6.5.*.0.zip'", - "invalid-command" ] } } diff --git a/internal/client/client_manager.go b/internal/client/client_manager.go index 3cae017..2327db8 100644 --- a/internal/client/client_manager.go +++ b/internal/client/client_manager.go @@ -44,6 +44,8 @@ func (c ClientManager) connection(typeName string, settings map[string]string) ( instanceID: settings["instance_id"], region: settings["region"], outputTimeout: cast.ToDuration(settings["output_timeout"]), + minWaitDelay: cast.ToDuration(settings["min_wait_delay"]), + maxWaitDelay: cast.ToDuration(settings["max_wait_delay"]), context: context.Background(), }, nil } diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index 609a781..5fc5824 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -16,6 +16,8 @@ type AWSSSMConnection struct { instanceID string region string outputTimeout time.Duration + minWaitDelay time.Duration + maxWaitDelay time.Duration client *ssm.Client sessionId *string context context.Context @@ -39,7 +41,13 @@ func (a *AWSSSMConnection) User() string { func (a *AWSSSMConnection) Connect() error { if a.outputTimeout == 0 { - a.outputTimeout = time.Hour + a.outputTimeout = 5 * time.Hour + } + if a.minWaitDelay == 0 { + a.minWaitDelay = 5 * time.Millisecond + } + if a.maxWaitDelay == 0 { + a.maxWaitDelay = 5 * time.Second } var optFns []func(*config.LoadOptions) error @@ -97,15 +105,19 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { CommandId: commandId, InstanceId: aws.String(a.instanceID), } - waiter := ssm.NewCommandExecutedWaiter(a.client) - _, err = waiter.WaitForOutput(a.context, invocationIn, a.outputTimeout) + optFns := []func(opt *ssm.CommandExecutedWaiterOptions){func(opt *ssm.CommandExecutedWaiterOptions) { + opt.MinDelay = a.minWaitDelay + opt.MaxDelay = a.maxWaitDelay + }} + waiter := ssm.NewCommandExecutedWaiter(a.client, optFns...) + invocationOut, err := waiter.WaitForOutput(a.context, invocationIn, a.outputTimeout) if err != nil { - return nil, fmt.Errorf("ssm: error executing command: %v", err) - } - - invocationOut, err := a.client.GetCommandInvocation(a.context, invocationIn) - if err != nil { - return nil, fmt.Errorf("ssm: error executing command: %v", err) + invocationOut, err = a.client.GetCommandInvocation(a.context, invocationIn) + if invocationOut != nil { + return nil, fmt.Errorf("ssm: error executing command: %v", *invocationOut.StandardErrorContent) + } else if err != nil { + return nil, fmt.Errorf("ssm: error executing command: %v", err) + } } return []byte(*invocationOut.StandardOutputContent), nil From d4043d4699d90416a1750b5667805a9653e951f6 Mon Sep 17 00:00:00 2001 From: Krystian Panek Date: Mon, 29 Jan 2024 11:10:07 +0100 Subject: [PATCH 24/26] SSM works like a charm ;) --- internal/client/client_manager.go | 12 +++--- internal/client/connection_aws_ssm.go | 59 ++++++++++++++------------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/internal/client/client_manager.go b/internal/client/client_manager.go index 2327db8..8f37b5d 100644 --- a/internal/client/client_manager.go +++ b/internal/client/client_manager.go @@ -41,12 +41,12 @@ func (c ClientManager) connection(typeName string, settings map[string]string) ( }, nil case "aws-ssm": return &AWSSSMConnection{ - instanceID: settings["instance_id"], - region: settings["region"], - outputTimeout: cast.ToDuration(settings["output_timeout"]), - minWaitDelay: cast.ToDuration(settings["min_wait_delay"]), - maxWaitDelay: cast.ToDuration(settings["max_wait_delay"]), - context: context.Background(), + instanceID: settings["instance_id"], + region: settings["region"], + context: context.Background(), + commandOutputTimeout: cast.ToDuration(settings["command_output_timeout"]), + commandWaitMin: cast.ToDuration(settings["command_wait_min"]), + commandWaitMax: cast.ToDuration(settings["command_wait_max"]), }, nil } return nil, fmt.Errorf("unknown AEM client type: %s", typeName) diff --git a/internal/client/connection_aws_ssm.go b/internal/client/connection_aws_ssm.go index 5fc5824..e2a5608 100644 --- a/internal/client/connection_aws_ssm.go +++ b/internal/client/connection_aws_ssm.go @@ -13,14 +13,14 @@ import ( ) type AWSSSMConnection struct { - instanceID string - region string - outputTimeout time.Duration - minWaitDelay time.Duration - maxWaitDelay time.Duration - client *ssm.Client - sessionId *string - context context.Context + instanceID string + region string + client *ssm.Client + sessionId *string + context context.Context + commandOutputTimeout time.Duration + commandWaitMax time.Duration + commandWaitMin time.Duration } func (a *AWSSSMConnection) Info() string { @@ -40,14 +40,14 @@ func (a *AWSSSMConnection) User() string { } func (a *AWSSSMConnection) Connect() error { - if a.outputTimeout == 0 { - a.outputTimeout = 5 * time.Hour + if a.commandOutputTimeout == 0 { + a.commandOutputTimeout = 5 * time.Hour } - if a.minWaitDelay == 0 { - a.minWaitDelay = 5 * time.Millisecond + if a.commandWaitMin == 0 { + a.commandWaitMin = 5 * time.Millisecond } - if a.maxWaitDelay == 0 { - a.maxWaitDelay = 5 * time.Second + if a.commandWaitMax == 0 { + a.commandWaitMax = 5 * time.Second } var optFns []func(*config.LoadOptions) error @@ -61,24 +61,21 @@ func (a *AWSSSMConnection) Connect() error { } client := ssm.NewFromConfig(cfg) - startSessionInput := &ssm.StartSessionInput{Target: aws.String(a.instanceID)} - - startSessionOutput, err := client.StartSession(a.context, startSessionInput) + sessionIn := &ssm.StartSessionInput{Target: aws.String(a.instanceID)} + sessionOut, err := client.StartSession(a.context, sessionIn) if err != nil { return fmt.Errorf("ssm: error starting session: %v", err) } a.client = client - a.sessionId = startSessionOutput.SessionId + a.sessionId = sessionOut.SessionId return nil } func (a *AWSSSMConnection) Disconnect() error { - // Disconnect from the session - terminateSessionInput := &ssm.TerminateSessionInput{SessionId: a.sessionId} - - _, err := a.client.TerminateSession(a.context, terminateSessionInput) + sessionIn := &ssm.TerminateSessionInput{SessionId: a.sessionId} + _, err := a.client.TerminateSession(a.context, sessionIn) if err != nil { return fmt.Errorf("ssm: error terminating session: %v", err) } @@ -88,14 +85,14 @@ func (a *AWSSSMConnection) Disconnect() error { func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { command := strings.Join(cmdLine, " ") - runCommandInput := &ssm.SendCommandInput{ + commandIn := &ssm.SendCommandInput{ DocumentName: aws.String("AWS-RunShellScript"), InstanceIds: []string{a.instanceID}, Parameters: map[string][]string{ "commands": {command}, }, } - runOut, err := a.client.SendCommand(a.context, runCommandInput) + runOut, err := a.client.SendCommand(a.context, commandIn) if err != nil { return nil, fmt.Errorf("ssm: error executing command: %v", err) } @@ -105,12 +102,16 @@ func (a *AWSSSMConnection) Command(cmdLine []string) ([]byte, error) { CommandId: commandId, InstanceId: aws.String(a.instanceID), } - optFns := []func(opt *ssm.CommandExecutedWaiterOptions){func(opt *ssm.CommandExecutedWaiterOptions) { - opt.MinDelay = a.minWaitDelay - opt.MaxDelay = a.maxWaitDelay - }} + var optFns []func(opt *ssm.CommandExecutedWaiterOptions) + if a.commandWaitMax > 0 && a.commandWaitMin > 0 { + optFns = []func(opt *ssm.CommandExecutedWaiterOptions){func(opt *ssm.CommandExecutedWaiterOptions) { + opt.MinDelay = a.commandWaitMin + opt.MaxDelay = a.commandWaitMax + }} + } + waiter := ssm.NewCommandExecutedWaiter(a.client, optFns...) - invocationOut, err := waiter.WaitForOutput(a.context, invocationIn, a.outputTimeout) + invocationOut, err := waiter.WaitForOutput(a.context, invocationIn, a.commandOutputTimeout) if err != nil { invocationOut, err = a.client.GetCommandInvocation(a.context, invocationIn) if invocationOut != nil { From 9f3b2710f4d5e258bee339364bb99986b995f022 Mon Sep 17 00:00:00 2001 From: Krystian Panek Date: Mon, 29 Jan 2024 11:48:31 +0100 Subject: [PATCH 25/26] Timeouts configurable --- docs/resources/instance.md | 2 ++ internal/provider/instance_model.go | 20 +++++++++++++++++--- internal/provider/instance_resource.go | 7 ++++--- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/docs/resources/instance.md b/docs/resources/instance.md index f1b77be..c92faec 100644 --- a/docs/resources/instance.md +++ b/docs/resources/instance.md @@ -48,7 +48,9 @@ Required: Optional: +- `action_timeout` (String) Used when trying to connect to the AEM instance machine (often right after creating it). Need to be enough long because various types of connections (like AWS SSM or SSH) may need some time to boot up the agent. - `credentials` (Map of String, Sensitive) Credentials for the connection type +- `state_timeout` (String) Used when reading the AEM instance state when determining the plan. diff --git a/internal/provider/instance_model.go b/internal/provider/instance_model.go index c212dc9..77755f2 100644 --- a/internal/provider/instance_model.go +++ b/internal/provider/instance_model.go @@ -22,9 +22,11 @@ import ( type InstanceResourceModel struct { Client struct { - Type types.String `tfsdk:"type"` - Settings types.Map `tfsdk:"settings"` - Credentials types.Map `tfsdk:"credentials"` + Type types.String `tfsdk:"type"` + Settings types.Map `tfsdk:"settings"` + Credentials types.Map `tfsdk:"credentials"` + ActionTimeout types.String `tfsdk:"action_timeout"` + StateTimeout types.String `tfsdk:"state_timeout"` } `tfsdk:"client"` Files types.Map `tfsdk:"files"` System struct { @@ -122,6 +124,18 @@ func (r *InstanceResource) Schema(ctx context.Context, req resource.SchemaReques Optional: true, Sensitive: true, }, + "action_timeout": schema.StringAttribute{ + MarkdownDescription: "Used when trying to connect to the AEM instance machine (often right after creating it). Need to be enough long because various types of connections (like AWS SSM or SSH) may need some time to boot up the agent.", + Optional: true, + Computed: true, + Default: stringdefault.StaticString("10m"), + }, + "state_timeout": schema.StringAttribute{ + MarkdownDescription: "Used when reading the AEM instance state when determining the plan.", + Optional: true, + Computed: true, + Default: stringdefault.StaticString("30s"), + }, }, }, "system": schema.SingleNestedBlock{ diff --git a/internal/provider/instance_resource.go b/internal/provider/instance_resource.go index fddfaa0..77524bb 100644 --- a/internal/provider/instance_resource.go +++ b/internal/provider/instance_resource.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/spf13/cast" "github.com/wttech/terraform-provider-aem/internal/client" "golang.org/x/exp/maps" "time" @@ -66,7 +67,7 @@ func (r *InstanceResource) createOrUpdate(ctx context.Context, plan *tfsdk.Plan, tflog.Info(ctx, "Started setting up AEM instance resource") - ic, err := r.client(ctx, plannedModel, time.Minute*5) + ic, err := r.client(ctx, plannedModel, cast.ToDuration(plannedModel.Client.ActionTimeout.ValueString())) if err != nil { diags.AddError("Unable to connect to AEM instance", fmt.Sprintf("%s", err)) return @@ -138,7 +139,7 @@ func (r *InstanceResource) Read(ctx context.Context, req resource.ReadRequest, r return } - ic, err := r.client(ctx, model, time.Second*15) + ic, err := r.client(ctx, model, cast.ToDuration(model.Client.StateTimeout.ValueString())) if err != nil { tflog.Info(ctx, "Cannot read AEM instance state as it is not possible to connect at the moment. Possible reasons: machine IP change is in progress, machine is not yet created or booting up, etc.") } else { @@ -173,7 +174,7 @@ func (r *InstanceResource) Delete(ctx context.Context, req resource.DeleteReques tflog.Info(ctx, "Started deleting AEM instance resource") - ic, err := r.client(ctx, model, time.Minute*5) + ic, err := r.client(ctx, model, cast.ToDuration(model.Client.StateTimeout.ValueString())) if err != nil { resp.Diagnostics.AddError("Unable to connect to AEM instance", fmt.Sprintf("%s", err)) return From 5f60ea845d433bdeca1cd50dd20242ac19310124 Mon Sep 17 00:00:00 2001 From: Krystian Panek Date: Mon, 29 Jan 2024 11:49:43 +0100 Subject: [PATCH 26/26] Done threshold --- examples/aws_ssh/aem.yml | 2 +- internal/provider/instance/aem.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/aws_ssh/aem.yml b/examples/aws_ssh/aem.yml index a897b1d..8133864 100644 --- a/examples/aws_ssh/aem.yml +++ b/examples/aws_ssh/aem.yml @@ -63,7 +63,7 @@ instance: # Time to wait for next state checking interval: 6s # Number of successful check attempts that indicates end of checking - done_threshold: 4 + done_threshold: 3 # Wait only for those instances whose state has been changed internally (unaware of external changes) await_strict: true # Max time to wait for the instance to be healthy after executing the start script or e.g deploying a package diff --git a/internal/provider/instance/aem.yml b/internal/provider/instance/aem.yml index a897b1d..8133864 100644 --- a/internal/provider/instance/aem.yml +++ b/internal/provider/instance/aem.yml @@ -63,7 +63,7 @@ instance: # Time to wait for next state checking interval: 6s # Number of successful check attempts that indicates end of checking - done_threshold: 4 + done_threshold: 3 # Wait only for those instances whose state has been changed internally (unaware of external changes) await_strict: true # Max time to wait for the instance to be healthy after executing the start script or e.g deploying a package