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  }