Skip to content

Commit bf777ad

Browse files
committed
feat: env prep
1 parent 84f3037 commit bf777ad

File tree

2 files changed

+91
-21
lines changed

2 files changed

+91
-21
lines changed

models/connections.go

+86-16
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package models
22

33
import (
4+
"bytes"
5+
"context"
46
"fmt"
57
"net/url"
8+
"os"
9+
"os/exec"
610
"regexp"
7-
"strings"
811
"time"
912

1013
"github.com/flanksource/duty/types"
@@ -153,33 +156,100 @@ func (c Connection) AsGoGetterURL() (string, error) {
153156
}
154157

155158
// AsEnv generates environment variables and a configuration file content based on the connection type.
156-
func (c Connection) AsEnv() ([]string, string) {
157-
var (
158-
envs []string
159-
file strings.Builder
160-
)
159+
func (c Connection) AsEnv() EnvPrep {
160+
envPrep := EnvPrep{
161+
Conn: c,
162+
}
161163

162164
switch c.Type {
163165
case ConnectionTypeAWS:
164-
envs = append(envs, fmt.Sprintf("AWS_ACCESS_KEY_ID=%s", c.Username))
165-
envs = append(envs, fmt.Sprintf("AWS_SECRET_ACCESS_KEY=%s", c.Password))
166+
envPrep.Env = append(envPrep.Env, fmt.Sprintf("AWS_ACCESS_KEY_ID=%s", c.Username))
167+
envPrep.Env = append(envPrep.Env, fmt.Sprintf("AWS_SECRET_ACCESS_KEY=%s", c.Password))
166168

167-
file.WriteString("[default]\n")
168-
file.WriteString(fmt.Sprintf("aws_access_key_id = %s\n", c.Username))
169-
file.WriteString(fmt.Sprintf("aws_secret_access_key = %s\n", c.Password))
169+
envPrep.File.WriteString("[default]\n")
170+
envPrep.File.WriteString(fmt.Sprintf("aws_access_key_id = %s\n", c.Username))
171+
envPrep.File.WriteString(fmt.Sprintf("aws_secret_access_key = %s\n", c.Password))
170172

171173
if v, ok := c.Properties["profile"]; ok {
172-
envs = append(envs, fmt.Sprintf("AWS_DEFAULT_PROFILE=%s", v))
174+
envPrep.Env = append(envPrep.Env, fmt.Sprintf("AWS_DEFAULT_PROFILE=%s", v))
173175
}
174176

175177
if v, ok := c.Properties["region"]; ok {
176-
envs = append(envs, fmt.Sprintf("AWS_DEFAULT_REGION=%s", v))
177-
file.WriteString(fmt.Sprintf("region = %s\n", v))
178+
envPrep.Env = append(envPrep.Env, fmt.Sprintf("AWS_DEFAULT_REGION=%s", v))
179+
envPrep.File.WriteString(fmt.Sprintf("region = %s\n", v))
178180
}
179181

182+
case ConnectionTypeAzure:
183+
// Do nothing
184+
180185
case ConnectionTypeGCP:
181-
file.WriteString(c.Certificate)
186+
envPrep.File.WriteString(c.Certificate)
187+
}
188+
189+
return envPrep
190+
}
191+
192+
type EnvPrep struct {
193+
Conn Connection
194+
195+
// Env is the connection credentials in environment variables
196+
Env []string
197+
198+
// File contains the content of the configuration file based on the connection
199+
File bytes.Buffer
200+
}
201+
202+
func (c *EnvPrep) Apply(ctx context.Context, cmd *exec.Cmd, configAbsPath string) error {
203+
switch c.Conn.Type {
204+
case ConnectionTypeAWS:
205+
if err := saveConfig(c.File.Bytes(), configAbsPath); err != nil {
206+
return err
207+
}
208+
209+
cmd.Env = append(cmd.Env, "AWS_EC2_METADATA_DISABLED=true") // https://github.com/aws/aws-cli/issues/5262#issuecomment-705832151
210+
cmd.Env = append(cmd.Env, fmt.Sprintf("AWS_SHARED_CREDENTIALS_FILE=%s", configAbsPath))
211+
if v, ok := c.Conn.Properties["region"]; ok {
212+
cmd.Env = append(cmd.Env, fmt.Sprintf("AWS_DEFAULT_REGION=%s", v))
213+
}
214+
215+
case ConnectionTypeGCP:
216+
if err := saveConfig(c.File.Bytes(), configAbsPath); err != nil {
217+
return err
218+
}
219+
220+
// to configure gcloud CLI to use the service account specified in GOOGLE_APPLICATION_CREDENTIALS,
221+
// we need to explicitly activate it
222+
runCmd := exec.Command("gcloud", "auth", "activate-service-account", "--key-file", configAbsPath)
223+
if err := runCmd.Run(); err != nil {
224+
return fmt.Errorf("failed to activate GCP service account: %w", err)
225+
}
226+
227+
cmd.Env = append(cmd.Env, fmt.Sprintf("GOOGLE_APPLICATION_CREDENTIALS=%s", configAbsPath))
228+
229+
case ConnectionTypeAzure:
230+
args := []string{"login", "--service-principal", "--username", c.Conn.Username, "--password", c.Conn.Password}
231+
if v, ok := c.Conn.Properties["tenant"]; ok {
232+
args = append(args, "--tenant")
233+
args = append(args, v)
234+
}
235+
236+
// login with service principal
237+
runCmd := exec.CommandContext(ctx, "az", args...)
238+
if err := runCmd.Run(); err != nil {
239+
return err
240+
}
241+
}
242+
243+
return nil
244+
}
245+
246+
func saveConfig(content []byte, absPath string) error {
247+
file, err := os.Create(absPath)
248+
if err != nil {
249+
return err
182250
}
251+
defer file.Close()
183252

184-
return envs, file.String()
253+
_, err = file.Write(content)
254+
return err
185255
}

models/connections_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,16 @@ func Test_Connection_AsEnv(t *testing.T) {
8787

8888
for _, tc := range testCases {
8989
t.Run(tc.name, func(t *testing.T) {
90-
env, file := tc.connection.AsEnv()
90+
envPrep := tc.connection.AsEnv()
9191

9292
for i, expected := range tc.expectedEnv {
93-
if env[i] != expected {
94-
t.Errorf("Expected environment variable: %s, but got: %s", expected, env[i])
93+
if envPrep.Env[i] != expected {
94+
t.Errorf("Expected environment variable: %s, but got: %s", expected, envPrep.Env[i])
9595
}
9696
}
9797

98-
if file != tc.expectedFile {
99-
t.Errorf("Expected file content:\n%s\nBut got:\n%s", tc.expectedFile, file)
98+
if envPrep.File.String() != tc.expectedFile {
99+
t.Errorf("Expected file content:\n%s\nBut got:\n%s", tc.expectedFile, envPrep.File.String())
100100
}
101101
})
102102
}

0 commit comments

Comments
 (0)