• 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

32.99
/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
)
35

36
// Selector used as labels and selector
37
const Selector = "io.kompose.service"
38

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

252
        if !service.WithKomposeAnnotation {
×
253
                return annotations
×
254
        }
×
255

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

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

269
        return annotations
×
270
}
271

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

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

310
// EnvSort struct
311
type EnvSort []api.EnvVar
312

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

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

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

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

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

351
        log.Debug("Build image working dir is: ", wd)
×
352

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

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

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

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

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

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

×
392
        if err != nil {
×
393
                return err
×
394
        }
×
395

396
        return nil
×
397
}
398

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

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

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

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

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

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

×
433
                if err != nil {
×
434
                        return err
×
435
                }
×
436
        }
437

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

444
        return nil
×
445
}
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