diff --git a/pkg/skaffold/runner/build_deploy.go b/pkg/skaffold/runner/build_deploy.go index e05ca3300d7..8bf5974f4b6 100644 --- a/pkg/skaffold/runner/build_deploy.go +++ b/pkg/skaffold/runner/build_deploy.go @@ -18,11 +18,13 @@ package runner import ( "context" + "fmt" "io" "time" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/tag" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/color" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" "github.com/pkg/errors" ) @@ -41,13 +43,13 @@ func (r *SkaffoldRunner) BuildAndTest(ctx context.Context, out io.Writer, artifa r.hasBuilt = true - bRes, err := r.Builder.Build(ctx, out, tags, artifacts) + bRes, err := r.builder.Build(ctx, out, tags, artifacts) if err != nil { return nil, errors.Wrap(err, "build failed") } if !r.runCtx.Opts.SkipTests { - if err = r.Tester.Test(ctx, out, bRes); err != nil { + if err = r.tester.Test(ctx, out, bRes); err != nil { return nil, errors.Wrap(err, "test failed") } } @@ -98,3 +100,52 @@ func (r *SkaffoldRunner) DeployAndLog(ctx context.Context, out io.Writer, artifa return nil } + +type tagErr struct { + tag string + err error +} + +// imageTags generates tags for a list of artifacts +func (r *SkaffoldRunner) imageTags(ctx context.Context, out io.Writer, artifacts []*latest.Artifact) (tag.ImageTags, error) { + start := time.Now() + color.Default.Fprintln(out, "Generating tags...") + + tagErrs := make([]chan tagErr, len(artifacts)) + + for i := range artifacts { + tagErrs[i] = make(chan tagErr, 1) + + i := i + go func() { + tag, err := r.tagger.GenerateFullyQualifiedImageName(artifacts[i].Workspace, artifacts[i].ImageName) + tagErrs[i] <- tagErr{tag: tag, err: err} + }() + } + + imageTags := make(tag.ImageTags, len(artifacts)) + + for i, artifact := range artifacts { + imageName := artifact.ImageName + color.Default.Fprintf(out, " - %s -> ", imageName) + + select { + case <-ctx.Done(): + return nil, context.Canceled + + case t := <-tagErrs[i]: + tag := t.tag + err := t.err + if err != nil { + return nil, errors.Wrapf(err, "generating tag for %s", imageName) + } + + fmt.Fprintln(out, tag) + + imageTags[imageName] = tag + } + } + + color.Default.Fprintln(out, "Tags generated in", time.Since(start)) + return imageTags, nil +} diff --git a/pkg/skaffold/runner/cleanup.go b/pkg/skaffold/runner/cleanup.go new file mode 100644 index 00000000000..a14d2b23794 --- /dev/null +++ b/pkg/skaffold/runner/cleanup.go @@ -0,0 +1,26 @@ +/* +Copyright 2019 The Skaffold Authors + +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 runner + +import ( + "context" + "io" +) + +func (r *SkaffoldRunner) Cleanup(ctx context.Context, out io.Writer) error { + return r.deployer.Cleanup(ctx, out) +} diff --git a/pkg/skaffold/runner/deploy.go b/pkg/skaffold/runner/deploy.go new file mode 100644 index 00000000000..16df9d87710 --- /dev/null +++ b/pkg/skaffold/runner/deploy.go @@ -0,0 +1,56 @@ +/* +Copyright 2019 The Skaffold Authors + +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 runner + +import ( + "context" + "fmt" + "io" + + cfg "github.com/GoogleContainerTools/skaffold/cmd/skaffold/app/cmd/config" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build" + "github.com/pkg/errors" +) + +func (r *SkaffoldRunner) Deploy(ctx context.Context, out io.Writer, artifacts []build.Artifact) error { + if cfg.IsKindCluster(r.runCtx.KubeContext) { + // With `kind`, docker images have to be loaded with the `kind` CLI. + if err := r.loadImagesInKindNodes(ctx, out, artifacts); err != nil { + return errors.Wrapf(err, "loading images into kind nodes") + } + } + + err := r.deployer.Deploy(ctx, out, artifacts, r.labellers) + r.hasDeployed = true + if err != nil { + return err + } + return r.performStatusCheck(ctx, out) +} + +func (r *SkaffoldRunner) performStatusCheck(ctx context.Context, out io.Writer) error { + // Check if we need to perform deploy status + if r.runCtx.Opts.StatusCheck { + fmt.Fprintln(out, "Waiting for deployments to stabilize") + err := statusCheck(ctx, r.defaultLabeller, r.runCtx) + if err != nil { + fmt.Fprintln(out, err.Error()) + } + return err + } + return nil +} diff --git a/pkg/skaffold/runner/dev.go b/pkg/skaffold/runner/dev.go index e55af580ae9..a334f30033c 100644 --- a/pkg/skaffold/runner/dev.go +++ b/pkg/skaffold/runner/dev.go @@ -58,7 +58,7 @@ func (r *SkaffoldRunner) doDev(ctx context.Context, out io.Writer) error { for _, s := range r.changeSet.needsResync { color.Default.Fprintf(out, "Syncing %d files for %s\n", len(s.Copy)+len(s.Delete), s.Image) - if err := r.Syncer.Sync(ctx, s); err != nil { + if err := r.syncer.Sync(ctx, s); err != nil { r.changeSet.reset() logrus.Warnln("Skipping deploy due to sync error:", err) return nil @@ -117,9 +117,9 @@ func (r *SkaffoldRunner) Dev(ctx context.Context, out io.Writer, artifacts []*la } if err := r.monitor.Register( - func() ([]string, error) { return r.Builder.DependenciesForArtifact(ctx, artifact) }, + func() ([]string, error) { return r.builder.DependenciesForArtifact(ctx, artifact) }, func(e filemon.Events) { - syncMap := func() (map[string][]string, error) { return r.SyncMap(ctx, artifact) } + syncMap := func() (map[string][]string, error) { return r.builder.SyncMap(ctx, artifact) } s, err := sync.NewItem(artifact, e, r.builds, r.runCtx.InsecureRegistries, syncMap) switch { case err != nil: @@ -137,7 +137,7 @@ func (r *SkaffoldRunner) Dev(ctx context.Context, out io.Writer, artifacts []*la // Watch test configuration if err := r.monitor.Register( - r.Tester.TestDependencies, + r.tester.TestDependencies, func(filemon.Events) { r.changeSet.needsRedeploy = true }, ); err != nil { return errors.Wrap(err, "watching test files") @@ -145,7 +145,7 @@ func (r *SkaffoldRunner) Dev(ctx context.Context, out io.Writer, artifacts []*la // Watch deployment configuration if err := r.monitor.Register( - r.Deployer.Dependencies, + r.deployer.Dependencies, func(filemon.Events) { r.changeSet.needsRedeploy = true }, ); err != nil { return errors.Wrap(err, "watching files for deployer") diff --git a/pkg/skaffold/runner/diagnose.go b/pkg/skaffold/runner/diagnose.go index 6ce35163098..482654bdcba 100644 --- a/pkg/skaffold/runner/diagnose.go +++ b/pkg/skaffold/runner/diagnose.go @@ -47,11 +47,11 @@ func (r *SkaffoldRunner) DiagnoseArtifacts(out io.Writer) error { fmt.Fprintf(out, " - Size of the context: %vbytes\n", size) } - timeDeps1, deps, err := timeToListDependencies(ctx, r.Builder, artifact) + timeDeps1, deps, err := timeToListDependencies(ctx, r.builder, artifact) if err != nil { return errors.Wrap(err, "listing artifact dependencies") } - timeDeps2, _, err := timeToListDependencies(ctx, r.Builder, artifact) + timeDeps2, _, err := timeToListDependencies(ctx, r.builder, artifact) if err != nil { return errors.Wrap(err, "listing artifact dependencies") } @@ -59,13 +59,13 @@ func (r *SkaffoldRunner) DiagnoseArtifacts(out io.Writer) error { fmt.Fprintln(out, " - Dependencies:", len(deps), "files") fmt.Fprintf(out, " - Time to list dependencies: %v (2nd time: %v)\n", timeDeps1, timeDeps2) - timeSyncMap1, err := timeToConstructSyncMap(ctx, r.Builder, artifact) + timeSyncMap1, err := timeToConstructSyncMap(ctx, r.builder, artifact) if err != nil { if _, isNotSupported := err.(build.ErrSyncMapNotSupported); !isNotSupported { return errors.Wrap(err, "construct artifact dependencies") } } - timeSyncMap2, err := timeToConstructSyncMap(ctx, r.Builder, artifact) + timeSyncMap2, err := timeToConstructSyncMap(ctx, r.builder, artifact) if err != nil { if _, isNotSupported := err.(build.ErrSyncMapNotSupported); !isNotSupported { return errors.Wrap(err, "construct artifact dependencies") diff --git a/pkg/skaffold/runner/new.go b/pkg/skaffold/runner/new.go new file mode 100644 index 00000000000..7d1633bdf93 --- /dev/null +++ b/pkg/skaffold/runner/new.go @@ -0,0 +1,242 @@ +/* +Copyright 2019 The Skaffold Authors + +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 runner + +import ( + "fmt" + + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/cache" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/cluster" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/gcb" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/local" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/tag" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/deploy" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/event" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/filemon" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/server" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/sync" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/test" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/trigger" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// NewForConfig returns a new SkaffoldRunner for a SkaffoldConfig +func NewForConfig(runCtx *runcontext.RunContext) (*SkaffoldRunner, error) { + tagger, err := getTagger(runCtx) + if err != nil { + return nil, errors.Wrap(err, "parsing tag config") + } + + builder, err := getBuilder(runCtx) + if err != nil { + return nil, errors.Wrap(err, "parsing build config") + } + + imagesAreLocal := false + if localBuilder, ok := builder.(*local.Builder); ok { + imagesAreLocal = !localBuilder.PushImages() + } + + artifactCache, err := cache.NewCache(runCtx, imagesAreLocal, builder) + if err != nil { + return nil, errors.Wrap(err, "initializing cache") + } + + tester := getTester(runCtx) + syncer := getSyncer(runCtx) + + deployer, err := getDeployer(runCtx) + if err != nil { + return nil, errors.Wrap(err, "parsing deploy config") + } + + defaultLabeller := deploy.NewLabeller("") + labellers := []deploy.Labeller{&runCtx.Opts, builder, deployer, tagger, defaultLabeller} + + builder, tester, deployer = WithTimings(builder, tester, deployer, runCtx.Opts.CacheArtifacts) + if runCtx.Opts.Notification { + deployer = WithNotification(deployer) + } + + trigger, err := trigger.NewTrigger(runCtx) + if err != nil { + return nil, errors.Wrap(err, "creating watch trigger") + } + + event.InitializeState(runCtx.Cfg.Build) + + monitor := filemon.NewMonitor() + + intentChan := make(chan bool, 1) + + r := &SkaffoldRunner{ + builder: builder, + tester: tester, + deployer: deployer, + tagger: tagger, + syncer: syncer, + monitor: monitor, + listener: &SkaffoldListener{ + Monitor: monitor, + Trigger: trigger, + intentChan: intentChan, + }, + changeSet: &changeSet{ + rebuildTracker: make(map[string]*latest.Artifact), + resyncTracker: make(map[string]*sync.Item), + }, + labellers: labellers, + defaultLabeller: defaultLabeller, + portForwardResources: runCtx.Cfg.PortForward, + imageList: kubernetes.NewImageList(), + cache: artifactCache, + runCtx: runCtx, + intents: newIntents(runCtx.Opts.AutoBuild, runCtx.Opts.AutoSync, runCtx.Opts.AutoDeploy), + } + + if err := r.setupTriggerCallbacks(intentChan); err != nil { + return nil, errors.Wrapf(err, "setting up trigger callbacks") + } + + return r, nil +} + +func (r *SkaffoldRunner) setupTriggerCallbacks(c chan bool) error { + if err := r.setupTriggerCallback("build", c); err != nil { + return err + } + if err := r.setupTriggerCallback("sync", c); err != nil { + return err + } + if err := r.setupTriggerCallback("deploy", c); err != nil { + return err + } + return nil +} + +func (r *SkaffoldRunner) setupTriggerCallback(triggerName string, c chan<- bool) error { + var ( + setIntent func(bool) + trigger bool + serverCallback func(func()) + ) + + switch triggerName { + case "build": + setIntent = r.intents.setBuild + trigger = r.runCtx.Opts.AutoBuild + serverCallback = server.SetBuildCallback + case "sync": + setIntent = r.intents.setSync + trigger = r.runCtx.Opts.AutoSync + serverCallback = server.SetSyncCallback + case "deploy": + setIntent = r.intents.setDeploy + trigger = r.runCtx.Opts.AutoDeploy + serverCallback = server.SetDeployCallback + default: + return fmt.Errorf("unsupported trigger type when setting callbacks: %s", triggerName) + } + + setIntent(true) + + // if "auto" is set to false, we're in manual mode + if !trigger { + setIntent(false) // set the initial value of the intent to false + // give the server a callback to set the intent value when a user request is received + serverCallback(func() { + logrus.Debugf("%s intent received, calling back to runner", triggerName) + c <- true + setIntent(true) + }) + } + return nil +} + +func getBuilder(runCtx *runcontext.RunContext) (build.Builder, error) { + switch { + case runCtx.Cfg.Build.LocalBuild != nil: + logrus.Debugln("Using builder: local") + return local.NewBuilder(runCtx) + + case runCtx.Cfg.Build.GoogleCloudBuild != nil: + logrus.Debugln("Using builder: google cloud") + return gcb.NewBuilder(runCtx), nil + + case runCtx.Cfg.Build.Cluster != nil: + logrus.Debugln("Using builder: cluster") + return cluster.NewBuilder(runCtx) + + default: + return nil, fmt.Errorf("unknown builder for config %+v", runCtx.Cfg.Build) + } +} + +func getTester(runCtx *runcontext.RunContext) test.Tester { + return test.NewTester(runCtx) +} + +func getSyncer(runCtx *runcontext.RunContext) sync.Syncer { + return sync.NewSyncer(runCtx) +} + +func getDeployer(runCtx *runcontext.RunContext) (deploy.Deployer, error) { + switch { + case runCtx.Cfg.Deploy.HelmDeploy != nil: + return deploy.NewHelmDeployer(runCtx), nil + + case runCtx.Cfg.Deploy.KubectlDeploy != nil: + return deploy.NewKubectlDeployer(runCtx), nil + + case runCtx.Cfg.Deploy.KustomizeDeploy != nil: + return deploy.NewKustomizeDeployer(runCtx), nil + + default: + return nil, fmt.Errorf("unknown deployer for config %+v", runCtx.Cfg.Deploy) + } +} + +func getTagger(runCtx *runcontext.RunContext) (tag.Tagger, error) { + t := runCtx.Cfg.Build.TagPolicy + + switch { + case runCtx.Opts.CustomTag != "": + return &tag.CustomTag{ + Tag: runCtx.Opts.CustomTag, + }, nil + + case t.EnvTemplateTagger != nil: + return tag.NewEnvTemplateTagger(t.EnvTemplateTagger.Template) + + case t.ShaTagger != nil: + return &tag.ChecksumTagger{}, nil + + case t.GitTagger != nil: + return tag.NewGitCommit(t.GitTagger.Variant) + + case t.DateTimeTagger != nil: + return tag.NewDateTimeTagger(t.DateTimeTagger.Format, t.DateTimeTagger.TimeZone), nil + + default: + return nil, fmt.Errorf("unknown tagger for strategy %+v", t) + } +} diff --git a/pkg/skaffold/runner/prune.go b/pkg/skaffold/runner/prune.go new file mode 100644 index 00000000000..eae749fb52a --- /dev/null +++ b/pkg/skaffold/runner/prune.go @@ -0,0 +1,26 @@ +/* +Copyright 2019 The Skaffold Authors + +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 runner + +import ( + "context" + "io" +) + +func (r *SkaffoldRunner) Prune(ctx context.Context, out io.Writer) error { + return r.builder.Prune(ctx, out) +} diff --git a/pkg/skaffold/runner/runner.go b/pkg/skaffold/runner/runner.go index 93c024b2aa6..bf0e5fd4aeb 100644 --- a/pkg/skaffold/runner/runner.go +++ b/pkg/skaffold/runner/runner.go @@ -18,31 +18,19 @@ package runner import ( "context" - "fmt" "io" - "time" - cfg "github.com/GoogleContainerTools/skaffold/cmd/skaffold/app/cmd/config" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/cache" - "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/cluster" - "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/gcb" - "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/local" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/tag" - "github.com/GoogleContainerTools/skaffold/pkg/skaffold/color" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/deploy" - "github.com/GoogleContainerTools/skaffold/pkg/skaffold/event" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/filemon" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/portforward" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" - "github.com/GoogleContainerTools/skaffold/pkg/skaffold/server" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/sync" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/test" - "github.com/GoogleContainerTools/skaffold/pkg/skaffold/trigger" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" ) // Runner is responsible for running the skaffold build, test and deploy config. @@ -59,12 +47,11 @@ type Runner interface { // SkaffoldRunner is responsible for running the skaffold build, test and deploy config. type SkaffoldRunner struct { - // TODO(nkubala): make embedded fields private - build.Builder - deploy.Deployer - test.Tester - tag.Tagger - sync.Syncer + builder build.Builder + deployer deploy.Deployer + tester test.Tester + tagger tag.Tagger + syncer sync.Syncer monitor filemon.Monitor listener Listener forwarderManager *portforward.ForwarderManager @@ -90,237 +77,6 @@ var ( statusCheck = deploy.StatusCheck ) -// NewForConfig returns a new SkaffoldRunner for a SkaffoldConfig -func NewForConfig(runCtx *runcontext.RunContext) (*SkaffoldRunner, error) { - tagger, err := getTagger(runCtx) - if err != nil { - return nil, errors.Wrap(err, "parsing tag config") - } - - builder, err := getBuilder(runCtx) - if err != nil { - return nil, errors.Wrap(err, "parsing build config") - } - - imagesAreLocal := false - if localBuilder, ok := builder.(*local.Builder); ok { - imagesAreLocal = !localBuilder.PushImages() - } - - artifactCache, err := cache.NewCache(runCtx, imagesAreLocal, builder) - if err != nil { - return nil, errors.Wrap(err, "initializing cache") - } - - tester := getTester(runCtx) - syncer := getSyncer(runCtx) - - deployer, err := getDeployer(runCtx) - if err != nil { - return nil, errors.Wrap(err, "parsing deploy config") - } - - defaultLabeller := deploy.NewLabeller("") - labellers := []deploy.Labeller{&runCtx.Opts, builder, deployer, tagger, defaultLabeller} - - builder, tester, deployer = WithTimings(builder, tester, deployer, runCtx.Opts.CacheArtifacts) - if runCtx.Opts.Notification { - deployer = WithNotification(deployer) - } - - trigger, err := trigger.NewTrigger(runCtx) - if err != nil { - return nil, errors.Wrap(err, "creating watch trigger") - } - - event.InitializeState(runCtx.Cfg.Build) - - monitor := filemon.NewMonitor() - - intentChan := make(chan bool, 1) - - r := &SkaffoldRunner{ - Builder: builder, - Tester: tester, - Deployer: deployer, - Tagger: tagger, - Syncer: syncer, - monitor: monitor, - listener: &SkaffoldListener{ - Monitor: monitor, - Trigger: trigger, - intentChan: intentChan, - }, - changeSet: &changeSet{ - rebuildTracker: make(map[string]*latest.Artifact), - resyncTracker: make(map[string]*sync.Item), - }, - labellers: labellers, - defaultLabeller: defaultLabeller, - portForwardResources: runCtx.Cfg.PortForward, - imageList: kubernetes.NewImageList(), - cache: artifactCache, - runCtx: runCtx, - intents: newIntents(runCtx.Opts.AutoBuild, runCtx.Opts.AutoSync, runCtx.Opts.AutoDeploy), - } - - if err := r.setupTriggerCallbacks(intentChan); err != nil { - return nil, errors.Wrapf(err, "setting up trigger callbacks") - } - - return r, nil -} - -func (r *SkaffoldRunner) setupTriggerCallbacks(c chan bool) error { - if err := r.setupTriggerCallback("build", c); err != nil { - return err - } - if err := r.setupTriggerCallback("sync", c); err != nil { - return err - } - if err := r.setupTriggerCallback("deploy", c); err != nil { - return err - } - return nil -} - -func (r *SkaffoldRunner) setupTriggerCallback(triggerName string, c chan<- bool) error { - var ( - setIntent func(bool) - trigger bool - serverCallback func(func()) - ) - - switch triggerName { - case "build": - setIntent = r.intents.setBuild - trigger = r.runCtx.Opts.AutoBuild - serverCallback = server.SetBuildCallback - case "sync": - setIntent = r.intents.setSync - trigger = r.runCtx.Opts.AutoSync - serverCallback = server.SetSyncCallback - case "deploy": - setIntent = r.intents.setDeploy - trigger = r.runCtx.Opts.AutoDeploy - serverCallback = server.SetDeployCallback - default: - return fmt.Errorf("unsupported trigger type when setting callbacks: %s", triggerName) - } - - setIntent(true) - - // if "auto" is set to false, we're in manual mode - if !trigger { - setIntent(false) // set the initial value of the intent to false - // give the server a callback to set the intent value when a user request is received - serverCallback(func() { - logrus.Debugf("%s intent received, calling back to runner", triggerName) - c <- true - setIntent(true) - }) - } - return nil -} - -func getBuilder(runCtx *runcontext.RunContext) (build.Builder, error) { - switch { - case runCtx.Cfg.Build.LocalBuild != nil: - logrus.Debugln("Using builder: local") - return local.NewBuilder(runCtx) - - case runCtx.Cfg.Build.GoogleCloudBuild != nil: - logrus.Debugln("Using builder: google cloud") - return gcb.NewBuilder(runCtx), nil - - case runCtx.Cfg.Build.Cluster != nil: - logrus.Debugln("Using builder: cluster") - return cluster.NewBuilder(runCtx) - - default: - return nil, fmt.Errorf("unknown builder for config %+v", runCtx.Cfg.Build) - } -} - -func getTester(runCtx *runcontext.RunContext) test.Tester { - return test.NewTester(runCtx) -} - -func getSyncer(runCtx *runcontext.RunContext) sync.Syncer { - return sync.NewSyncer(runCtx) -} - -func getDeployer(runCtx *runcontext.RunContext) (deploy.Deployer, error) { - switch { - case runCtx.Cfg.Deploy.HelmDeploy != nil: - return deploy.NewHelmDeployer(runCtx), nil - - case runCtx.Cfg.Deploy.KubectlDeploy != nil: - return deploy.NewKubectlDeployer(runCtx), nil - - case runCtx.Cfg.Deploy.KustomizeDeploy != nil: - return deploy.NewKustomizeDeployer(runCtx), nil - - default: - return nil, fmt.Errorf("unknown deployer for config %+v", runCtx.Cfg.Deploy) - } -} - -func getTagger(runCtx *runcontext.RunContext) (tag.Tagger, error) { - t := runCtx.Cfg.Build.TagPolicy - - switch { - case runCtx.Opts.CustomTag != "": - return &tag.CustomTag{ - Tag: runCtx.Opts.CustomTag, - }, nil - - case t.EnvTemplateTagger != nil: - return tag.NewEnvTemplateTagger(t.EnvTemplateTagger.Template) - - case t.ShaTagger != nil: - return &tag.ChecksumTagger{}, nil - - case t.GitTagger != nil: - return tag.NewGitCommit(t.GitTagger.Variant) - - case t.DateTimeTagger != nil: - return tag.NewDateTimeTagger(t.DateTimeTagger.Format, t.DateTimeTagger.TimeZone), nil - - default: - return nil, fmt.Errorf("unknown tagger for strategy %+v", t) - } -} - -func (r *SkaffoldRunner) Deploy(ctx context.Context, out io.Writer, artifacts []build.Artifact) error { - if cfg.IsKindCluster(r.runCtx.KubeContext) { - // With `kind`, docker images have to be loaded with the `kind` CLI. - if err := r.loadImagesInKindNodes(ctx, out, artifacts); err != nil { - return errors.Wrapf(err, "loading images into kind nodes") - } - } - - err := r.Deployer.Deploy(ctx, out, artifacts, r.labellers) - r.hasDeployed = true - if err != nil { - return err - } - return r.performStatusCheck(ctx, out) -} - -func (r *SkaffoldRunner) performStatusCheck(ctx context.Context, out io.Writer) error { - // Check if we need to perform deploy status - if r.runCtx.Opts.StatusCheck { - fmt.Fprintln(out, "Waiting for deployments to stabilize") - err := statusCheck(ctx, r.defaultLabeller, r.runCtx) - if err != nil { - fmt.Fprintln(out, err.Error()) - } - return err - } - return nil -} - // HasDeployed returns true if this runner has deployed something. func (r *SkaffoldRunner) HasDeployed() bool { return r.hasDeployed @@ -330,52 +86,3 @@ func (r *SkaffoldRunner) HasDeployed() bool { func (r *SkaffoldRunner) HasBuilt() bool { return r.hasBuilt } - -type tagErr struct { - tag string - err error -} - -// imageTags generates tags for a list of artifacts -func (r *SkaffoldRunner) imageTags(ctx context.Context, out io.Writer, artifacts []*latest.Artifact) (tag.ImageTags, error) { - start := time.Now() - color.Default.Fprintln(out, "Generating tags...") - - tagErrs := make([]chan tagErr, len(artifacts)) - - for i := range artifacts { - tagErrs[i] = make(chan tagErr, 1) - - i := i - go func() { - tag, err := r.Tagger.GenerateFullyQualifiedImageName(artifacts[i].Workspace, artifacts[i].ImageName) - tagErrs[i] <- tagErr{tag: tag, err: err} - }() - } - - imageTags := make(tag.ImageTags, len(artifacts)) - - for i, artifact := range artifacts { - imageName := artifact.ImageName - color.Default.Fprintf(out, " - %s -> ", imageName) - - select { - case <-ctx.Done(): - return nil, context.Canceled - - case t := <-tagErrs[i]: - tag := t.tag - err := t.err - if err != nil { - return nil, errors.Wrapf(err, "generating tag for %s", imageName) - } - - fmt.Fprintln(out, tag) - - imageTags[imageName] = tag - } - } - - color.Default.Fprintln(out, "Tags generated in", time.Since(start)) - return imageTags, nil -} diff --git a/pkg/skaffold/runner/runner_test.go b/pkg/skaffold/runner/runner_test.go index 1d44c443128..8d1e136b11d 100644 --- a/pkg/skaffold/runner/runner_test.go +++ b/pkg/skaffold/runner/runner_test.go @@ -215,10 +215,10 @@ func createRunner(t *testutil.T, testBench *TestBench, monitor filemon.Monitor) runner, err := NewForConfig(runCtx) t.CheckNoError(err) - runner.Builder = testBench - runner.Syncer = testBench - runner.Tester = testBench - runner.Deployer = testBench + runner.builder = testBench + runner.syncer = testBench + runner.tester = testBench + runner.deployer = testBench runner.listener = testBench runner.monitor = monitor @@ -341,9 +341,9 @@ func TestNewForConfig(t *testing.T) { if cfg != nil { b, _t, d := WithTimings(test.expectedBuilder, test.expectedTester, test.expectedDeployer, test.cacheArtifacts) - t.CheckErrorAndTypeEquality(test.shouldErr, err, b, cfg.Builder) - t.CheckErrorAndTypeEquality(test.shouldErr, err, _t, cfg.Tester) - t.CheckErrorAndTypeEquality(test.shouldErr, err, d, cfg.Deployer) + t.CheckErrorAndTypeEquality(test.shouldErr, err, b, cfg.builder) + t.CheckErrorAndTypeEquality(test.shouldErr, err, _t, cfg.tester) + t.CheckErrorAndTypeEquality(test.shouldErr, err, d, cfg.deployer) } }) }