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

kubernetes / kompose / 6696194161

30 Oct 2023 05:02PM UTC coverage: 54.96%. Remained the same
6696194161

push

github

web-flow
chore(deps)(deps): bump golang.org/x/tools from 0.13.0 to 0.14.0 (#1723)

Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.13.0 to 0.14.0.
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](https://github.com/golang/tools/compare/v0.13.0...v0.14.0)

---
updated-dependencies:
- dependency-name: golang.org/x/tools
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

2205 of 4012 relevant lines covered (54.96%)

7.91 hits per line

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

30.6
/pkg/transformer/utils.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 transformer
18

19
import (
20
        "fmt"
21
        "os"
22
        "os/exec"
23
        "path"
24
        "path/filepath"
25
        "strings"
26

27
        dockerlib "github.com/fsouza/go-dockerclient"
28
        "github.com/kubernetes/kompose/pkg/kobject"
29
        "github.com/kubernetes/kompose/pkg/utils/docker"
30
        "github.com/kubernetes/kompose/pkg/version"
31
        "github.com/pkg/errors"
32
        log "github.com/sirupsen/logrus"
33
        api "k8s.io/api/core/v1"
34
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35
        "k8s.io/apimachinery/pkg/runtime"
36
)
37

38
// Selector used as labels and selector
39
const Selector = "io.kompose.service"
40

41
// Exists returns true if a file path exists.
42
// Otherwise, returns false.
43
func Exists(p string) bool {
×
44
        _, err := os.Stat(p)
×
45
        return err == nil
×
46
}
×
47

48
// CreateOutFile creates the file to write to if --out is specified
49
func CreateOutFile(out string) (*os.File, error) {
×
50
        if len(out) == 0 {
×
51
                return nil, nil
×
52
        }
×
53
        // Creates directories if "out" contains nonexistent directories.
54
        if dir := filepath.Dir(out); !Exists(dir) {
×
55
                if err := os.MkdirAll(dir, os.ModePerm); err != nil {
×
56
                        return nil, errors.Wrap(err, "failed to create directories")
×
57
                }
×
58
        }
59
        f, err := os.Create(out)
×
60
        if err != nil {
×
61
                return nil, errors.Wrap(err, "failed to create file, os.Create failed")
×
62
        }
×
63
        return f, nil
×
64
}
65

66
// ParseVolume parses a given volume, which might be [name:][host:]container[:access_mode]
67
func ParseVolume(volume string) (name, host, container, mode string, err error) {
26✔
68
        if containWindowsPath(volume) {
39✔
69
                return parseWindowsVolume(volume)
13✔
70
        }
13✔
71
        return parseVolume(volume)
13✔
72
}
73

74
func parseVolume(volume string) (name, host, container, mode string, err error) {
13✔
75
        separator := ":"
13✔
76

13✔
77
        // Parse based on ":"
13✔
78
        volumeStrings := strings.Split(volume, separator)
13✔
79
        if len(volumeStrings) == 0 {
13✔
80
                return
×
81
        }
×
82

83
        // Set name if existed
84
        if !isPath(volumeStrings[0]) {
19✔
85
                name = volumeStrings[0]
6✔
86
                volumeStrings = volumeStrings[1:]
6✔
87
        }
6✔
88

89
        // Check if *anything* has been passed
90
        if len(volumeStrings) == 0 {
13✔
91
                err = fmt.Errorf("invalid volume format: %s", volume)
×
92
                return
×
93
        }
×
94

95
        // Get the last ":" passed which is presumingly the "access mode"
96
        possibleAccessMode := volumeStrings[len(volumeStrings)-1]
13✔
97

13✔
98
        // Check to see if :Z or :z exists. We do not support SELinux relabeling at the moment.
13✔
99
        // See https://github.com/kubernetes/kompose/issues/176
13✔
100
        // Otherwise, check to see if "rw" or "ro" has been passed
13✔
101
        if possibleAccessMode == "z" || possibleAccessMode == "Z" {
14✔
102
                log.Warnf("Volume mount \"%s\" will be mounted without labeling support. :z or :Z not supported", volume)
1✔
103
                mode = ""
1✔
104
                volumeStrings = volumeStrings[:len(volumeStrings)-1]
1✔
105
        } else if possibleAccessMode == "rw" || possibleAccessMode == "ro" {
19✔
106
                mode = possibleAccessMode
6✔
107
                volumeStrings = volumeStrings[:len(volumeStrings)-1]
6✔
108
        }
6✔
109

110
        // Check the volume format as well as host
111
        container = volumeStrings[len(volumeStrings)-1]
13✔
112
        volumeStrings = volumeStrings[:len(volumeStrings)-1]
13✔
113
        if len(volumeStrings) == 1 {
18✔
114
                host = volumeStrings[0]
5✔
115
        }
5✔
116
        if !isPath(container) || (len(host) > 0 && !isPath(host)) || len(volumeStrings) > 1 {
13✔
117
                err = fmt.Errorf("invalid volume format: %s", volume)
×
118
                return
×
119
        }
×
120
        return
13✔
121
}
122

123
// parseVolume parses window volume.
124
// example: windows host mount to windows container
125
// volume = dataVolumeName:C:\Users\Data:D:\config:rw
126
// it can be parsed:
127
// name=dataVolumeName, host=C:\Users\Data, container=D:\config, mode=rw
128
// example: windows host mount to linux container
129
// volume = dataVolumeName:C:\Users\Data:/etc/config:rw
130
// it can be parsed:
131
// name=dataVolumeName, host=C:\Users\Data, container=/etc/config, mode=rw
132
func parseWindowsVolume(volume string) (name, host, container, mode string, err error) {
13✔
133
        var (
13✔
134
                buffer, volumePaths []string
13✔
135
                volumeStrings       = strings.Split(volume, ":")
13✔
136
        )
13✔
137

13✔
138
        // extract path and leave order
13✔
139
        for _, fragment := range volumeStrings {
65✔
140
                switch {
52✔
141
                case containWindowsPath(fragment):
17✔
142
                        if len(buffer) == 0 {
17✔
143
                                err = fmt.Errorf("invalid windows volume %s", volume)
×
144
                                return
×
145
                        }
×
146

147
                        driveLetter := buffer[len(buffer)-1]
17✔
148
                        if len(driveLetter) != 1 {
17✔
149
                                err = fmt.Errorf("invalid windows volume %s", volume)
×
150
                                return
×
151
                        }
×
152
                        volumePaths = append(volumePaths, driveLetter+":"+fragment)
17✔
153
                        buffer = buffer[:len(buffer)-1]
17✔
154

155
                case isPath(fragment):
5✔
156
                        volumePaths = append(volumePaths, fragment)
5✔
157
                default:
30✔
158
                        buffer = append(buffer, fragment)
30✔
159
                }
160
        }
161

162
        // set name and mode if exist
163
        if len(buffer) == 1 {
20✔
164
                if volumeStrings[0] == buffer[0] {
10✔
165
                        name = buffer[0]
3✔
166
                } else if volumeStrings[len(volumeStrings)-1] == buffer[0] {
11✔
167
                        mode = buffer[0]
4✔
168
                }
4✔
169
        } else if len(buffer) == 2 {
9✔
170
                name = buffer[0]
3✔
171
                mode = buffer[1]
3✔
172
        } else if len(buffer) > 2 {
6✔
173
                err = fmt.Errorf("invalid windows volume %s", volume)
×
174
                return
×
175
        }
×
176

177
        // Support in pass time
178
        // Check to see if :Z or :z exists. We do not support SELinux relabeling at the moment.
179
        // See https://github.com/kubernetes/kompose/issues/176
180
        // Otherwise, check to see if "rw" or "ro" has been passed
181
        if mode == "z" || mode == "Z" {
14✔
182
                log.Warnf("Volume mount \"%s\" will be mounted without labeling support. :z or :Z not supported", volume)
1✔
183
                mode = ""
1✔
184
        }
1✔
185

186
        // Set host and container if exist
187
        if len(volumePaths) == 1 {
17✔
188
                container = volumePaths[0]
4✔
189
        } else if len(volumePaths) == 2 {
22✔
190
                host = volumePaths[0]
9✔
191
                container = volumePaths[1]
9✔
192
        } else {
9✔
193
                err = fmt.Errorf("invalid windows volume %s", volume)
×
194
                return
×
195
        }
×
196
        return
13✔
197
}
198

199
// containWindowsPath check whether it contains windows path.
200
// windows path's separator is "\"
201
func containWindowsPath(substring string) bool {
78✔
202
        return strings.Contains(substring, "\\")
78✔
203
}
78✔
204

205
// ParseIngressPath parse path for ingress.
206
// eg. example.com/org -> example.com org
207
func ParseIngressPath(url string) (string, string) {
×
208
        if strings.Contains(url, "/") {
×
209
                splits := strings.Split(url, "/")
×
210
                return splits[0], "/" + strings.Join(splits[1:], "/")
×
211
        }
×
212
        return url, ""
×
213
}
214

215
func isPath(substring string) bool {
66✔
216
        return strings.Contains(substring, "/") || substring == "."
66✔
217
}
66✔
218

219
// ConfigLabels configures label name alone
220
func ConfigLabels(name string) map[string]string {
×
221
        return map[string]string{Selector: name}
×
222
}
×
223

224
// ConfigLabelsWithNetwork configures label and add Network Information in labels
225
func ConfigLabelsWithNetwork(name string, net []string) map[string]string {
×
226
        labels := map[string]string{}
×
227
        labels[Selector] = name
×
228

×
229
        for _, n := range net {
×
230
                labels["io.kompose.network/"+n] = "true"
×
231
        }
×
232
        return labels
×
233
        //return map[string]string{Selector: name, "Network": net}
234
}
235

236
// ConfigAllLabels creates labels with service nam and deploy labels
237
func ConfigAllLabels(name string, service *kobject.ServiceConfig) map[string]string {
×
238
        base := ConfigLabels(name)
×
239
        if service.DeployLabels != nil {
×
240
                for k, v := range service.DeployLabels {
×
241
                        base[k] = v
×
242
                }
×
243
        }
244
        return base
×
245
}
246

247
// ConfigAnnotations configures annotations
248
func ConfigAnnotations(service kobject.ServiceConfig) map[string]string {
×
249
        annotations := map[string]string{}
×
250
        for key, value := range service.Annotations {
×
251
                annotations[key] = value
×
252
        }
×
253

254
        if !service.WithKomposeAnnotation {
×
255
                return annotations
×
256
        }
×
257

258
        annotations["kompose.cmd"] = strings.Join(os.Args, " ")
×
259
        versionCmd := exec.Command("kompose", "version")
×
260
        out, err := versionCmd.Output()
×
261
        if err != nil {
×
262
                errors.Wrap(err, "Failed to get kompose version")
×
263
        }
×
264
        annotations["kompose.version"] = strings.Trim(string(out), " \n")
×
265

×
266
        // If the version is blank (couldn't retrieve the kompose version for whatever reason)
×
267
        if annotations["kompose.version"] == "" {
×
268
                annotations["kompose.version"] = version.VERSION + " (" + version.GITCOMMIT + ")"
×
269
        }
×
270

271
        return annotations
×
272
}
273

274
// Print either prints to stdout or to file/s
275
func Print(name, path string, trailing string, data []byte, toStdout, generateJSON bool, f *os.File, provider string) (string, error) {
×
276
        file := ""
×
277
        if generateJSON {
×
278
                file = fmt.Sprintf("%s-%s.json", name, trailing)
×
279
        } else {
×
280
                file = fmt.Sprintf("%s-%s.yaml", name, trailing)
×
281
        }
×
282
        if toStdout {
×
283
                fmt.Fprintf(os.Stdout, "%s\n", string(data))
×
284
                return "", nil
×
285
        } else if f != nil {
×
286
                // Write all content to a single file f
×
287
                if _, err := f.WriteString(fmt.Sprintf("%s\n", string(data))); err != nil {
×
288
                        return "", errors.Wrap(err, "f.WriteString failed, Failed to write %s to file: "+trailing)
×
289
                }
×
290
                f.Sync()
×
291
        } else {
×
292
                // Write content separately to each file
×
293
                file = filepath.Join(path, file)
×
294
                if err := os.WriteFile(file, data, 0644); err != nil {
×
295
                        return "", errors.Wrap(err, "Failed to write %s: "+trailing)
×
296
                }
×
297
                log.Printf("%s file %q created", formatProviderName(provider), file)
×
298
        }
299
        return file, nil
×
300
}
301

302
// If Openshift, change to OpenShift!
303
func formatProviderName(provider string) string {
2✔
304
        if strings.EqualFold(provider, "openshift") {
3✔
305
                return "OpenShift"
1✔
306
        } else if strings.EqualFold(provider, "kubernetes") {
3✔
307
                return "Kubernetes"
1✔
308
        }
1✔
309
        return provider
×
310
}
311

312
// EnvSort struct
313
type EnvSort []api.EnvVar
314

315
// Len returns the number of elements in the collection.
316
func (env EnvSort) Len() int {
×
317
        return len(env)
×
318
}
×
319

320
// Less returns whether the element with index i should sort before
321
// the element with index j.
322
func (env EnvSort) Less(i, j int) bool {
×
323
        return env[i].Name < env[j].Name
×
324
}
×
325

326
// Swap swaps the elements with indexes i and j.
327
func (env EnvSort) Swap(i, j int) {
×
328
        env[i], env[j] = env[j], env[i]
×
329
}
×
330

331
// GetComposeFileDir returns compose file directory
332
func GetComposeFileDir(inputFiles []string) (string, error) {
1✔
333
        // Lets assume all the docker-compose files are in the same directory
1✔
334
        inputFile := inputFiles[0]
1✔
335
        if strings.Index(inputFile, "/") != 0 {
2✔
336
                workDir, err := os.Getwd()
1✔
337
                if err != nil {
1✔
338
                        return "", err
×
339
                }
×
340
                inputFile = filepath.Join(workDir, inputFile)
1✔
341
        }
342
        log.Debugf("Compose file dir: %s", filepath.Dir(inputFile))
1✔
343
        return filepath.Dir(inputFile), nil
1✔
344
}
345

346
// BuildDockerImage builds docker image
347
func BuildDockerImage(service kobject.ServiceConfig, name string) error {
×
348
        wd, err := os.Getwd()
×
349
        if err != nil {
×
350
                return err
×
351
        }
×
352

353
        log.Debug("Build image working dir is: ", wd)
×
354

×
355
        log.Debug("Build image service build is: ", service.Build)
×
356
        // Get the appropriate image source and name
×
357
        imagePath := service.Build
×
358
        if !path.IsAbs(service.Build) {
×
359
                imagePath = path.Join(wd, service.Build)
×
360
        }
×
361
        log.Debugf("Build image context is: %s", imagePath)
×
362

×
363
        if _, err := os.Stat(imagePath); err != nil {
×
364
                return errors.Wrapf(err, "%s is not a valid path for building image %s. Check if this dir exists.", service.Build, name)
×
365
        }
×
366

367
        imageName := name
×
368
        if service.Image != "" {
×
369
                imageName = service.Image
×
370
        }
×
371

372
        buildargs := []dockerlib.BuildArg{}
×
373
        for envName, envValue := range service.BuildArgs {
×
374
                var value string
×
375
                if envValue == nil {
×
376
                        value = os.Getenv(envName)
×
377
                } else {
×
378
                        value = *envValue
×
379
                }
×
380
                buildargs = append(buildargs, dockerlib.BuildArg{Name: envName, Value: value})
×
381
        }
382

383
        // Connect to the Docker client
384
        client, err := docker.Client()
×
385
        if err != nil {
×
386
                return err
×
387
        }
×
388

389
        // Use the build struct function to build the image
390
        // Build the image!
391
        build := docker.Build{Client: *client}
×
392
        err = build.BuildImage(imagePath, imageName, service.Dockerfile, buildargs)
×
393

×
394
        if err != nil {
×
395
                return err
×
396
        }
×
397

398
        return nil
×
399
}
400

401
// PushDockerImageWithOpt pushes docker image
402
func PushDockerImageWithOpt(service kobject.ServiceConfig, serviceName string, opt kobject.ConvertOptions) error {
×
403
        if !opt.PushImage {
×
404
                // Don't do anything if registry is specified but push is disabled, just WARN about it
×
405
                if opt.PushImageRegistry != "" {
×
406
                        log.Warnf("Push image registry '%s' is specified but push image is disabled, skipping pushing to repository", opt.PushImageRegistry)
×
407
                }
×
408
                return nil
×
409
        }
410

411
        log.Infof("Push image is enabled. Attempting to push image '%s'", service.Image)
×
412

×
413
        // Don't do anything if service.Image is blank, but at least WARN about it
×
414
        // else, let's push the image
×
415
        if service.Image == "" {
×
416
                log.Warnf("No image name has been passed for service %s, skipping pushing to repository", serviceName)
×
417
                return nil
×
418
        }
×
419

420
        image, err := docker.ParseImage(service.Image, opt.PushImageRegistry)
×
421
        if err != nil {
×
422
                return err
×
423
        }
×
424

425
        client, err := docker.Client()
×
426
        if err != nil {
×
427
                return err
×
428
        }
×
429

430
        if opt.PushImageRegistry != "" {
×
431
                log.Info("Push image registry is specified. Tag the image into registry firstly.")
×
432
                tag := docker.Tag{Client: *client}
×
433
                err = tag.TagImage(image)
×
434

×
435
                if err != nil {
×
436
                        return err
×
437
                }
×
438
        }
439

440
        push := docker.Push{Client: *client}
×
441
        err = push.PushImage(image)
×
442
        if err != nil {
×
443
                return err
×
444
        }
×
445

446
        return nil
×
447
}
448

449
// CreateNamespace creates a Kubernetes namespace, which can be used in both:
450
// Openshift and Kubernetes
451
func CreateNamespace(namespace string) *api.Namespace {
×
452
        return &api.Namespace{
×
453
                TypeMeta: metav1.TypeMeta{
×
454
                        Kind:       "Namespace",
×
455
                        APIVersion: "v1",
×
456
                },
×
457
                ObjectMeta: metav1.ObjectMeta{
×
458
                        Name: namespace,
×
459
                },
×
460
        }
×
461
}
×
462

463
// AssignNamespaceToObjects will add the namespace metadata to each object
464
func AssignNamespaceToObjects(objs *[]runtime.Object, namespace string) {
×
465
        ns := "default"
×
466
        if namespace != "" {
×
467
                ns = namespace
×
468
        }
×
469
        var result []runtime.Object
×
470
        for _, obj := range *objs {
×
471
                if us, ok := obj.(metav1.Object); ok {
×
472
                        us.SetNamespace(ns)
×
473
                }
×
474
                result = append(result, obj)
×
475
        }
476
        *objs = result
×
477
}
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