• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubernetes / kompose / 4217081086

19 Feb 2023 04:20PM UTC coverage: 53.126%. Remained the same
4217081086

push

github

GitHub
Bump golang.org/x/net from 0.5.0 to 0.7.0 (#1592)

1963 of 3695 relevant lines covered (53.13%)

7.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.87
/pkg/transformer/openshift/openshift.go
1
/*
2
Copyright 2017 The Kubernetes Authors All rights reserved.
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 openshift
18

19
import (
20
        "fmt"
21
        "os"
22
        "sort"
23

24
        "github.com/kubernetes/kompose/pkg/kobject"
25
        "github.com/kubernetes/kompose/pkg/transformer"
26
        "github.com/kubernetes/kompose/pkg/transformer/kubernetes"
27
        deployapi "github.com/openshift/api/apps/v1"
28
        buildapi "github.com/openshift/api/build/v1"
29
        imageapi "github.com/openshift/api/image/v1"
30
        routeapi "github.com/openshift/api/route/v1"
31
        "github.com/pkg/errors"
32
        log "github.com/sirupsen/logrus"
33
        corev1 "k8s.io/api/core/v1"
34
        kapi "k8s.io/apimachinery/pkg/apis/meta/v1"
35
        "k8s.io/apimachinery/pkg/runtime"
36
        "k8s.io/apimachinery/pkg/util/intstr"
37
)
38

39
// OpenShift implements Transformer interface and represents OpenShift transformer
40
type OpenShift struct {
41
        // Anonymous field allows for inheritance. We are basically inheriting
42
        // all of kubernetes.Kubernetes Methods and variables here. We'll overwrite
43
        // some of those methods with our own for openshift.
44
        kubernetes.Kubernetes
45
}
46

47
// list of all unsupported keys for this transformer
48
// Keys are names of variables in kobject struct.
49
// this is map to make searching for keys easier
50
// to make sure that unsupported key is not going to be reported twice
51
// by keeping record if already saw this key in another service
52
var unsupportedKey = map[string]bool{}
53

54
// initImageStream initializes ImageStream object
55
func (o *OpenShift) initImageStream(name string, service kobject.ServiceConfig, opt kobject.ConvertOptions) *imageapi.ImageStream {
1✔
56
        if service.Image == "" {
1✔
57
                service.Image = name
×
58
        }
×
59
        // Retrieve tags and image name for mapping
60
        var importPolicy imageapi.TagImportPolicy
1✔
61
        if opt.InsecureRepository {
1✔
62
                importPolicy = imageapi.TagImportPolicy{Insecure: true}
×
63
        }
×
64

65
        var tags []imageapi.TagReference
1✔
66

1✔
67
        if service.Build != "" || opt.Build != "build-config" {
2✔
68
                tags = append(tags,
1✔
69
                        imageapi.TagReference{
1✔
70
                                From: &corev1.ObjectReference{
1✔
71
                                        Kind: "DockerImage",
1✔
72
                                        Name: service.Image,
1✔
73
                                },
1✔
74
                                ImportPolicy: importPolicy,
1✔
75
                                Name:         GetImageTag(service.Image),
1✔
76
                        })
1✔
77
        }
1✔
78

79
        is := &imageapi.ImageStream{
1✔
80
                TypeMeta: kapi.TypeMeta{
1✔
81
                        Kind:       "ImageStream",
1✔
82
                        APIVersion: "v1",
1✔
83
                },
1✔
84
                ObjectMeta: kapi.ObjectMeta{
1✔
85
                        Name:   name,
1✔
86
                        Labels: transformer.ConfigLabels(name),
1✔
87
                },
1✔
88
                Spec: imageapi.ImageStreamSpec{
1✔
89
                        Tags: tags,
1✔
90
                },
1✔
91
        }
1✔
92
        return is
1✔
93
}
94

95
func initBuildConfig(name string, service kobject.ServiceConfig, repo string, branch string) (*buildapi.BuildConfig, error) {
2✔
96
        contextDir, err := GetAbsBuildContext(service.Build)
2✔
97
        envList := transformer.EnvSort{}
2✔
98
        for envName, envValue := range service.BuildArgs {
4✔
99
                if *envValue == "\x00" {
2✔
100
                        *envValue = os.Getenv(envName)
×
101
                }
×
102
                envList = append(envList, corev1.EnvVar{Name: envName, Value: *envValue})
2✔
103
        }
104
        // Stable sorts data while keeping the original order of equal elements
105
        // we need this because envs are not populated in any random order
106
        // this sorting ensures they are populated in a particular order
107
        sort.Stable(envList)
2✔
108
        if err != nil {
2✔
109
                return nil, errors.Wrap(err, name+"buildconfig cannot be created due to error in creating build context, getAbsBuildContext failed")
×
110
        }
×
111

112
        bc := &buildapi.BuildConfig{
2✔
113
                TypeMeta: kapi.TypeMeta{
2✔
114
                        Kind:       "BuildConfig",
2✔
115
                        APIVersion: "v1",
2✔
116
                },
2✔
117

2✔
118
                ObjectMeta: kapi.ObjectMeta{
2✔
119
                        Name:   name,
2✔
120
                        Labels: transformer.ConfigLabels(name),
2✔
121
                },
2✔
122
                Spec: buildapi.BuildConfigSpec{
2✔
123
                        Triggers: []buildapi.BuildTriggerPolicy{
2✔
124
                                {Type: "ConfigChange"},
2✔
125
                        },
2✔
126
                        RunPolicy: "Serial",
2✔
127
                        CommonSpec: buildapi.CommonSpec{
2✔
128
                                Source: buildapi.BuildSource{
2✔
129
                                        Git: &buildapi.GitBuildSource{
2✔
130
                                                Ref: branch,
2✔
131
                                                URI: repo,
2✔
132
                                        },
2✔
133
                                        ContextDir: contextDir,
2✔
134
                                },
2✔
135
                                Strategy: buildapi.BuildStrategy{
2✔
136
                                        DockerStrategy: &buildapi.DockerBuildStrategy{
2✔
137
                                                DockerfilePath: service.Dockerfile,
2✔
138
                                                Env:            envList,
2✔
139
                                        },
2✔
140
                                },
2✔
141
                                Output: buildapi.BuildOutput{
2✔
142
                                        To: &corev1.ObjectReference{
2✔
143
                                                Kind: "ImageStreamTag",
2✔
144
                                                Name: name + ":" + GetImageTag(service.Image),
2✔
145
                                        },
2✔
146
                                },
2✔
147
                        },
2✔
148
                },
2✔
149
        }
2✔
150
        return bc, nil
2✔
151
}
152

153
// initDeploymentConfig initializes OpenShifts DeploymentConfig object
154
func (o *OpenShift) initDeploymentConfig(name string, service kobject.ServiceConfig, replicas int) *deployapi.DeploymentConfig {
3✔
155
        containerName := []string{name}
3✔
156

3✔
157
        // Properly add tags to the image name
3✔
158
        tag := GetImageTag(service.Image)
3✔
159

3✔
160
        // Use ContainerName if it was set
3✔
161
        if service.ContainerName != "" {
6✔
162
                containerName = []string{service.ContainerName}
3✔
163
        }
3✔
164

165
        var podSpec corev1.PodSpec
3✔
166
        if len(service.Configs) > 0 {
3✔
167
                podSpec = o.InitPodSpecWithConfigMap(name, " ", service)
×
168
        } else {
3✔
169
                podSpec = o.InitPodSpec(name, " ", "")
3✔
170
        }
3✔
171

172
        dc := &deployapi.DeploymentConfig{
3✔
173
                TypeMeta: kapi.TypeMeta{
3✔
174
                        Kind:       "DeploymentConfig",
3✔
175
                        APIVersion: "v1",
3✔
176
                },
3✔
177
                ObjectMeta: kapi.ObjectMeta{
3✔
178
                        Name:   name,
3✔
179
                        Labels: transformer.ConfigLabels(name),
3✔
180
                },
3✔
181
                Spec: deployapi.DeploymentConfigSpec{
3✔
182
                        Replicas: int32(replicas),
3✔
183
                        Selector: transformer.ConfigLabels(name),
3✔
184
                        //UniqueLabelKey: p.Name,
3✔
185
                        Template: &corev1.PodTemplateSpec{
3✔
186
                                ObjectMeta: kapi.ObjectMeta{
3✔
187
                                        Labels: transformer.ConfigLabels(name),
3✔
188
                                },
3✔
189
                                Spec: podSpec,
3✔
190
                        },
3✔
191
                        Triggers: []deployapi.DeploymentTriggerPolicy{
3✔
192
                                // Trigger new deploy when DeploymentConfig is created (config change)
3✔
193
                                {
3✔
194
                                        Type: deployapi.DeploymentTriggerOnConfigChange,
3✔
195
                                },
3✔
196
                                {
3✔
197
                                        Type: deployapi.DeploymentTriggerOnImageChange,
3✔
198
                                        ImageChangeParams: &deployapi.DeploymentTriggerImageChangeParams{
3✔
199
                                                //Automatic - if new tag is detected - update image update inside the pod template
3✔
200
                                                Automatic:      true,
3✔
201
                                                ContainerNames: containerName,
3✔
202
                                                From: corev1.ObjectReference{
3✔
203
                                                        Name: name + ":" + tag,
3✔
204
                                                        Kind: "ImageStreamTag",
3✔
205
                                                },
3✔
206
                                        },
3✔
207
                                },
3✔
208
                        },
3✔
209
                },
3✔
210
        }
3✔
211

3✔
212
        update := service.GetOSUpdateStrategy()
3✔
213
        if update != nil {
3✔
214
                dc.Spec.Strategy = deployapi.DeploymentStrategy{
×
215
                        Type:          deployapi.DeploymentStrategyTypeRolling,
×
216
                        RollingParams: update,
×
217
                }
×
218
                log.Debugf("Set deployment '%s' rolling update: MaxSurge: %s, MaxUnavailable: %s", name, update.MaxSurge.String(), update.MaxUnavailable.String())
×
219
        }
×
220

221
        return dc
3✔
222
}
223

224
func (o *OpenShift) initRoute(name string, service kobject.ServiceConfig, port int32) *routeapi.Route {
2✔
225
        route := &routeapi.Route{
2✔
226
                TypeMeta: kapi.TypeMeta{
2✔
227
                        Kind:       "Route",
2✔
228
                        APIVersion: "v1",
2✔
229
                },
2✔
230
                ObjectMeta: kapi.ObjectMeta{
2✔
231
                        Name:   name,
2✔
232
                        Labels: transformer.ConfigLabels(name),
2✔
233
                },
2✔
234
                Spec: routeapi.RouteSpec{
2✔
235
                        Port: &routeapi.RoutePort{
2✔
236
                                TargetPort: intstr.IntOrString{
2✔
237
                                        IntVal: port,
2✔
238
                                },
2✔
239
                        },
2✔
240
                        To: routeapi.RouteTargetReference{
2✔
241
                                Kind: "Service",
2✔
242
                                Name: name,
2✔
243
                        },
2✔
244
                },
2✔
245
        }
2✔
246

2✔
247
        if service.ExposeService != "true" {
3✔
248
                route.Spec.Host = service.ExposeService
1✔
249
        }
1✔
250
        return route
2✔
251
}
252

253
// Transform maps komposeObject to openshift objects
254
// returns objects that are already sorted in the way that Services are first
255
func (o *OpenShift) Transform(komposeObject kobject.KomposeObject, opt kobject.ConvertOptions) ([]runtime.Object, error) {
4✔
256
        noSupKeys := o.Kubernetes.CheckUnsupportedKey(&komposeObject, unsupportedKey)
4✔
257
        for _, keyName := range noSupKeys {
4✔
258
                log.Warningf("OpenShift provider doesn't support %s key - ignoring", keyName)
×
259
        }
×
260
        // this will hold all the converted data
261
        var allobjects []runtime.Object
4✔
262
        var err error
4✔
263
        var composeFileDir string
4✔
264
        buildRepo := opt.BuildRepo
4✔
265
        buildBranch := opt.BuildBranch
4✔
266

4✔
267
        if komposeObject.Secrets != nil {
4✔
268
                secrets, err := o.CreateSecrets(komposeObject)
×
269
                if err != nil {
×
270
                        return nil, errors.Wrapf(err, "create secrets error")
×
271
                }
×
272
                for _, item := range secrets {
×
273
                        allobjects = append(allobjects, item)
×
274
                }
×
275
        }
276

277
        sortedKeys := kubernetes.SortedKeys(komposeObject)
4✔
278
        for _, name := range sortedKeys {
8✔
279
                service := komposeObject.ServiceConfigs[name]
4✔
280
                var objects []runtime.Object
4✔
281

4✔
282
                //replicas
4✔
283
                var replica int
4✔
284
                if opt.IsReplicaSetFlag || service.Replicas == 0 {
8✔
285
                        replica = opt.Replicas
4✔
286
                } else {
4✔
287
                        replica = service.Replicas
×
288
                }
×
289

290
                // If Deploy.Mode = Global has been set, make replica = 1 when generating DeploymentConfig
291
                if service.DeployMode == "global" {
4✔
292
                        replica = 1
×
293
                }
×
294

295
                // Must build the images before conversion (got to add service.Image in case 'image' key isn't provided
296
                // Check to see if there is an InputFile (required!) before we build the container
297
                // Check that there's actually a Build key
298
                // Lastly, we must have an Image name to continue
299
                if opt.Build == "local" && opt.InputFiles != nil && service.Build != "" {
4✔
300
                        // If there's no "image" key, use the name of the container that's built
×
301
                        if service.Image == "" {
×
302
                                service.Image = name
×
303
                        }
×
304

305
                        if service.Image == "" {
×
306
                                return nil, fmt.Errorf("image key required within build parameters in order to build and push service '%s'", name)
×
307
                        }
×
308

309
                        // Build the container!
310
                        err := transformer.BuildDockerImage(service, name)
×
311
                        if err != nil {
×
312
                                log.Fatalf("Unable to build Docker container for service %v: %v", name, err)
×
313
                        }
×
314

315
                        // Push the built container to the repo!
316
                        err = transformer.PushDockerImageWithOpt(service, name, opt)
×
317
                        if err != nil {
×
318
                                log.Fatalf("Unable to push Docker image for service %v: %v", name, err)
×
319
                        }
×
320
                }
321

322
                // Generate pod only and nothing more
323
                if service.Restart == "no" || service.Restart == "on-failure" {
5✔
324
                        // Error out if Controller Object is specified with restart: 'on-failure'
1✔
325
                        if opt.IsDeploymentConfigFlag {
2✔
326
                                return nil, errors.New("Controller object cannot be specified with restart: 'on-failure'")
1✔
327
                        }
1✔
328
                        pod := o.InitPod(name, service)
×
329
                        objects = append(objects, pod)
×
330
                } else {
3✔
331
                        objects = o.CreateWorkloadAndConfigMapObjects(name, service, opt)
3✔
332

3✔
333
                        if opt.CreateDeploymentConfig {
4✔
334
                                objects = append(objects, o.initDeploymentConfig(name, service, replica)) // OpenShift DeploymentConfigs
1✔
335
                                // create ImageStream after deployment (creating IS will trigger new deployment)
1✔
336
                                objects = append(objects, o.initImageStream(name, service, opt))
1✔
337
                        }
1✔
338

339
                        // buildconfig needs to be added to objects after imagestream because of this Openshift bug: https://github.com/openshift/origin/issues/4518
340
                        // Generate BuildConfig if the parameter has been passed
341
                        if service.Build != "" && opt.Build == "build-config" {
3✔
342
                                // Get the compose file directory
×
343
                                composeFileDir, err = transformer.GetComposeFileDir(opt.InputFiles)
×
344
                                if err != nil {
×
345
                                        log.Warningf("Error %v in detecting compose file's directory.", err)
×
346
                                        continue
×
347
                                }
348

349
                                // Check for Git
350
                                if !HasGitBinary() && (buildRepo == "" || buildBranch == "") {
×
351
                                        return nil, errors.New("Git is not installed! Please install Git to create buildconfig, else supply source repository and branch to use for build using '--build-repo', '--build-branch' options respectively")
×
352
                                }
×
353

354
                                // Check the Git branch
355
                                if buildBranch == "" {
×
356
                                        buildBranch, err = GetGitCurrentBranch(composeFileDir)
×
357
                                        if err != nil {
×
358
                                                return nil, errors.Wrap(err, "Buildconfig cannot be created because current git branch couldn't be detected.")
×
359
                                        }
×
360
                                }
361

362
                                // Detect the remote branches
363
                                if opt.BuildRepo == "" {
×
364
                                        if err != nil {
×
365
                                                return nil, errors.Wrap(err, "Buildconfig cannot be created because remote for current git branch couldn't be detected.")
×
366
                                        }
×
367
                                        buildRepo, err = GetGitCurrentRemoteURL(composeFileDir)
×
368
                                        if err != nil {
×
369
                                                return nil, errors.Wrap(err, "Buildconfig cannot be created because git remote origin repo couldn't be detected.")
×
370
                                        }
×
371
                                }
372

373
                                // Initialize and build BuildConfig
374
                                bc, err := initBuildConfig(name, service, buildRepo, buildBranch)
×
375
                                if err != nil {
×
376
                                        return nil, errors.Wrap(err, "initBuildConfig failed")
×
377
                                }
×
378
                                objects = append(objects, bc) // Openshift BuildConfigs
×
379

×
380
                                // Log what we're doing
×
381
                                log.Infof("Buildconfig using %s::%s as source.", buildRepo, buildBranch)
×
382
                        }
383
                }
384

385
                if o.PortsExist(service) {
4✔
386
                        if service.ServiceType == "LoadBalancer" {
2✔
387
                                svcs := o.CreateLBService(name, service)
1✔
388
                                for _, svc := range svcs {
2✔
389
                                        svc.Spec.ExternalTrafficPolicy = corev1.ServiceExternalTrafficPolicyType(service.ServiceExternalTrafficPolicy)
1✔
390
                                        objects = append(objects, svc)
1✔
391
                                }
1✔
392
                                if len(svcs) > 1 {
1✔
393
                                        log.Warningf("Create multiple service to avoid using mixed protocol in the same service when it's loadbalancer type")
×
394
                                }
×
395
                        } else {
×
396
                                svc := o.CreateService(name, service)
×
397
                                objects = append(objects, svc)
×
398

×
399
                                if service.ExposeService != "" {
×
400
                                        objects = append(objects, o.initRoute(name, service, svc.Spec.Ports[0].Port))
×
401
                                }
×
402
                                if service.ServiceExternalTrafficPolicy != "" && svc.Spec.Type != corev1.ServiceTypeNodePort {
×
403
                                        log.Warningf("External Traffic Policy is ignored for the service %v of type %v", name, service.ServiceType)
×
404
                                }
×
405
                        }
406
                } else if service.ServiceType == "Headless" {
3✔
407
                        svc := o.CreateHeadlessService(name, service)
1✔
408
                        objects = append(objects, svc)
1✔
409
                        if service.ServiceExternalTrafficPolicy != "" {
1✔
410
                                log.Warningf("External Traffic Policy is ignored for the service %v of type Headless", name)
×
411
                        }
×
412
                }
413

414
                err := o.UpdateKubernetesObjects(name, service, opt, &objects)
3✔
415
                if err != nil {
3✔
416
                        return nil, errors.Wrap(err, "Error transforming Kubernetes objects")
×
417
                }
×
418

419
                allobjects = append(allobjects, objects...)
3✔
420
        }
421

422
        // sort all object so Services are first
423
        o.SortServicesFirst(&allobjects)
3✔
424
        o.RemoveDupObjects(&allobjects)
3✔
425
        // o.FixWorkloadVersion(&allobjects)
3✔
426

3✔
427
        return allobjects, nil
3✔
428
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc