devfile 0.0.9.pre.alpha1-aarch64-linux → 0.0.26.pre.alpha1-aarch64-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (9) hide show
  1. checksums.yaml +4 -4
  2. data/bin/devfile +0 -0
  3. data/ext/devfile.go +128 -13
  4. data/ext/go.mod +84 -69
  5. data/ext/go.sum +242 -879
  6. data/ext/main.go +49 -9
  7. data/ext/volume.go +74 -66
  8. data/lib/devfile.rb +27 -29
  9. metadata +11 -8
data/ext/main.go CHANGED
@@ -30,6 +30,8 @@ func main() {
30
30
  content, err = getService(devfile, args[3], args[4], args[5], args[6])
31
31
  case "ingress":
32
32
  content, err = getIngress(devfile, args[3], args[4], args[5], args[6], args[7], args[8])
33
+ case "pvc":
34
+ content, err = getPVC(devfile, args[3], args[4], args[5], args[6])
33
35
  case "all":
34
36
  content, err = getAll(devfile, args[3], args[4], args[5], args[6], args[7], args[8], args[9])
35
37
  case "flatten":
@@ -62,8 +64,8 @@ func getDeployment(devfile, name, namespace, labelsStr, annotationsStr, replicas
62
64
  if err != nil {
63
65
  return "", err
64
66
  }
65
- if exists == false {
66
- return "", err
67
+ if !exists {
68
+ return "", nil
67
69
  }
68
70
  labels, err := unmarshalKeyValuePair(labelsStr)
69
71
  if err != nil {
@@ -97,8 +99,8 @@ func getService(devfile, name, namespace, labelsStr, annotationsStr string) (str
97
99
  if err != nil {
98
100
  return "", err
99
101
  }
100
- if exists == false {
101
- return "", err
102
+ if !exists {
103
+ return "", nil
102
104
  }
103
105
  labels, err := unmarshalKeyValuePair(labelsStr)
104
106
  if err != nil {
@@ -128,8 +130,8 @@ func getIngress(devfile, name, namespace, labelsStr, annotationsStr, domainTempl
128
130
  if err != nil {
129
131
  return "", err
130
132
  }
131
- if exists == false {
132
- return "", err
133
+ if !exists {
134
+ return "", nil
133
135
  }
134
136
  labels, err := unmarshalKeyValuePair(labelsStr)
135
137
  if err != nil {
@@ -155,7 +157,7 @@ func getIngress(devfile, name, namespace, labelsStr, annotationsStr, domainTempl
155
157
  return content, nil
156
158
  }
157
159
 
158
- func getAll(devfile string, name, namespace, labelsStr, annotationsStr, replicas, domainTemplate, ingressClass string) (string, error) {
160
+ func getPVC(devfile, name, namespace, labelsStr, annotationsStr string) (string, error) {
159
161
  d, err := parseDevfile(devfile)
160
162
  if err != nil {
161
163
  return "", err
@@ -164,9 +166,44 @@ func getAll(devfile string, name, namespace, labelsStr, annotationsStr, replicas
164
166
  if err != nil {
165
167
  return "", err
166
168
  }
167
- if exists == false {
169
+ if !exists {
170
+ return "", nil
171
+ }
172
+ labels, err := unmarshalKeyValuePair(labelsStr)
173
+ if err != nil {
174
+ return "", err
175
+ }
176
+ annotations, err := unmarshalKeyValuePair(annotationsStr)
177
+ if err != nil {
178
+ return "", err
179
+ }
180
+ pvcs, err := d.getPVC(name, namespace, labels, annotations)
181
+ if err != nil {
168
182
  return "", err
169
183
  }
184
+ var result []runtime.Object
185
+ for _, pvc := range pvcs {
186
+ result = append(result, pvc)
187
+ }
188
+ content, err := marshalResources(result)
189
+ if err != nil {
190
+ return "", err
191
+ }
192
+ return content, nil
193
+ }
194
+
195
+ func getAll(devfile string, name, namespace, labelsStr, annotationsStr, replicas, domainTemplate, ingressClass string) (string, error) {
196
+ d, err := parseDevfile(devfile)
197
+ if err != nil {
198
+ return "", err
199
+ }
200
+ exists, err := d.hasContainerComponents()
201
+ if err != nil {
202
+ return "", err
203
+ }
204
+ if !exists {
205
+ return "", nil
206
+ }
170
207
  labels, err := unmarshalKeyValuePair(labelsStr)
171
208
  if err != nil {
172
209
  return "", err
@@ -195,7 +232,10 @@ func flatten(devfile string) (string, error) {
195
232
  if err != nil {
196
233
  return "", err
197
234
  }
198
- flattenedDevfile := d.getFlattenedDevfileContent()
235
+ flattenedDevfile, err := d.getFlattenedDevfileContent()
236
+ if err != nil {
237
+ return "", err
238
+ }
199
239
  content, err := marshalDevfile(flattenedDevfile)
200
240
  if err != nil {
201
241
  return "", err
data/ext/volume.go CHANGED
@@ -1,79 +1,108 @@
1
1
  package main
2
2
 
3
3
  import (
4
- "fmt"
4
+ devfileApiV1Alpha2 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
5
5
  "github.com/devfile/library/v2/pkg/devfile/generator"
6
+ "github.com/devfile/library/v2/pkg/devfile/parser"
6
7
  "github.com/devfile/library/v2/pkg/devfile/parser/data/v2/common"
7
8
  corev1 "k8s.io/api/core/v1"
8
- "k8s.io/apimachinery/pkg/api/resource"
9
9
  "strings"
10
10
  )
11
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{})
12
+ // There's a bug in the devfile library
13
+ // When a container component which has events and commands attached to it, becomes a init container, the name is
14
+ // init container is a concatenation of component name, event/command.
15
+ // However, when generating containerNameToMountPaths, we are using the component name
16
+ // And in addVolumeMountToContainers, we are comparing the container name with a component name
17
+ // For init containers this will not match
18
+ // Temporary fix is to use a string prefix check in addVolumeMountToContainers and return the updatedAllContainers from
19
+ // getVolumesAndVolumeMounts
20
+ // TODO: This might not be a perfect fix because maybe a string prefix match can have undesirable effects.
21
+ // issue: https://gitlab.com/gitlab-org/gitlab/-/issues/408950
22
+
23
+ // getVolumesAndVolumeMounts gets the PVC volumes and updates the containers with the volume mounts.
24
+ func getVolumesAndVolumeMounts(devfileObj parser.DevfileObj, volumeParams generator.VolumeParams, options common.DevfileOptions) ([]corev1.Container, []corev1.Volume, error) {
25
+ options.ComponentOptions = common.ComponentOptions{
26
+ ComponentType: devfileApiV1Alpha2.ContainerComponentType,
27
+ }
28
+ containerComponents, err := devfileObj.Data.GetComponents(options)
14
29
  if err != nil {
15
- return nil, err
30
+ return nil, nil, err
31
+ }
32
+
33
+ options.ComponentOptions = common.ComponentOptions{
34
+ ComponentType: devfileApiV1Alpha2.VolumeComponentType,
16
35
  }
17
- volumeComponents, err := d.devfileObj.Data.GetDevfileVolumeComponents(common.DevfileOptions{})
36
+ volumeComponent, err := devfileObj.Data.GetComponents(options)
18
37
  if err != nil {
19
- return nil, err
38
+ return nil, nil, err
20
39
  }
21
40
 
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
41
+ var pvcVols []corev1.Volume
42
+ for volName, volInfo := range volumeParams.VolumeNameToVolumeInfo {
43
+ emptyDirVolume := false
44
+ for _, volumeComp := range volumeComponent {
45
+ if volumeComp.Name == volName && *volumeComp.Volume.Ephemeral {
46
+ emptyDirVolume = true
47
+ break
29
48
  }
30
- volumes = append(volumes, emptyDir)
49
+ }
50
+
51
+ // if `ephemeral=true`, a volume with emptyDir should be created
52
+ if emptyDirVolume {
53
+ pvcVols = append(pvcVols, getEmptyDirSource(volInfo.VolumeName))
31
54
  } 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))
55
+ pvcVols = append(pvcVols, getPVCSource(volInfo.VolumeName, volInfo.PVCName))
35
56
  }
57
+
36
58
  // containerNameToMountPaths is a map of the Devfile container name to their Devfile Volume Mount Paths for a given Volume Name
37
59
  containerNameToMountPaths := make(map[string][]string)
38
60
  for _, containerComp := range containerComponents {
39
61
  for _, volumeMount := range containerComp.Container.VolumeMounts {
40
62
  if volName == volumeMount.Name {
41
- containerNameToMountPaths[containerComp.Name] = append(containerNameToMountPaths[containerComp.Name], generator.GetVolumeMountPath(volumeMount))
63
+ containerNameToMountPaths[containerComp.Name] = append(containerNameToMountPaths[containerComp.Name], getVolumeMountPath(volumeMount))
42
64
  }
43
65
  }
44
66
  }
45
67
 
46
- addVolumeMountToContainers(containers, initContainers, volName, containerNameToMountPaths)
68
+ addVolumeMountToContainers(volumeParams.Containers, volInfo.VolumeName, containerNameToMountPaths)
47
69
  }
70
+ return volumeParams.Containers, pvcVols, nil
71
+ }
72
+
73
+ // getPVCSource gets a pvc type volume with the given volume name and pvc name.
74
+ func getPVCSource(volumeName, pvcName string) corev1.Volume {
48
75
 
49
- return volumes, nil
76
+ return corev1.Volume{
77
+ Name: volumeName,
78
+ VolumeSource: corev1.VolumeSource{
79
+ PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
80
+ ClaimName: pvcName,
81
+ },
82
+ },
83
+ }
50
84
  }
51
85
 
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) {
86
+ // getEmptyDirSource gets a volume with emptyDir
87
+ func getEmptyDirSource(volumeName string) corev1.Volume {
88
+ return corev1.Volume{
89
+ Name: volumeName,
90
+ VolumeSource: corev1.VolumeSource{
91
+ EmptyDir: &corev1.EmptyDirVolumeSource{},
92
+ },
93
+ }
94
+ }
56
95
 
96
+ // addVolumeMountToContainers adds the Volume Mounts in containerNameToMountPaths to the containers for a given volumeName.
97
+ // containerNameToMountPaths is a map of a container name to an array of its Mount Paths.
98
+ func addVolumeMountToContainers(containers []corev1.Container, volumeName string, containerNameToMountPaths map[string][]string) {
57
99
  for containerName, mountPaths := range containerNameToMountPaths {
58
100
  for i := range containers {
59
- if containers[i].Name == containerName {
101
+ if strings.HasPrefix(containers[i].Name, containerName) {
60
102
  for _, mountPath := range mountPaths {
61
103
  containers[i].VolumeMounts = append(containers[i].VolumeMounts, corev1.VolumeMount{
62
104
  Name: volumeName,
63
105
  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
106
  },
78
107
  )
79
108
  }
@@ -82,33 +111,12 @@ func addVolumeMountToContainers(containers []corev1.Container, initContainers []
82
111
  }
83
112
  }
84
113
 
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
- },
114
+ // getVolumeMountPath gets the volume mount's path.
115
+ func getVolumeMountPath(volumeMount devfileApiV1Alpha2.VolumeMount) string {
116
+ // if there is no volume mount path, default to volume mount name as per devfile schema
117
+ if volumeMount.Path == "" {
118
+ volumeMount.Path = "/" + volumeMount.Name
95
119
  }
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
120
 
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
121
+ return volumeMount.Path
114
122
  }
data/lib/devfile.rb CHANGED
@@ -4,58 +4,56 @@ require 'open3'
4
4
 
5
5
  # Module that works with the Devfile standard
6
6
  module Devfile
7
+ class CliError < StandardError; end
8
+
7
9
  # Set of services to parse a devfile and output k8s manifests
8
10
  class Parser
9
11
  FILE_PATH = File.expand_path('./../bin/devfile', File.dirname(__FILE__))
12
+ DEVFILE_GEMSPEC = Gem.loaded_specs['devfile']
13
+ SYSTEM_PLATFORM = "#{Gem::Platform.local.cpu}-#{Gem::Platform.local.os}"
10
14
 
11
15
  class << self
12
16
  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
17
+ call('deployment', devfile, name, namespace, labels, annotations, replicas)
20
18
  end
21
19
 
22
20
  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
21
+ call('service', devfile, name, namespace, labels, annotations)
30
22
  end
31
23
 
32
24
  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?
25
+ call('ingress', devfile, name, namespace, labels, annotations, domain_template, ingress_class)
26
+ end
38
27
 
39
- stdout
28
+ def get_pvc(devfile, name, namespace, labels, annotations)
29
+ call('deployment', devfile, name, namespace, labels, annotations)
40
30
  end
41
31
 
42
32
  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
33
+ call('all', devfile, name, namespace, labels, annotations, replicas, domain_template, ingress_class)
50
34
  end
51
35
 
52
36
  def flatten(devfile)
53
- stdout, stderr, status = Open3.capture3("#{FILE_PATH} flatten '#{devfile}'")
37
+ call('flatten', devfile)
38
+ end
39
+
40
+ private
54
41
 
55
- raise stderr unless status.success?
42
+ def call(*cmd)
43
+ warn_for_ruby_platform
44
+
45
+ stdout, stderr, status = Open3.capture3({}, FILE_PATH, *cmd.map(&:to_s))
46
+
47
+ raise(CliError, stderr) unless status.success?
56
48
 
57
49
  stdout
58
50
  end
51
+
52
+ def warn_for_ruby_platform
53
+ return unless DEVFILE_GEMSPEC && DEVFILE_GEMSPEC.platform == 'ruby' && SYSTEM_PLATFORM != 'arm64-darwin'
54
+
55
+ warn "devfile-gem only supports os: darwin and architecture: arm64 for 'ruby' platform"
56
+ end
59
57
  end
60
58
  end
61
59
  end
metadata CHANGED
@@ -1,17 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devfile
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9.pre.alpha1
4
+ version: 0.0.26.pre.alpha1
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - GitLab
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-18 00:00:00.000000000 Z
11
+ date: 2024-09-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Library used to generate kubernetes manifests from a Devfile.
14
- email: spatnaik@gitlab.com
14
+ email:
15
+ - cwoolley@gitlab.com
16
+ - vtak@gitlab.com
17
+ - spatnaik@gitlab.com
15
18
  executables: []
16
19
  extensions: []
17
20
  extra_rdoc_files: []
@@ -27,8 +30,8 @@ homepage: https://gitlab.com
27
30
  licenses:
28
31
  - MIT
29
32
  metadata:
30
- source_code_uri: https://gitlab.com/gitlab-org/remote-development/devfile-gem
31
- post_install_message:
33
+ source_code_uri: https://gitlab.com/gitlab-org/ruby/gems/devfile-gem
34
+ post_install_message:
32
35
  rdoc_options: []
33
36
  require_paths:
34
37
  - lib
@@ -43,8 +46,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
43
46
  - !ruby/object:Gem::Version
44
47
  version: 1.3.1
45
48
  requirements: []
46
- rubygems_version: 3.2.33
47
- signing_key:
49
+ rubygems_version: 3.4.19
50
+ signing_key:
48
51
  specification_version: 4
49
52
  summary: Parse and generate kubernetes manifests from a Devfile
50
53
  test_files: []