github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/runner/runcontext/context.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 runcontext 18 19 import ( 20 "context" 21 "fmt" 22 "os" 23 24 "github.com/google/uuid" 25 26 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/config" 27 kubectx "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/context" 28 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log" 29 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" 30 schemaUtil "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/util" 31 ) 32 33 type RunContext struct { 34 Opts config.SkaffoldOptions 35 Pipelines Pipelines 36 KubeContext string 37 WorkingDir string 38 InsecureRegistries map[string]bool 39 Cluster config.Cluster 40 RunID string 41 } 42 43 // Pipelines encapsulates multiple config pipelines 44 type Pipelines struct { 45 pipelines []latest.Pipeline 46 pipelinesByImageName map[string]latest.Pipeline 47 } 48 49 // All returns all config pipelines. 50 func (ps Pipelines) All() []latest.Pipeline { 51 return ps.pipelines 52 } 53 54 // Head returns the first `latest.Pipeline`. 55 func (ps Pipelines) Head() latest.Pipeline { 56 return ps.pipelines[0] // there always exists atleast one pipeline. 57 } 58 59 // Select returns the first `latest.Pipeline` that matches the given artifact `imageName`. 60 func (ps Pipelines) Select(imageName string) (latest.Pipeline, bool) { 61 p, found := ps.pipelinesByImageName[imageName] 62 return p, found 63 } 64 65 // IsMultiPipeline returns true if there are more than one constituent skaffold pipelines. 66 func (ps Pipelines) IsMultiPipeline() bool { 67 return len(ps.pipelines) > 1 68 } 69 70 func (ps Pipelines) PortForwardResources() []*latest.PortForwardResource { 71 var pf []*latest.PortForwardResource 72 for _, p := range ps.pipelines { 73 pf = append(pf, p.PortForward...) 74 } 75 return pf 76 } 77 78 func (ps Pipelines) Artifacts() []*latest.Artifact { 79 var artifacts []*latest.Artifact 80 for _, p := range ps.pipelines { 81 artifacts = append(artifacts, p.Build.Artifacts...) 82 } 83 return artifacts 84 } 85 86 func (ps Pipelines) DeployConfigs() []latest.DeployConfig { 87 var cfgs []latest.DeployConfig 88 for _, p := range ps.pipelines { 89 cfgs = append(cfgs, p.Deploy) 90 } 91 return cfgs 92 } 93 94 func (ps Pipelines) Deployers() []latest.DeployConfig { 95 var deployers []latest.DeployConfig 96 for _, p := range ps.pipelines { 97 deployers = append(deployers, p.Deploy) 98 } 99 return deployers 100 } 101 102 func (ps Pipelines) TestCases() []*latest.TestCase { 103 var tests []*latest.TestCase 104 for _, p := range ps.pipelines { 105 tests = append(tests, p.Test...) 106 } 107 return tests 108 } 109 110 // TransformAllowList returns combined allowlist from pipelines 111 func (ps Pipelines) TransformAllowList() []latest.ResourceFilter { 112 var allowlist []latest.ResourceFilter 113 for _, p := range ps.pipelines { 114 if p.ResourceSelector.Allow != nil { 115 allowlist = append(allowlist, p.ResourceSelector.Allow...) 116 } 117 } 118 return allowlist 119 } 120 121 // TransformDenyList returns combined denylist from pipelines 122 func (ps Pipelines) TransformDenyList() []latest.ResourceFilter { 123 var denylist []latest.ResourceFilter 124 for _, p := range ps.pipelines { 125 if p.ResourceSelector.Deny != nil { 126 denylist = append(denylist, p.ResourceSelector.Deny...) 127 } 128 } 129 return denylist 130 } 131 132 func (ps Pipelines) StatusCheckDeadlineSeconds() int { 133 c := 0 134 // set the group status check deadline to maximum of any individually specified value 135 for _, p := range ps.pipelines { 136 if p.Deploy.StatusCheckDeadlineSeconds > c { 137 c = p.Deploy.StatusCheckDeadlineSeconds 138 } 139 } 140 return c 141 } 142 func NewPipelines(pipelines []latest.Pipeline) Pipelines { 143 m := make(map[string]latest.Pipeline) 144 for _, p := range pipelines { 145 for _, a := range p.Build.Artifacts { 146 m[a.ImageName] = p 147 } 148 } 149 return Pipelines{pipelines: pipelines, pipelinesByImageName: m} 150 } 151 152 func (rc *RunContext) PipelineForImage(imageName string) (latest.Pipeline, bool) { 153 return rc.Pipelines.Select(imageName) 154 } 155 156 func (rc *RunContext) PortForwardResources() []*latest.PortForwardResource { 157 return rc.Pipelines.PortForwardResources() 158 } 159 160 func (rc *RunContext) Artifacts() []*latest.Artifact { return rc.Pipelines.Artifacts() } 161 162 func (rc *RunContext) DeployConfigs() []latest.DeployConfig { return rc.Pipelines.DeployConfigs() } 163 164 func (rc *RunContext) Deployers() []latest.DeployConfig { return rc.Pipelines.Deployers() } 165 166 func (rc *RunContext) TestCases() []*latest.TestCase { return rc.Pipelines.TestCases() } 167 168 func (rc *RunContext) StatusCheckDeadlineSeconds() int { 169 return rc.Pipelines.StatusCheckDeadlineSeconds() 170 } 171 172 func (rc *RunContext) SkipTests() bool { 173 return rc.Opts.SkipTests 174 } 175 176 func (rc *RunContext) IsTestPhaseActive() bool { 177 return !rc.SkipTests() && len(rc.TestCases()) != 0 178 } 179 180 func (rc *RunContext) TransformAllowList() []latest.ResourceFilter { 181 return rc.Pipelines.TransformAllowList() 182 } 183 184 func (rc *RunContext) TransformDenyList() []latest.ResourceFilter { 185 return rc.Pipelines.TransformDenyList() 186 } 187 188 // AddSkaffoldLabels tells the Runner whether to add skaffold-specific labels. 189 // We only ever skip adding labels during a `skaffold render`. 190 func (rc *RunContext) AddSkaffoldLabels() bool { 191 return rc.Opts.Mode() != config.RunModes.Render 192 } 193 194 func (rc *RunContext) DefaultPipeline() latest.Pipeline { return rc.Pipelines.Head() } 195 func (rc *RunContext) GetKubeContext() string { return rc.KubeContext } 196 func (rc *RunContext) GetPipelines() []latest.Pipeline { return rc.Pipelines.All() } 197 func (rc *RunContext) GetInsecureRegistries() map[string]bool { return rc.InsecureRegistries } 198 func (rc *RunContext) GetWorkingDir() string { return rc.WorkingDir } 199 func (rc *RunContext) GetCluster() config.Cluster { return rc.Cluster } 200 func (rc *RunContext) GetNamespace() string { return rc.Opts.Namespace } 201 func (rc *RunContext) AutoBuild() bool { return rc.Opts.AutoBuild } 202 func (rc *RunContext) AutoDeploy() bool { return rc.Opts.AutoDeploy } 203 func (rc *RunContext) AutoSync() bool { return rc.Opts.AutoSync } 204 func (rc *RunContext) ContainerDebugging() bool { return rc.Opts.ContainerDebugging } 205 func (rc *RunContext) CacheArtifacts() bool { return rc.Opts.CacheArtifacts } 206 func (rc *RunContext) CacheFile() string { return rc.Opts.CacheFile } 207 func (rc *RunContext) ConfigurationFile() string { return rc.Opts.ConfigurationFile } 208 func (rc *RunContext) CustomLabels() []string { return rc.Opts.CustomLabels } 209 func (rc *RunContext) CustomTag() string { return rc.Opts.CustomTag } 210 func (rc *RunContext) DefaultRepo() *string { return rc.Cluster.DefaultRepo.Value() } 211 func (rc *RunContext) MultiLevelRepo() *bool { return rc.Opts.MultiLevelRepo } 212 func (rc *RunContext) Mode() config.RunMode { return rc.Opts.Mode() } 213 func (rc *RunContext) DigestSource() string { return rc.Opts.DigestSource } 214 func (rc *RunContext) DryRun() bool { return rc.Opts.DryRun } 215 func (rc *RunContext) ForceDeploy() bool { return rc.Opts.Force } 216 func (rc *RunContext) GetKubeConfig() string { return rc.Opts.KubeConfig } 217 func (rc *RunContext) GetKubeNamespace() string { return rc.Opts.Namespace } 218 func (rc *RunContext) GlobalConfig() string { return rc.Opts.GlobalConfig } 219 func (rc *RunContext) HydratedManifests() []string { return rc.Opts.HydratedManifests } 220 func (rc *RunContext) LoadImages() bool { return rc.Cluster.LoadImages } 221 func (rc *RunContext) ForceLoadImages() bool { return rc.Opts.ForceLoadImages } 222 func (rc *RunContext) MinikubeProfile() string { return rc.Opts.MinikubeProfile } 223 func (rc *RunContext) Muted() config.Muted { return rc.Opts.Muted } 224 func (rc *RunContext) NoPruneChildren() bool { return rc.Opts.NoPruneChildren } 225 func (rc *RunContext) Notification() bool { return rc.Opts.Notification } 226 func (rc *RunContext) PortForward() bool { return rc.Opts.PortForward.Enabled() } 227 func (rc *RunContext) PortForwardOptions() config.PortForwardOptions { return rc.Opts.PortForward } 228 func (rc *RunContext) Prune() bool { return rc.Opts.Prune() } 229 func (rc *RunContext) RenderOnly() bool { return rc.Opts.RenderOnly } 230 func (rc *RunContext) RenderOutput() string { return rc.Opts.RenderOutput } 231 func (rc *RunContext) SkipRender() bool { return rc.Opts.SkipRender } 232 func (rc *RunContext) StatusCheck() *bool { return rc.Opts.StatusCheck.Value() } 233 func (rc *RunContext) IterativeStatusCheck() bool { return rc.Opts.IterativeStatusCheck } 234 func (rc *RunContext) Tail() bool { return rc.Opts.Tail } 235 func (rc *RunContext) Trigger() string { return rc.Opts.Trigger } 236 func (rc *RunContext) WaitForDeletions() config.WaitForDeletions { return rc.Opts.WaitForDeletions } 237 func (rc *RunContext) WatchPollInterval() int { return rc.Opts.WatchPollInterval } 238 func (rc *RunContext) BuildConcurrency() int { return rc.Opts.BuildConcurrency } 239 func (rc *RunContext) IsMultiConfig() bool { return rc.Pipelines.IsMultiPipeline() } 240 func (rc *RunContext) IsDefaultKubeContext() bool { return rc.Opts.KubeContext == "" } 241 func (rc *RunContext) GetRunID() string { return rc.RunID } 242 func (rc *RunContext) RPCPort() *int { return rc.Opts.RPCPort.Value() } 243 func (rc *RunContext) RPCHTTPPort() *int { return rc.Opts.RPCHTTPPort.Value() } 244 func (rc *RunContext) PushImages() config.BoolOrUndefined { return rc.Opts.PushImages } 245 func (rc *RunContext) TransformRulesFile() string { return rc.Opts.TransformRulesFile } 246 func (rc *RunContext) JSONParseConfig() latest.JSONParseConfig { 247 return rc.DefaultPipeline().Deploy.Logs.JSONParse 248 } 249 250 func GetRunContext(ctx context.Context, opts config.SkaffoldOptions, configs []schemaUtil.VersionedConfig) (*RunContext, error) { 251 var pipelines []latest.Pipeline 252 for _, cfg := range configs { 253 if cfg != nil { 254 pipelines = append(pipelines, cfg.(*latest.SkaffoldConfig).Pipeline) 255 } 256 } 257 kubeConfig, err := kubectx.CurrentConfig() 258 if err != nil { 259 return nil, fmt.Errorf("getting current cluster context: %w", err) 260 } 261 kubeContext := kubeConfig.CurrentContext 262 log.Entry(context.TODO()).Infof("Using kubectl context: %s", kubeContext) 263 264 // TODO(dgageot): this should be the folder containing skaffold.yaml. Should also be moved elsewhere. 265 cwd, err := os.Getwd() 266 if err != nil { 267 return nil, fmt.Errorf("finding current directory: %w", err) 268 } 269 270 // combine all provided lists of insecure registries into a map 271 cfgRegistries, err := config.GetInsecureRegistries(opts.GlobalConfig) 272 if err != nil { 273 log.Entry(context.TODO()).Warn("error retrieving insecure registries from global config: push/pull issues may exist...") 274 } 275 var regList []string 276 regList = append(regList, opts.InsecureRegistries...) 277 for _, cfg := range pipelines { 278 regList = append(regList, cfg.Build.InsecureRegistries...) 279 } 280 regList = append(regList, cfgRegistries...) 281 insecureRegistries := make(map[string]bool, len(regList)) 282 for _, r := range regList { 283 insecureRegistries[r] = true 284 } 285 ps := NewPipelines(pipelines) 286 287 // TODO(https://github.com/GoogleContainerTools/skaffold/issues/3668): 288 // remove minikubeProfile from here and instead detect it by matching the 289 // kubecontext API Server to minikube profiles 290 cluster, err := config.GetCluster(ctx, config.GetClusterOpts{ 291 ConfigFile: opts.GlobalConfig, 292 DefaultRepo: opts.DefaultRepo, 293 MinikubeProfile: opts.MinikubeProfile, 294 DetectMinikube: opts.DetectMinikube, 295 }) 296 if err != nil { 297 return nil, fmt.Errorf("getting cluster: %w", err) 298 } 299 300 runID := uuid.New().String() 301 302 return &RunContext{ 303 Opts: opts, 304 Pipelines: ps, 305 WorkingDir: cwd, 306 KubeContext: kubeContext, 307 InsecureRegistries: insecureRegistries, 308 Cluster: cluster, 309 RunID: runID, 310 }, nil 311 }