generatebundlefile/main.go (191 lines of code) (raw):

package main import ( "context" "fmt" "io" "os" "path/filepath" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/ecr" "github.com/aws/aws-sdk-go-v2/service/sts" ctrl "sigs.k8s.io/controller-runtime" api "github.com/aws/eks-anywhere-packages/api/v1alpha1" sig "github.com/aws/eks-anywhere-packages/pkg/signature" ) const ( defaultRegion = "us-west-2" ) var BundleLog = ctrl.Log.WithName("BundleGenerator") func main() { opts := NewOptions() opts.SetupLogger() if opts.generateSample { outputFilename := filepath.Join(opts.outputFolder, "bundle.yaml") f, err := os.OpenFile(outputFilename, os.O_WRONLY|os.O_CREATE, 0o644) if err != nil { BundleLog.Error(err, fmt.Sprintf("opening output file %q", outputFilename)) os.Exit(1) } defer f.Close() err = cmdGenerateSample(f) if err != nil { BundleLog.Error(err, "generating sample bundle") os.Exit(1) } fmt.Printf("sample bundle file written to %q\n", outputFilename) return } err := cmdGenerate(opts) if err != nil { BundleLog.Error(err, "generating bundle") os.Exit(1) } } // cmdGenerateSample writes a sample bundle file to the given output folder. func cmdGenerateSample(w io.Writer) error { sample := NewBundleGenerate("generatesample") _, yml, err := sig.GetDigest(sample, sig.EksaDomain) if err != nil { return fmt.Errorf("generating bundle digest: %w", err) } _, err = w.Write(yml) if err != nil { return fmt.Errorf("writing sample bundle data: %w", err) } return nil } func cmdGenerate(opts *Options) error { // grab local path to caller, and make new caller pwd, err := os.Getwd() if err != nil { BundleLog.Error(err, "Unable to get current working directory") os.Exit(1) } // validate that an input flag is either given, or the system can find yaml files to use. files, err := opts.ValidateInput() if err != nil { return err } // Validate Input config, and turn into Input struct BundleLog.Info("Using input file to create bundle crds.", "Input file", opts.inputFile) conf, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(defaultRegion)) if err != nil { BundleLog.Error(err, "loading default AWS config: %w", err) os.Exit(1) } clients := &SDKClients{} ecrClient := ecr.NewFromConfig(conf) clients.ecrClient, err = NewECRClient(ecrClient, true) if err != nil { BundleLog.Error(err, "creating ECR client") os.Exit(1) } stsClient := sts.NewFromConfig(conf) clients.stsClient, err = NewStsClient(stsClient, true) if err != nil { BundleLog.Error(err, "creating STS client") os.Exit(1) } for _, f := range files { Inputs, err := ValidateInputConfig(f) if err != nil { BundleLog.Error(err, "Unable to validate input file") os.Exit(1) } // Create Authfile for Helm Driver dockerReleaseStruct := &DockerAuth{ Auths: map[string]DockerAuthRegistry{ fmt.Sprintf("%s.dkr.ecr.%s.amazonaws.com", clients.stsClient.AccountID, defaultRegion): { clients.ecrClient.AuthConfig, }, }, } dockerAuth, err := NewAuthFile(dockerReleaseStruct) if err != nil || dockerAuth.Authfile == "" { BundleLog.Error(err, "Unable create AuthFile") os.Exit(1) } driver, err := NewHelm(BundleLog, dockerAuth.Authfile) if err != nil { BundleLog.Error(err, "Unable to create Helm driver") os.Exit(1) } BundleLog.Info("In Progress: Populating Bundles and looking up Sha256 tags") addOnBundleSpec, name, err := clients.NewBundleFromInput(Inputs) if err != nil { BundleLog.Error(err, "Unable to create bundle from input file") os.Exit(1) } // Pull Helm charts for all the populated helm fields of the bundles. for i, charts := range addOnBundleSpec.Packages { fullURI := fmt.Sprintf("%s/%s", charts.Source.Registry, charts.Source.Repository) chartPath, err := driver.PullHelmChart(fullURI, charts.Source.Versions[0].Name) if err != nil { BundleLog.Error(err, "Unable to pull Helm Chart") os.Exit(1) } chartName, helmname, err := splitECRName(fullURI) if err != nil { BundleLog.Error(err, "Unable to split helm name, invalid format") os.Exit(1) } dest := filepath.Join(pwd, chartName) err = UnTarHelmChart(chartPath, chartName, dest) if err != nil { BundleLog.Error(err, "Unable to untar Helm Chart") os.Exit(1) } // Check for requires.yaml in the unpacked helm chart helmDest := filepath.Join(pwd, chartName, helmname) defer os.RemoveAll(helmDest) f, err := hasRequires(helmDest) if err != nil { BundleLog.Error(err, "Helm chart doesn't have requires.yaml inside") os.Exit(1) } // Unpack requires.yaml into a GO struct helmRequires, err := validateHelmRequires(f) if err != nil { BundleLog.Error(err, "Unable to parse requires.yaml file to Go Struct") os.Exit(1) } // Populate Images to bundle spec from Requires.yaml helmImage := []api.VersionImages{} for _, image := range helmRequires.Spec.Images { helmImage = append(helmImage, api.VersionImages{ Repository: image.Repository, Digest: image.Digest, }) } charts.Source.Versions[0].Images = helmImage // Populate Configurations to bundle spec from Requires.yaml if len(deleteEmptyStringSlice(helmRequires.Spec.Dependencies)) > 0 { charts.Source.Versions[0].Dependencies = helmRequires.Spec.Dependencies } charts.Source.Versions[0].Schema = helmRequires.Spec.Schema // Set the registry to empty string since we pull it from the PackageBundleController instead now. addOnBundleSpec.Packages[i].Source.Registry = "" } err = dockerAuth.Remove() if err != nil { BundleLog.Error(err, "unable to remove docker auth file") os.Exit(1) } bundle := AddMetadata(addOnBundleSpec, name) bundle.Annotations[FullExcludesAnnotation] = Excludes BundleLog.Info("Generating bundle signature", "key", opts.key) signature, err := GetBundleSignature(context.Background(), bundle, opts.key) if err != nil { BundleLog.Error(err, "Unable to sign bundle with kms key") os.Exit(1) } bundle.Annotations[FullSignatureAnnotation] = signature yml, err := serializeBundle(bundle) if err != nil { BundleLog.Error(err, "marshaling bundle YAML: %w", err) os.Exit(1) } BundleLog.Info("In Progress: Writing bundle to output") outputDir := filepath.Join(pwd, opts.outputFolder) outputPath, err := NewWriter(outputDir) if err != nil { BundleLog.Error(err, "Unable to create new Writer") os.Exit(1) } if _, err := outputPath.Write("bundle.yaml", yml, PersistentFile); err != nil { BundleLog.Error(err, "Unable to write Bundle to yaml") os.Exit(1) } BundleLog.Info("Finished writing output crd files.", "Output path", fmt.Sprintf("%s%s", opts.outputFolder, "/")) } return nil }