Skip to content

Commit

Permalink
feat: add kubernetes connection in exec connections
Browse files Browse the repository at this point in the history
  • Loading branch information
adityathebe committed Nov 5, 2024
1 parent 7c7dada commit 19d4736
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 17 deletions.
61 changes: 45 additions & 16 deletions connection/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ import (

"github.com/flanksource/commons/logger"
"github.com/flanksource/duty/context"
"github.com/flanksource/duty/types"

textTemplate "text/template"
)

// +kubebuilder:object:generate=true
type ExecConnections struct {
AWS *AWSConnection `yaml:"aws,omitempty" json:"aws,omitempty"`
GCP *GCPConnection `yaml:"gcp,omitempty" json:"gcp,omitempty"`
Azure *AzureConnection `yaml:"azure,omitempty" json:"azure,omitempty"`
Kubernetes *types.EnvVar `yaml:"kubernetes,omitempty" json:"kubernetes,omitempty"`
AWS *AWSConnection `yaml:"aws,omitempty" json:"aws,omitempty"`
GCP *GCPConnection `yaml:"gcp,omitempty" json:"gcp,omitempty"`
Azure *AzureConnection `yaml:"azure,omitempty" json:"azure,omitempty"`
}

func saveConfig(configTemplate *textTemplate.Template, view any) (string, error) {
Expand All @@ -43,8 +45,9 @@ func saveConfig(configTemplate *textTemplate.Template, view any) (string, error)
}

var (
awsConfigTemplate *textTemplate.Template
gcloudConfigTemplate *textTemplate.Template
awsConfigTemplate *textTemplate.Template
kubernetesConfigTemplate *textTemplate.Template
gcloudConfigTemplate *textTemplate.Template
)

func init() {
Expand All @@ -55,20 +58,43 @@ aws_secret_access_key = {{.SecretKey.ValueStatic}}
`))

gcloudConfigTemplate = textTemplate.Must(textTemplate.New("").Parse(`{{.Credentials}}`))

kubernetesConfigTemplate = textTemplate.Must(textTemplate.New("").Parse(`{{.ValueStatic}}`))
}

// SetupCConnections creates the necessary credential files and injects env vars
// into the cmd
func SetupConnection(ctx context.Context, connections ExecConnections, cmd *osExec.Cmd) error {
func SetupConnection(ctx context.Context, connections ExecConnections, cmd *osExec.Cmd) (func() error, error) {
var cleaner = func() error {
return nil
}

if connections.Kubernetes != nil {
configPath, err := saveConfig(kubernetesConfigTemplate, connections.Kubernetes)
if err != nil {
return nil, fmt.Errorf("failed to store AWS credentials: %w", err)
}

cleaner = func() error {
return os.RemoveAll(filepath.Dir(configPath))
}

cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, fmt.Sprintf("KUBECONFIG=%s", configPath))
}

if connections.AWS != nil {
if err := connections.AWS.Populate(ctx); err != nil {
return fmt.Errorf("failed to hydrate aws connection: %w", err)
return nil, fmt.Errorf("failed to hydrate aws connection: %w", err)
}

configPath, err := saveConfig(awsConfigTemplate, connections.AWS)
defer os.RemoveAll(filepath.Dir(configPath))
if err != nil {
return fmt.Errorf("failed to store AWS credentials: %w", err)
return nil, fmt.Errorf("failed to store AWS credentials: %w", err)
}

cleaner = func() error {
return os.RemoveAll(filepath.Dir(configPath))
}

cmd.Env = os.Environ()
Expand All @@ -81,37 +107,40 @@ func SetupConnection(ctx context.Context, connections ExecConnections, cmd *osEx

if connections.Azure != nil {
if err := connections.Azure.HydrateConnection(ctx); err != nil {
return fmt.Errorf("failed to hydrate connection %w", err)
return nil, fmt.Errorf("failed to hydrate connection %w", err)
}

// login with service principal
runCmd := osExec.Command("az", "login", "--service-principal", "--username", connections.Azure.ClientID.ValueStatic, "--password", connections.Azure.ClientSecret.ValueStatic, "--tenant", connections.Azure.TenantID)
if err := runCmd.Run(); err != nil {
return fmt.Errorf("failed to login: %w", err)
return nil, fmt.Errorf("failed to login: %w", err)
}
}

if connections.GCP != nil {
if err := connections.GCP.HydrateConnection(ctx); err != nil {
return fmt.Errorf("failed to hydrate connection %w", err)
return nil, fmt.Errorf("failed to hydrate connection %w", err)
}

configPath, err := saveConfig(gcloudConfigTemplate, connections.GCP)
defer os.RemoveAll(filepath.Dir(configPath))
if err != nil {
return fmt.Errorf("failed to store gcloud credentials: %w", err)
return nil, fmt.Errorf("failed to store gcloud credentials: %w", err)
}

cleaner = func() error {
return os.RemoveAll(filepath.Dir(configPath))
}

// to configure gcloud CLI to use the service account specified in GOOGLE_APPLICATION_CREDENTIALS,
// we need to explicitly activate it
runCmd := osExec.Command("gcloud", "auth", "activate-service-account", "--key-file", configPath)
if err := runCmd.Run(); err != nil {
return fmt.Errorf("failed to activate GCP service account: %w", err)
return nil, fmt.Errorf("failed to activate GCP service account: %w", err)
}

cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, fmt.Sprintf("GOOGLE_APPLICATION_CREDENTIALS=%s", configPath))
}

return nil
return cleaner, nil
}
5 changes: 5 additions & 0 deletions connection/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion shell/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,14 @@ func Run(ctx context.Context, exec Exec) (*ExecDetails, error) {
cmd.Dir = envParams.mountPoint
}

if err := connection.SetupConnection(ctx, exec.Connections, cmd); err != nil {
if cleanup, err := connection.SetupConnection(ctx, exec.Connections, cmd); err != nil {
return nil, ctx.Oops().Wrap(err)
} else {
defer func() {
if err := cleanup(); err != nil {
logger.Errorf("failed to cleanup connection artifacts: %v", err)
}
}()
}

envParams.cmd = cmd
Expand Down
1 change: 1 addition & 0 deletions types/resource_selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type ComponentConfigTraversalArgs struct {
Direction string `yaml:"direction,omitempty" json:"direction,omitempty"`
}

// +kubebuilder:object:generate=true
type Functions struct {
// It uses the config_id linked to the componentID to lookup up all the config relations and returns
// a list of componentIDs that are linked to the found configIDs
Expand Down
21 changes: 21 additions & 0 deletions types/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 19d4736

Please sign in to comment.