Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Remove make from end-user workflow #310

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,19 @@ vendor:
${GOPATH}/bin/dep ensure
bazel run //:gazelle

kustomize:
${GOPATH}/bin/kustomize version || go get -u sigs.k8s.io/kustomize

check-install:
./scripts/check-install.sh

# Generate code.
generate: vendor
generate: vendor kustomize
GOPATH=${GOPATH} go generate ./pkg/... ./cmd/...
# generate kubebuilder components
go run vendor/sigs.k8s.io/controller-tools/cmd/controller-gen/main.go crd
kustomize build vendor/sigs.k8s.io/cluster-api/config/default/ > config/samples/common-provider-components.yaml
kustomize build config/aws-provider-components/ > config/samples/aws-provider-components.yaml

genmocks: vendor
hack/generate-mocks.sh "github.com/aws/aws-sdk-go/service/ec2/ec2iface EC2API" "pkg/cloud/aws/services/ec2/mock_ec2iface/mock.go"
Expand Down Expand Up @@ -94,24 +101,23 @@ clean:
rm -f kubeconfig
rm -f minikube.kubeconfig

# Create cluster.
create-cluster:
clusterctl create cluster -v3 --provider aws -m ./cmd/clusterctl/examples/aws/out/machines.yaml -c ./cmd/clusterctl/examples/aws/out/cluster.yaml -p ./cmd/clusterctl/examples/aws/out/provider-components.yaml

# Development.
# Manifests.
cmd/clusterctl/examples/aws/out/:
MANAGER_IMAGE=${MANAGER_IMAGE} ./cmd/clusterctl/examples/aws/generate-yaml.sh

cmd/clusterctl/examples/aws/out/credentials: cmd/clusterctl/examples/aws/out/ clusterawsadm
clusterawsadm alpha bootstrap generate-aws-default-profile > cmd/clusterctl/examples/aws/out/credentials
out/credentials.yaml: clusterawsadm
mkdir -p out
clusterawsadm alpha bootstrap credentials generate-credentials bootstrapper.cluster-api-provider-aws.sigs.k8s.io > out/credentials.yaml

manifests: cmd/clusterctl/examples/aws/out/credentials
go run vendor/sigs.k8s.io/controller-tools/cmd/controller-gen/main.go crd
kustomize build config/default/ > cmd/clusterctl/examples/aws/out/provider-components.yaml
echo "---" >> cmd/clusterctl/examples/aws/out/provider-components.yaml
kustomize build vendor/sigs.k8s.io/cluster-api/config/default/ >> cmd/clusterctl/examples/aws/out/provider-components.yaml

# Create cluster.
create-cluster:
clusterctl create cluster -v3 --provider aws -m ./cmd/clusterctl/examples/aws/out/machines.yaml -c ./cmd/clusterctl/examples/aws/out/cluster.yaml -p ./cmd/clusterctl/examples/aws/out/provider-components.yaml
manifests: cmd/clusterctl/examples/aws/out/ out/credentials.yaml
kustomize build config/provider-components/ > cmd/clusterctl/examples/aws/out/provider-components-base.yaml
kustomize build cmd/clusterctl/examples/aws/default/ > cmd/clusterctl/examples/aws/out/provider-components.yaml

# Development.
dev-images:
MANAGER_IMAGE=$(DEV_MANAGER_IMAGE) $(MAKE) docker-build docker-push

Expand Down
2 changes: 1 addition & 1 deletion cmd/clusterawsadm/cmd/alpha/alpha.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ func AlphaCmd() *cobra.Command {
cmd.Help()
},
}
newCmd.AddCommand(bootstrap.RootCmd())
newCmd.AddCommand(bootstrap.Cmd())
return newCmd
}
268 changes: 9 additions & 259 deletions cmd/clusterawsadm/cmd/alpha/bootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,273 +14,23 @@
package bootstrap

import (
"bytes"
"encoding/base64"
"fmt"
"os"
"text/template"

"github.com/aws/aws-sdk-go/aws/session"
cfn "github.com/aws/aws-sdk-go/service/cloudformation"
awssts "github.com/aws/aws-sdk-go/service/sts"
"github.com/spf13/cobra"
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/aws/services/cloudformation"
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/aws/services/sts"
)

// KubernetesAWSSecret is the template to generate an encoded version of the
// users' AWS credentials
const KubernetesAWSSecret = `apiVersion: v1
kind: Secret
metadata:
name: credentials.cluster-api-provider-aws.sigs.k8s.io
type: Opaque
data:
credentials: {{ .CredentialsFile }}
`

// AWSCredentialsTemplate generates an AWS credentials file that can
// be loaded by the various SDKs.
const AWSCredentialsTemplate = `[default]
aws_access_key_id = {{ .AccessKeyID }}
aws_secret_access_key = {{ .SecretAccessKey }}
region = {{ .Region }}
{{if .SessionToken }}
aws_session_token = {{ .SessionToken }}
{{end}}
`
"sigs.k8s.io/cluster-api-provider-aws/cmd/clusterawsadm/cmd/alpha/bootstrap/cloudformation"
"sigs.k8s.io/cluster-api-provider-aws/cmd/clusterawsadm/cmd/alpha/bootstrap/credentials"
)

