github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/initializer/init.go (about) 1 /* 2 Copyright 2019 The Skaffold Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package initializer 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "io" 24 "io/ioutil" 25 26 "github.com/GoogleContainerTools/skaffold/cmd/skaffold/app/tips" 27 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/analyze" 28 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/build" 29 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/config" 30 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/deploy" 31 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/prompt" 32 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" 33 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/yaml" 34 ) 35 36 // DoInit executes the `skaffold init` flow. 37 func DoInit(ctx context.Context, out io.Writer, c config.Config) error { 38 if c.ComposeFile != "" { 39 if err := runKompose(ctx, c.ComposeFile); err != nil { 40 return err 41 } 42 } 43 44 a, err := AnalyzeProject(c) 45 if err != nil { 46 return err 47 } 48 49 newConfig, newManifests, err := Initialize(out, c, a) 50 // If the --analyze flag is used, we return early with the result of PrintAnalysis() 51 // TODO(marlongamez): Figure out a cleaner way to do this. Might have to change return values to include the different Initializers. 52 if err != nil || c.Analyze { 53 return err 54 } 55 56 return WriteData(out, c, newConfig, newManifests) 57 } 58 59 // AnalyzeProject scans the project directory for files and keeps track of what types of files it finds (builders, k8s manifests, etc.). 60 func AnalyzeProject(c config.Config) (*analyze.ProjectAnalysis, error) { 61 a := analyze.NewAnalyzer(c) 62 if err := a.Analyze("."); err != nil { 63 return nil, err 64 } 65 66 // helm projects can't currently be bootstrapped automatically by skaffold, so we fail fast and link to our docs instead. 67 if len(a.ChartPaths()) > 0 { 68 //nolint 69 return nil, errors.New(`Projects set up to deploy with helm must be manually configured. 70 71 See https://skaffold.dev/docs/pipeline-stages/deployers/helm/ for a detailed guide on setting your project up with skaffold.`) 72 } 73 74 return a, nil 75 } 76 77 // Initialize uses the information gathered by the analyzer to create a skaffold config and generate kubernetes manifests. 78 // The returned map[string][]byte represents a mapping from generated config name to its respective manifest data held in a []byte 79 func Initialize(out io.Writer, c config.Config, a *analyze.ProjectAnalysis) (*latest.SkaffoldConfig, map[string][]byte, error) { 80 deployInitializer := deploy.NewInitializer(a.Manifests(), a.KustomizeBases(), a.KustomizePaths(), c) 81 images := deployInitializer.GetImages() 82 83 buildInitializer := build.NewInitializer(a.Builders(), c) 84 if err := buildInitializer.ProcessImages(images); err != nil { 85 return nil, nil, err 86 } 87 88 if c.Analyze { 89 return nil, nil, buildInitializer.PrintAnalysis(out) 90 } 91 92 newManifests, err := generateManifests(out, c, buildInitializer, deployInitializer) 93 if err != nil { 94 return nil, nil, err 95 } 96 97 if err := deployInitializer.Validate(); err != nil { 98 return nil, nil, err 99 } 100 101 return generateSkaffoldConfig(buildInitializer, deployInitializer), newManifests, nil 102 } 103 104 func generateManifests(out io.Writer, c config.Config, bInitializer build.Initializer, dInitializer deploy.Initializer) (map[string][]byte, error) { 105 var generatedManifests map[string][]byte 106 107 generatedManifestPairs, err := bInitializer.GenerateManifests(out, c.Force, c.EnableManifestGeneration) 108 if err != nil { 109 return nil, err 110 } 111 generatedManifests = make(map[string][]byte, len(generatedManifestPairs)) 112 for pair, manifest := range generatedManifestPairs { 113 dInitializer.AddManifestForImage(pair.ManifestPath, pair.ImageName) 114 generatedManifests[pair.ManifestPath] = manifest 115 } 116 117 return generatedManifests, nil 118 } 119 120 // WriteData takes the given skaffold config and k8s manifests and writes them out to a file or the given io.Writer 121 func WriteData(out io.Writer, c config.Config, newConfig *latest.SkaffoldConfig, newManifests map[string][]byte) error { 122 pipeline, err := yaml.Marshal(newConfig) 123 if err != nil { 124 return err 125 } 126 127 if c.Opts.ConfigurationFile == "-" { 128 out.Write(pipeline) 129 return nil 130 } 131 132 if !c.Force { 133 if done, err := prompt.WriteSkaffoldConfig(out, pipeline, newManifests, c.Opts.ConfigurationFile); done { 134 return err 135 } 136 } 137 138 for path, manifest := range newManifests { 139 if err = ioutil.WriteFile(path, manifest, 0644); err != nil { 140 return fmt.Errorf("writing k8s manifest to file: %w", err) 141 } 142 fmt.Fprintf(out, "Generated manifest %s was written\n", path) 143 } 144 145 if err = ioutil.WriteFile(c.Opts.ConfigurationFile, pipeline, 0644); err != nil { 146 return fmt.Errorf("writing config to file: %w", err) 147 } 148 149 fmt.Fprintf(out, "Configuration %s was written\n", c.Opts.ConfigurationFile) 150 tips.PrintForInit(out, c.Opts) 151 152 return nil 153 }