devfile 0.0.9.pre.alpha1-aarch64-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.
- checksums.yaml +7 -0
- data/bin/devfile +0 -0
- data/ext/devfile.go +227 -0
- data/ext/go.mod +119 -0
- data/ext/go.sum +1568 -0
- data/ext/main.go +204 -0
- data/ext/volume.go +114 -0
- data/lib/devfile.rb +61 -0
- metadata +50 -0
data/ext/main.go
ADDED
@@ -0,0 +1,204 @@
|
|
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
|
+
func main() {
|
13
|
+
args := os.Args
|
14
|
+
|
15
|
+
if len(args) <= 1 {
|
16
|
+
fmt.Fprint(os.Stderr, "Function name and devfile are required")
|
17
|
+
os.Exit(1)
|
18
|
+
}
|
19
|
+
|
20
|
+
fnName := os.Args[1]
|
21
|
+
devfile := os.Args[2]
|
22
|
+
|
23
|
+
var content string
|
24
|
+
var err error
|
25
|
+
|
26
|
+
switch fnName {
|
27
|
+
case "deployment":
|
28
|
+
content, err = getDeployment(devfile, args[3], args[4], args[5], args[6], args[7])
|
29
|
+
case "service":
|
30
|
+
content, err = getService(devfile, args[3], args[4], args[5], args[6])
|
31
|
+
case "ingress":
|
32
|
+
content, err = getIngress(devfile, args[3], args[4], args[5], args[6], args[7], args[8])
|
33
|
+
case "all":
|
34
|
+
content, err = getAll(devfile, args[3], args[4], args[5], args[6], args[7], args[8], args[9])
|
35
|
+
case "flatten":
|
36
|
+
content, err = flatten(devfile)
|
37
|
+
}
|
38
|
+
|
39
|
+
if err != nil {
|
40
|
+
fmt.Fprint(os.Stderr, err)
|
41
|
+
os.Exit(1)
|
42
|
+
}
|
43
|
+
|
44
|
+
fmt.Print(content)
|
45
|
+
}
|
46
|
+
|
47
|
+
func unmarshalKeyValuePair(data string) (map[string]string, error) {
|
48
|
+
values := map[string]string{}
|
49
|
+
err := yaml.Unmarshal([]byte(data), &values)
|
50
|
+
if err != nil {
|
51
|
+
return nil, err
|
52
|
+
}
|
53
|
+
return values, err
|
54
|
+
}
|
55
|
+
|
56
|
+
func getDeployment(devfile, name, namespace, labelsStr, annotationsStr, replicas string) (string, error) {
|
57
|
+
d, err := parseDevfile(devfile)
|
58
|
+
if err != nil {
|
59
|
+
return "", err
|
60
|
+
}
|
61
|
+
exists, err := d.hasContainerComponents()
|
62
|
+
if err != nil {
|
63
|
+
return "", err
|
64
|
+
}
|
65
|
+
if exists == false {
|
66
|
+
return "", err
|
67
|
+
}
|
68
|
+
labels, err := unmarshalKeyValuePair(labelsStr)
|
69
|
+
if err != nil {
|
70
|
+
return "", err
|
71
|
+
}
|
72
|
+
annotations, err := unmarshalKeyValuePair(annotationsStr)
|
73
|
+
if err != nil {
|
74
|
+
return "", err
|
75
|
+
}
|
76
|
+
replicasInt, err := strconv.Atoi(replicas)
|
77
|
+
if err != nil {
|
78
|
+
return "", err
|
79
|
+
}
|
80
|
+
deployment, err := d.getDeployment(name, namespace, labels, annotations, replicasInt)
|
81
|
+
if err != nil {
|
82
|
+
return "", err
|
83
|
+
}
|
84
|
+
content, err := marshalResources([]runtime.Object{deployment})
|
85
|
+
if err != nil {
|
86
|
+
return "", err
|
87
|
+
}
|
88
|
+
return content, nil
|
89
|
+
}
|
90
|
+
|
91
|
+
func getService(devfile, name, namespace, labelsStr, annotationsStr string) (string, error) {
|
92
|
+
d, err := parseDevfile(devfile)
|
93
|
+
if err != nil {
|
94
|
+
return "", err
|
95
|
+
}
|
96
|
+
exists, err := d.hasContainerComponents()
|
97
|
+
if err != nil {
|
98
|
+
return "", err
|
99
|
+
}
|
100
|
+
if exists == false {
|
101
|
+
return "", err
|
102
|
+
}
|
103
|
+
labels, err := unmarshalKeyValuePair(labelsStr)
|
104
|
+
if err != nil {
|
105
|
+
return "", err
|
106
|
+
}
|
107
|
+
annotations, err := unmarshalKeyValuePair(annotationsStr)
|
108
|
+
if err != nil {
|
109
|
+
return "", err
|
110
|
+
}
|
111
|
+
service, err := d.getService(name, namespace, labels, annotations)
|
112
|
+
if err != nil {
|
113
|
+
return "", err
|
114
|
+
}
|
115
|
+
content, err := marshalResources([]runtime.Object{service})
|
116
|
+
if err != nil {
|
117
|
+
return "", err
|
118
|
+
}
|
119
|
+
return content, nil
|
120
|
+
}
|
121
|
+
|
122
|
+
func getIngress(devfile, name, namespace, labelsStr, annotationsStr, domainTemplate, ingressClass string) (string, error) {
|
123
|
+
d, err := parseDevfile(devfile)
|
124
|
+
if err != nil {
|
125
|
+
return "", err
|
126
|
+
}
|
127
|
+
exists, err := d.hasContainerComponents()
|
128
|
+
if err != nil {
|
129
|
+
return "", err
|
130
|
+
}
|
131
|
+
if exists == false {
|
132
|
+
return "", err
|
133
|
+
}
|
134
|
+
labels, err := unmarshalKeyValuePair(labelsStr)
|
135
|
+
if err != nil {
|
136
|
+
return "", err
|
137
|
+
}
|
138
|
+
annotations, err := unmarshalKeyValuePair(annotationsStr)
|
139
|
+
if err != nil {
|
140
|
+
return "", err
|
141
|
+
}
|
142
|
+
ingress, err := d.getIngress(name, namespace, labels, annotations, domainTemplate, ingressClass)
|
143
|
+
if err != nil {
|
144
|
+
return "", err
|
145
|
+
}
|
146
|
+
|
147
|
+
if ingress == nil {
|
148
|
+
return "", nil
|
149
|
+
}
|
150
|
+
|
151
|
+
content, err := marshalResources([]runtime.Object{ingress})
|
152
|
+
if err != nil {
|
153
|
+
return "", err
|
154
|
+
}
|
155
|
+
return content, nil
|
156
|
+
}
|
157
|
+
|
158
|
+
func getAll(devfile string, name, namespace, labelsStr, annotationsStr, replicas, domainTemplate, ingressClass string) (string, error) {
|
159
|
+
d, err := parseDevfile(devfile)
|
160
|
+
if err != nil {
|
161
|
+
return "", err
|
162
|
+
}
|
163
|
+
exists, err := d.hasContainerComponents()
|
164
|
+
if err != nil {
|
165
|
+
return "", err
|
166
|
+
}
|
167
|
+
if exists == false {
|
168
|
+
return "", err
|
169
|
+
}
|
170
|
+
labels, err := unmarshalKeyValuePair(labelsStr)
|
171
|
+
if err != nil {
|
172
|
+
return "", err
|
173
|
+
}
|
174
|
+
annotations, err := unmarshalKeyValuePair(annotationsStr)
|
175
|
+
if err != nil {
|
176
|
+
return "", err
|
177
|
+
}
|
178
|
+
replicasInt, err := strconv.Atoi(replicas)
|
179
|
+
if err != nil {
|
180
|
+
return "", err
|
181
|
+
}
|
182
|
+
resources, err := d.getAll(name, namespace, labels, annotations, replicasInt, domainTemplate, ingressClass)
|
183
|
+
if err != nil {
|
184
|
+
return "", err
|
185
|
+
}
|
186
|
+
content, err := marshalResources(resources)
|
187
|
+
if err != nil {
|
188
|
+
return "", err
|
189
|
+
}
|
190
|
+
return content, nil
|
191
|
+
}
|
192
|
+
|
193
|
+
func flatten(devfile string) (string, error) {
|
194
|
+
d, err := parseDevfile(devfile)
|
195
|
+
if err != nil {
|
196
|
+
return "", err
|
197
|
+
}
|
198
|
+
flattenedDevfile := d.getFlattenedDevfileContent()
|
199
|
+
content, err := marshalDevfile(flattenedDevfile)
|
200
|
+
if err != nil {
|
201
|
+
return "", err
|
202
|
+
}
|
203
|
+
return content, err
|
204
|
+
}
|
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.9.pre.alpha1
|
5
|
+
platform: aarch64-linux
|
6
|
+
authors:
|
7
|
+
- GitLab
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-03-18 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: []
|