cmd/seeds/foundation/foundation.go (133 lines of code) (raw):
/*
Copyright © 2024 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package foundation
import (
"fmt"
"github.com/GoogleCloudPlatform/pastures-poc-toolkit/internal/fabric"
"github.com/GoogleCloudPlatform/pastures-poc-toolkit/internal/google"
"github.com/GoogleCloudPlatform/pastures-poc-toolkit/internal/utils"
"github.com/spf13/cobra"
)
var (
dryRun bool
verbose bool
)
// Set up pointers to support multiple distinct parents
var (
FoundationCreate = *FoundationCmd
FoundationDestroy = *FoundationCmd //TODO no destroy equivalent for foundation
)
// FoundationCmd represents the foundation command
var FoundationCmd = &cobra.Command{
Use: "foundation",
Short: "Deploy a foundation-only pasture with no blueprints",
Long: "Creates a foundation landing zone from the FAST framework.\n" +
"Projects can optionally be deployed as features into the landing zone. " +
"An example of how to use this pasture:\n\n\t" +
"pasture create foundation",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
// Construct path for the config
p, err := utils.ConfigPath()
if err != nil {
fmt.Println("Unable to set configuration path")
cobra.CheckErr(err)
}
// Check if Google ADC is valid
if _, err := google.AppDefaultCredentials(); err != nil {
cobra.CheckErr(err)
}
// Get persistent flags from parent
dryRun, _ = cmd.Flags().GetBool("dry-run")
verbose, _ = cmd.Flags().GetBool("verbose")
// Hydrate configuration
varFile := fabric.LoadVarsFile(p, "")
varData := fabric.NewFastConfig()
if err := varData.ReadConfig(varFile.LocalPath); err != nil {
fmt.Println(
"Unable to read var file.",
"Try running pasture configure --rehydrate",
)
cobra.CheckErr(err)
}
varFile.AddConfig(varData)
varFile.SetBucket(
varData.Prefix,
) // TODO: this can be optimized by splitting deps and stage vars
// Load foundation stages
stages := fabric.InitializeFoundationStages(p, varData.Prefix, varFile)
// Do things with the stages
for _, s := range stages {
var firstRun bool = false
// destroy not supported for foundation stage
if cmd.Parent().Name() == "destroy" && s.Type == "foundation" {
fmt.Println("Skipping foundation stage:", s.Name)
continue
}
// dry run bootstrap stage
if dryRun && s.Name == "0-bootstrap" {
fmt.Println(
"Testing if foundation can be applied to GCP organization",
)
if err := s.Init(verbose); err != nil {
fmt.Println("Cannot initialize stage for dry run")
cobra.CheckErr(err)
}
if err := s.Plan(verbose); err != nil {
fmt.Println(
"Foundation cannot be applied to GCP organization",
)
cobra.CheckErr(err)
}
fmt.Println("Foundation can be applied to GCP organization")
break // Don't do anything else
}
// do what we came here to do
if cmd.Parent().Name() == "destroy" {
fmt.Println("Destroying stage:", s.Name)
} else {
fmt.Println("Deploying stage:", s.Name)
}
// try fetching dependency files
if err := s.DiscoverFiles(); err != nil {
fmt.Println(
"Pastures first run detected - running with local state",
)
firstRun = true
}
// check if state needs to be migrated
fmt.Println("Initializing", s.Name)
if err := s.Init(verbose); err != nil {
fmt.Println("Failed to migrate state to remote backend")
cobra.CheckErr(err)
}
fmt.Println("Configuration complete")
if cmd.Parent().Name() == "destroy" {
// destroy the stage
fmt.Println("Starting destroy:", s.Name)
if err := s.Destroy(nil, verbose); err != nil {
fmt.Println("Stage failed to destroy:", s.Name)
cobra.CheckErr(err)
}
fmt.Println("Successfully destroyed stage:", s.Name)
} else {
// apply stage
fmt.Println("Starting apply:", s.Name)
if err := s.Apply(nil, verbose); err != nil {
fmt.Println("Stage failed to deploy:", s.Name)
cobra.CheckErr(err)
}
fmt.Println("Successfully applied stage:", s.Name)
// move pasture vars to bucket
if s.Name == "0-bootstrap" {
fmt.Println("Uploading pasture vars to GCS bucket")
if err := varFile.UploadFile(); err != nil {
fmt.Println("Failed to upload pasture var file")
cobra.CheckErr(err)
}
}
// first run was detected - move things to cloud
if firstRun {
// try fetching dependency files
if err := s.DiscoverFiles(); err != nil {
fmt.Println(
"Unable to retrieve stage dependencies for:",
s.Name,
)
cobra.CheckErr(err)
}
// migrate the state
if err := s.Init(verbose); err != nil {
fmt.Println("Failed to migrate state to remote backend")
cobra.CheckErr(err)
}
}
}
fmt.Println("Stage complete:", s.Name)
}
fmt.Println(
"Navigate to the Google Cloud Console to deploy your first workload:",
"https://console.cloud.google.com/welcome",
)
},
}
func init() {}