// RootCmd is the root of the `alpha bootstrap command`
func RootCmd() *cobra.Command {
// Cmd is the root of the `alpha bootstrap command`
func Cmd() *cobra.Command {
newCmd := &cobra.Command{
Use: "bootstrap",
Short: "bootstrap cloudformation",
Long: `Create and apply bootstrap AWS CloudFormation template to create IAM permissions for the Cluster API`,
Short: "bootstrap",
Long: `Bootstrapping commands`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
newCmd.AddCommand(generateCmd())
newCmd.AddCommand(createStackCmd())
newCmd.AddCommand(encodeAWSSecret())
newCmd.AddCommand(generateAWSDefaultProfile())
return newCmd
}

func generateCmd() *cobra.Command {
newCmd := &cobra.Command{
Use: "generate-cloudformation [AWS Account ID]",
Short: "Generate bootstrap AWS CloudFormation template",
Long: `Generate bootstrap AWS CloudFormation template with initial IAM policies.
You must enter an AWS account ID to generate the CloudFormation template.

Instructions for obtaining the AWS account ID can be found on https://docs.aws.amazon.com/IAM/latest/UserGuide/console_account-alias.html
`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
fmt.Printf("Error: requires AWS Account ID as an argument\n\n")
cmd.Help()
os.Exit(200)
}
if !sts.ValidateAccountID(args[0]) {
fmt.Printf("Error: provided AWS Account ID is invalid\n\n")
cmd.Help()
os.Exit(201)
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
template := cloudformation.BootstrapTemplate(args[0])
j, err := template.YAML()
if err != nil {
return err
}

fmt.Print(string(j))
return nil
},
}
return newCmd
}

func createStackCmd() *cobra.Command {
newCmd := &cobra.Command{
Use: "create-stack",
Short: "Create a new AWS CloudFormation stack using the bootstrap template",
Long: "Create a new AWS CloudFormation stack using the bootstrap template",
RunE: func(cmd *cobra.Command, args []string) error {
stackName := "cluster-api-provider-aws-sigs-k8s-io"
sess, err := session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
})
if err != nil {
return err
}

stsSvc := sts.NewService(awssts.New(sess))
accountID, stsErr := stsSvc.AccountID()
if stsErr != nil {
return stsErr
}

cfnSvc := cloudformation.NewService(cfn.New(sess))
err = cfnSvc.ReconcileBootstrapStack(stackName, accountID)
if err != nil {
return err
}

return cfnSvc.ShowStackResources(stackName)
},
}

return newCmd
}

func encodeAWSSecret() *cobra.Command {
newCmd := &cobra.Command{
Use: "encode-aws-credentials",
Short: "Encode AWS credentials as a base64 encoded Kubernetes secret",
Long: "Encode AWS credentials as a base64 encoded Kubernetes secret",
RunE: func(cmd *cobra.Command, args []string) error {
creds, err := getCredentialsFromEnvironment()

if err != nil {
return err
}

err = generateAWSKubernetesSecret(*creds)

if err != nil {
return err
}

return nil
},
}

return newCmd
}

func generateAWSDefaultProfile() *cobra.Command {
newCmd := &cobra.Command{
Use: "generate-aws-default-profile",
Short: "Generate an AWS profile from the current environment",
Long: "Generate an AWS profile from the current environment to be saved into minikube",
RunE: func(cmd *cobra.Command, args []string) error {

creds, err := getCredentialsFromEnvironment()

if err != nil {
return err
}

profile, err := renderAWSDefaultProfile(*creds)

if err != nil {
return err
}

fmt.Println(profile.String())

return nil
},
}

newCmd.AddCommand(cloudformation.Cmd())
newCmd.AddCommand(credentials.Cmd())
return newCmd
}

func getCredentialsFromEnvironment() (*awsCredential, error) {
creds := awsCredential{}

region, err := getEnv("AWS_REGION")
if err != nil {
return nil, err
}
creds.Region = region

accessKeyID, err := getEnv("AWS_ACCESS_KEY_ID")
if err != nil {
return nil, err
}
creds.AccessKeyID = accessKeyID

secretAccessKey, err := getEnv("AWS_SECRET_ACCESS_KEY")
if err != nil {
return nil, err
}
creds.SecretAccessKey = secretAccessKey

sessionToken, err := getEnv("AWS_SESSION_TOKEN")
if err != nil {
creds.SessionToken = ""
} else {
creds.SessionToken = sessionToken
}

return &creds, nil
}

type awsCredential struct {
AccessKeyID string
SecretAccessKey string
SessionToken string
Region string
}

type awsCredentialsFile struct {
CredentialsFile string
}

func getEnv(key string) (string, error) {
val, ok := os.LookupEnv(key)
if !ok {
return "", fmt.Errorf("Environment variable %q not found", key)
}
return val, nil
}

func renderAWSDefaultProfile(creds awsCredential) (*bytes.Buffer, error) {
tmpl, err := template.New("AWS Credentials").Parse(AWSCredentialsTemplate)
if err != nil {
return nil, err
}

var credsFileStr bytes.Buffer
err = tmpl.Execute(&credsFileStr, creds)
if err != nil {
return nil, err
}

return &credsFileStr, nil
}

func generateAWSKubernetesSecret(creds awsCredential) error {

profile, err := renderAWSDefaultProfile(creds)

if err != nil {
return err
}

encCreds := base64.StdEncoding.EncodeToString(profile.Bytes())

credsFile := awsCredentialsFile{
CredentialsFile: string(encCreds),
}

secretTmpl, err := template.New("AWS Credentials Secret").Parse(KubernetesAWSSecret)
if err != nil {
return err
}
var out bytes.Buffer

err = secretTmpl.Execute(&out, credsFile)

if err != nil {
return err
}

fmt.Println(out.String())

return nil
}
Loading