devfile 0.0.5.pre.alpha1-x86_64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/main.go ADDED
@@ -0,0 +1,203 @@
1
+ package main
2
+
3
+ import (
4
+ "fmt"
5
+ "k8s.io/apimachinery/pkg/util/yaml"
6
+ "os"
7
+ "strconv"
8
+
9
+ "k8s.io/apimachinery/pkg/runtime"
10
+ )
11
+
12
+ type Result struct {
13
+ content string
14
+ err error
15
+ }
16
+
17
+ func main() {
18
+ args := os.Args
19
+
20
+ if len(args) <= 1 {
21
+ fmt.Fprint(os.Stderr, "Function name and devfile are required")
22
+ os.Exit(1)
23
+ }
24
+
25
+ fnName := os.Args[1]
26
+ devfile := os.Args[2]
27
+
28
+ var result Result
29
+
30
+ switch fnName {
31
+ case "deployment":
32
+ result = getDeployment(devfile, args[3], args[4], args[5], args[6], args[7])
33
+ case "service":
34
+ result = getService(devfile, args[3], args[4], args[5], args[6])
35
+ case "ingress":
36
+ result = getIngress(devfile, args[3], args[4], args[5], args[6], args[7], args[8])
37
+ case "all":
38
+ result = getAll(devfile, args[3], args[4], args[5], args[6], args[7], args[8], args[9])
39
+ case "flatten":
40
+ result = flatten(devfile)
41
+ }
42
+
43
+ if result.err != nil {
44
+ fmt.Fprint(os.Stderr, result.err)
45
+ os.Exit(1)
46
+ }
47
+
48
+ fmt.Print(result.content)
49
+ }
50
+
51
+ func unmarshalKeyValuePair(data string) (map[string]string, error) {
52
+ values := map[string]string{}
53
+ err := yaml.Unmarshal([]byte(data), &values)
54
+ if err != nil {
55
+ return nil, err
56
+ }
57
+ return values, err
58
+ }
59
+
60
+ func getDeployment(devfile, name, namespace, labelsStr, annotationsStr, replicas string) Result {
61
+ d, err := parseDevfile(devfile)
62
+ if err != nil {
63
+ return Result{"", err}
64
+ }
65
+ exists, err := d.hasContainerComponents()
66
+ if err != nil {
67
+ return Result{"", err}
68
+ }
69
+ if exists == false {
70
+ return Result{"", err}
71
+ }
72
+ labels, err := unmarshalKeyValuePair(labelsStr)
73
+ if err != nil {
74
+ return Result{"", err}
75
+ }
76
+ annotations, err := unmarshalKeyValuePair(annotationsStr)
77
+ if err != nil {
78
+ return Result{"", err}
79
+ }
80
+ replicasInt, err := strconv.Atoi(replicas)
81
+ if err != nil {
82
+ return Result{"", err}
83
+ }
84
+ deployment, err := d.getDeployment(name, namespace, labels, annotations, replicasInt)
85
+ if err != nil {
86
+ return Result{"", err}
87
+ }
88
+ content, err := marshalResources([]runtime.Object{deployment})
89
+ if err != nil {
90
+ return Result{"", err}
91
+ }
92
+ return Result{content, nil}
93
+ }
94
+
95
+ func getService(devfile, name, namespace, labelsStr, annotationsStr string) Result {
96
+ d, err := parseDevfile(devfile)
97
+ if err != nil {
98
+ return Result{"", err}
99
+ }
100
+ exists, err := d.hasContainerComponents()
101
+ if err != nil {
102
+ return Result{"", err}
103
+ }
104
+ if exists == false {
105
+ return Result{"", err}
106
+ }
107
+ labels, err := unmarshalKeyValuePair(labelsStr)
108
+ if err != nil {
109
+ return Result{"", err}
110
+ }
111
+ annotations, err := unmarshalKeyValuePair(annotationsStr)
112
+ if err != nil {
113
+ return Result{"", err}
114
+ }
115
+ service, err := d.getService(name, namespace, labels, annotations)
116
+ if err != nil {
117
+ return Result{"", err}
118
+ }
119
+ content, err := marshalResources([]runtime.Object{service})
120
+ if err != nil {
121
+ return Result{"", err}
122
+ }
123
+ return Result{content, nil}
124
+ }
125
+
126
+ func getIngress(devfile, name, namespace, labelsStr, annotationsStr, domainTemplate, ingressClass string) Result {
127
+ d, err := parseDevfile(devfile)
128
+ if err != nil {
129
+ return Result{"", err}
130
+ }
131
+ exists, err := d.hasContainerComponents()
132
+ if err != nil {
133
+ return Result{"", err}
134
+ }
135
+ if exists == false {
136
+ return Result{"", err}
137
+ }
138
+ labels, err := unmarshalKeyValuePair(labelsStr)
139
+ if err != nil {
140
+ return Result{"", err}
141
+ }
142
+ annotations, err := unmarshalKeyValuePair(annotationsStr)
143
+ if err != nil {
144
+ return Result{"", err}
145
+ }
146
+ ingress, err := d.getIngress(name, namespace, labels, annotations, domainTemplate, ingressClass)
147
+ if err != nil {
148
+ return Result{"", err}
149
+ }
150
+ content, err := marshalResources([]runtime.Object{ingress})
151
+ if err != nil {
152
+ return Result{"", err}
153
+ }
154
+ return Result{content, nil}
155
+ }
156
+
157
+ func getAll(devfile string, name, namespace, labelsStr, annotationsStr, replicas, domainTemplate, ingressClass string) Result {
158
+ d, err := parseDevfile(devfile)
159
+ if err != nil {
160
+ return Result{"", err}
161
+ }
162
+ exists, err := d.hasContainerComponents()
163
+ if err != nil {
164
+ return Result{"", err}
165
+ }
166
+ if exists == false {
167
+ return Result{"", err}
168
+ }
169
+ labels, err := unmarshalKeyValuePair(labelsStr)
170
+ if err != nil {
171
+ return Result{"", err}
172
+ }
173
+ annotations, err := unmarshalKeyValuePair(annotationsStr)
174
+ if err != nil {
175
+ return Result{"", err}
176
+ }
177
+ replicasInt, err := strconv.Atoi(replicas)
178
+ if err != nil {
179
+ return Result{"", err}
180
+ }
181
+ resources, err := d.getAll(name, namespace, labels, annotations, replicasInt, domainTemplate, ingressClass)
182
+ if err != nil {
183
+ return Result{"", err}
184
+ }
185
+ content, err := marshalResources(resources)
186
+ if err != nil {
187
+ return Result{"", err}
188
+ }
189
+ return Result{content, nil}
190
+ }
191
+
192
+ func flatten(devfile string) Result {
193
+ d, err := parseDevfile(devfile)
194
+ if err != nil {
195
+ return Result{"", err}
196
+ }
197
+ flattenedDevfile := d.getFlattenedDevfileContent()
198
+ content, err := marshalDevfile(flattenedDevfile)
199
+ if err != nil {
200
+ return Result{"", err}
201
+ }
202
+ return Result{content, nil}
203
+ }
data/ext/volume.go ADDED
@@ -0,0 +1,114 @@
1
+ package main
2
+
3
+ import (
4
+ "fmt"
5
+ "github.com/devfile/library/v2/pkg/devfile/generator"
6
+ "github.com/devfile/library/v2/pkg/devfile/parser/data/v2/common"
7
+ corev1 "k8s.io/api/core/v1"
8
+ "k8s.io/apimachinery/pkg/api/resource"
9
+ "strings"
10
+ )
11
+
12
+ func (d Devfile) getVolumesAndVolumeMounts(containers []corev1.Container, initContainers []corev1.Container, pvcNamePrefix string) ([]corev1.Volume, error) {
13
+ containerComponents, err := d.devfileObj.Data.GetDevfileContainerComponents(common.DevfileOptions{})
14
+ if err != nil {
15
+ return nil, err
16
+ }
17
+ volumeComponents, err := d.devfileObj.Data.GetDevfileVolumeComponents(common.DevfileOptions{})
18
+ if err != nil {
19
+ return nil, err
20
+ }
21
+
22
+ var volumes []corev1.Volume
23
+ for _, volumeComponent := range volumeComponents {
24
+ volName := volumeComponent.Name
25
+ if bool(*volumeComponent.Volume.Ephemeral) == true {
26
+ emptyDir, err := getEmptyDir(volName, volumeComponent.Volume.Size)
27
+ if err != nil {
28
+ return nil, err
29
+ }
30
+ volumes = append(volumes, emptyDir)
31
+ } else {
32
+ // TODO: figure this out; how should we pass PVC name? should the object be generated here?
33
+ pvcName := fmt.Sprintf("%s-%s", pvcNamePrefix, volName)
34
+ volumes = append(volumes, getPVC(volName, pvcName))
35
+ }
36
+ // containerNameToMountPaths is a map of the Devfile container name to their Devfile Volume Mount Paths for a given Volume Name
37
+ containerNameToMountPaths := make(map[string][]string)
38
+ for _, containerComp := range containerComponents {
39
+ for _, volumeMount := range containerComp.Container.VolumeMounts {
40
+ if volName == volumeMount.Name {
41
+ containerNameToMountPaths[containerComp.Name] = append(containerNameToMountPaths[containerComp.Name], generator.GetVolumeMountPath(volumeMount))
42
+ }
43
+ }
44
+ }
45
+
46
+ addVolumeMountToContainers(containers, initContainers, volName, containerNameToMountPaths)
47
+ }
48
+
49
+ return volumes, nil
50
+ }
51
+
52
+ // addVolumeMountToContainers adds the Volume Mounts in containerNameToMountPaths to the containers for a given pvc and volumeName
53
+ // containerNameToMountPaths is a map of a container name to an array of its Mount Paths.
54
+ // To be moved to devfile/library.
55
+ func addVolumeMountToContainers(containers []corev1.Container, initContainers []corev1.Container, volumeName string, containerNameToMountPaths map[string][]string) {
56
+
57
+ for containerName, mountPaths := range containerNameToMountPaths {
58
+ for i := range containers {
59
+ if containers[i].Name == containerName {
60
+ for _, mountPath := range mountPaths {
61
+ containers[i].VolumeMounts = append(containers[i].VolumeMounts, corev1.VolumeMount{
62
+ Name: volumeName,
63
+ MountPath: mountPath,
64
+ SubPath: "",
65
+ },
66
+ )
67
+ }
68
+ }
69
+ }
70
+ for i := range initContainers {
71
+ if strings.HasPrefix(initContainers[i].Name, containerName) {
72
+ for _, mountPath := range mountPaths {
73
+ initContainers[i].VolumeMounts = append(initContainers[i].VolumeMounts, corev1.VolumeMount{
74
+ Name: volumeName,
75
+ MountPath: mountPath,
76
+ SubPath: "",
77
+ },
78
+ )
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+
85
+ // getPVC gets a pvc type volume with the given volume name and pvc name.
86
+ func getPVC(volumeName, pvcName string) corev1.Volume {
87
+
88
+ return corev1.Volume{
89
+ Name: volumeName,
90
+ VolumeSource: corev1.VolumeSource{
91
+ PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
92
+ ClaimName: pvcName,
93
+ },
94
+ },
95
+ }
96
+ }
97
+
98
+ // getEmptyDir gets an emptyDir type volume with the given volume name and size.
99
+ // size should be parseable as a Kubernetes `Quantity` or an error will be returned
100
+ func getEmptyDir(volumeName string, size string) (corev1.Volume, error) {
101
+
102
+ emptyDir := &corev1.EmptyDirVolumeSource{}
103
+ qty, err := resource.ParseQuantity(size)
104
+ if err != nil {
105
+ return corev1.Volume{}, err
106
+ }
107
+ emptyDir.SizeLimit = &qty
108
+ return corev1.Volume{
109
+ Name: volumeName,
110
+ VolumeSource: corev1.VolumeSource{
111
+ EmptyDir: emptyDir,
112
+ },
113
+ }, nil
114
+ }
data/lib/devfile.rb ADDED
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ # Module that works with the Devfile standard
6
+ module Devfile
7
+ # Set of services to parse a devfile and output k8s manifests
8
+ class Parser
9
+ FILE_PATH = File.expand_path('./../bin/devfile', File.dirname(__FILE__))
10
+
11
+ class << self
12
+ def get_deployment(devfile, name, namespace, labels, annotations, replicas)
13
+ stdout, stderr, status = Open3.capture3(
14
+ "#{FILE_PATH} deployment '#{devfile}' #{name} #{namespace} '#{labels}' '#{annotations}' #{replicas}"
15
+ )
16
+
17
+ raise stderr unless status.success?
18
+
19
+ stdout
20
+ end
21
+
22
+ def get_service(devfile, name, namespace, labels, annotations)
23
+ stdout, stderr, status = Open3.capture3(
24
+ "#{FILE_PATH} service '#{devfile}' #{name} #{namespace} '#{labels}' '#{annotations}'"
25
+ )
26
+
27
+ raise stderr unless status.success?
28
+
29
+ stdout
30
+ end
31
+
32
+ def get_ingress(devfile, name, namespace, labels, annotations, domain_template, ingress_class)
33
+ stdout, stderr, status = Open3.capture3(
34
+ "#{FILE_PATH} ingress '#{devfile}' #{name} #{namespace} '#{labels}' '#{annotations}' #{domain_template} #{ingress_class}"
35
+ )
36
+
37
+ raise stderr unless status.success?
38
+
39
+ stdout
40
+ end
41
+
42
+ def get_all(devfile, name, namespace, labels, annotations, replicas, domain_template, ingress_class)
43
+ stdout, stderr, status = Open3.capture3(
44
+ "#{FILE_PATH} all '#{devfile}' #{name} #{namespace} '#{labels}' '#{annotations}' #{replicas} #{domain_template} #{ingress_class}"
45
+ )
46
+
47
+ raise stderr unless status.success?
48
+
49
+ stdout
50
+ end
51
+
52
+ def flatten(devfile)
53
+ stdout, stderr, status = Open3.capture3("#{FILE_PATH} flatten '#{devfile}'")
54
+
55
+ raise stderr unless status.success?
56
+
57
+ stdout
58
+ end
59
+ end
60
+ end
61
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devfile
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5.pre.alpha1
5
+ platform: x86_64-linux
6
+ authors:
7
+ - GitLab
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-03-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Library used to generate kubernetes manifests from a Devfile.
14
+ email: spatnaik@gitlab.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - bin/devfile
20
+ - ext/devfile.go
21
+ - ext/go.mod
22
+ - ext/go.sum
23
+ - ext/main.go
24
+ - ext/volume.go
25
+ - lib/devfile.rb
26
+ homepage: https://gitlab.com
27
+ licenses:
28
+ - MIT
29
+ metadata:
30
+ source_code_uri: https://gitlab.com/gitlab-org/remote-development/devfile-gem
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '2.7'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">"
43
+ - !ruby/object:Gem::Version
44
+ version: 1.3.1
45
+ requirements: []
46
+ rubygems_version: 3.2.33
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: Parse and generate kubernetes manifests from a Devfile
50
+ test_files: []