1 package devstate
2
3 import (
4 "errors"
5 "fmt"
6 "strings"
7
8 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
9 "github.com/devfile/api/v2/pkg/devfile"
10 "github.com/devfile/library/v2/pkg/devfile/parser/data/v2/common"
11 "k8s.io/utils/pointer"
12
13 . "github.com/redhat-developer/odo/pkg/apiserver-gen/go"
14 "github.com/redhat-developer/odo/pkg/libdevfile"
15 )
16
17 const (
18 SEPARATOR = ","
19 )
20
21
22 func (o *DevfileState) GetContent() (DevfileContent, error) {
23 err := o.Devfile.WriteYamlDevfile()
24 if err != nil {
25 return DevfileContent{}, errors.New("error writing file")
26 }
27 result, err := o.FS.ReadFile(o.Devfile.Ctx.GetAbsPath())
28 if err != nil {
29 return DevfileContent{}, errors.New("error reading file")
30 }
31
32 commands, err := o.getCommands()
33 if err != nil {
34 return DevfileContent{}, fmt.Errorf("error getting commands: %w", err)
35 }
36
37 containers, err := o.getContainers()
38 if err != nil {
39 return DevfileContent{}, errors.New("error getting containers")
40 }
41 images, err := o.getImages()
42 if err != nil {
43 return DevfileContent{}, errors.New("error getting images")
44 }
45
46 resources, err := o.getResources()
47 if err != nil {
48 return DevfileContent{}, errors.New("error getting Kubernetes resources")
49 }
50
51 volumes, err := o.getVolumes()
52 if err != nil {
53 return DevfileContent{}, errors.New("error getting volumes")
54 }
55
56 return DevfileContent{
57 Content: string(result),
58 Version: o.Devfile.Data.GetSchemaVersion(),
59 Commands: commands,
60 Containers: containers,
61 Images: images,
62 Resources: resources,
63 Volumes: volumes,
64 Events: o.getEvents(),
65 Metadata: o.getMetadata(),
66 }, nil
67 }
68
69 func (o *DevfileState) getMetadata() Metadata {
70 metadata := o.Devfile.Data.GetMetadata()
71 return Metadata{
72 Name: metadata.Name,
73 Version: metadata.Version,
74 DisplayName: metadata.DisplayName,
75 Description: metadata.Description,
76 Tags: strings.Join(metadata.Tags, SEPARATOR),
77 Architectures: joinArchitectures(metadata.Architectures),
78 Icon: metadata.Icon,
79 GlobalMemoryLimit: metadata.GlobalMemoryLimit,
80 ProjectType: metadata.ProjectType,
81 Language: metadata.Language,
82 Website: metadata.Website,
83 Provider: metadata.Provider,
84 SupportUrl: metadata.SupportUrl,
85 }
86 }
87
88 func joinArchitectures(architectures []devfile.Architecture) string {
89 strArchs := make([]string, len(architectures))
90 for i, arch := range architectures {
91 strArchs[i] = string(arch)
92 }
93 return strings.Join(strArchs, SEPARATOR)
94 }
95
96 func (o *DevfileState) getCommands() ([]Command, error) {
97 commands, err := o.Devfile.Data.GetCommands(common.DevfileOptions{})
98 if err != nil {
99 return nil, err
100 }
101 result := make([]Command, 0, len(commands))
102 for _, command := range commands {
103 newCommand := Command{
104 Name: command.Id,
105 Group: GetGroup(command),
106 Default: GetDefault(command),
107 }
108
109 if command.Exec != nil {
110 newCommand.Type = "exec"
111 newCommand.Exec = ExecCommand{
112 Component: command.Exec.Component,
113 CommandLine: command.Exec.CommandLine,
114 WorkingDir: command.Exec.WorkingDir,
115 HotReloadCapable: pointer.BoolDeref(command.Exec.HotReloadCapable, false),
116 }
117 }
118
119 if command.Apply != nil {
120 components, err := o.Devfile.Data.GetComponents(common.DevfileOptions{
121 FilterByName: command.Apply.Component,
122 })
123 if err != nil {
124 return nil, err
125 }
126 if len(components) == 0 {
127 return nil, fmt.Errorf("component %q not found", command.Apply.Component)
128 }
129 component := components[0]
130 if component.Kubernetes != nil || component.Openshift != nil {
131 newCommand.Type = "apply"
132 newCommand.Apply = ApplyCommand{
133 Component: command.Apply.Component,
134 }
135 }
136 if component.Image != nil {
137 newCommand.Type = "image"
138 newCommand.Image = ImageCommand{
139 Component: command.Apply.Component,
140 }
141 }
142 }
143
144 if command.Composite != nil {
145 newCommand.Type = "composite"
146 newCommand.Composite = CompositeCommand{
147 Commands: command.Composite.Commands,
148 Parallel: pointer.BoolDeref(command.Composite.Parallel, false),
149 }
150 }
151 result = append(result, newCommand)
152 }
153 return result, nil
154 }
155
156 func (o *DevfileState) getContainers() ([]Container, error) {
157 containers, err := o.Devfile.Data.GetComponents(common.DevfileOptions{
158 ComponentOptions: common.ComponentOptions{
159 ComponentType: v1alpha2.ContainerComponentType,
160 },
161 })
162 if err != nil {
163 return nil, err
164 }
165 result := make([]Container, 0, len(containers))
166 for _, container := range containers {
167 result = append(result, Container{
168 Name: container.Name,
169 Image: container.ComponentUnion.Container.Image,
170 Command: container.ComponentUnion.Container.Command,
171 Args: container.ComponentUnion.Container.Args,
172 MemoryRequest: container.ComponentUnion.Container.MemoryRequest,
173 MemoryLimit: container.ComponentUnion.Container.MemoryLimit,
174 CpuRequest: container.ComponentUnion.Container.CpuRequest,
175 CpuLimit: container.ComponentUnion.Container.CpuLimit,
176 VolumeMounts: o.getVolumeMounts(container.Container.Container),
177 Annotation: o.getAnnotation(container.Container.Annotation),
178 Endpoints: o.getEndpoints(container.Container.Endpoints),
179 Env: o.getEnv(container.Container.Env),
180 ConfigureSources: container.Container.MountSources != nil,
181 MountSources: pointer.BoolDeref(container.Container.MountSources, true),
182 SourceMapping: container.Container.SourceMapping,
183 })
184 }
185 return result, nil
186 }
187
188 func (o *DevfileState) getVolumeMounts(container v1alpha2.Container) []VolumeMount {
189 result := make([]VolumeMount, 0, len(container.VolumeMounts))
190 for _, vm := range container.VolumeMounts {
191 result = append(result, VolumeMount{
192 Name: vm.Name,
193 Path: vm.Path,
194 })
195 }
196 return result
197 }
198
199 func (o *DevfileState) getAnnotation(annotation *v1alpha2.Annotation) Annotation {
200 if annotation == nil {
201 return Annotation{}
202 }
203 return Annotation{
204 Deployment: annotation.Deployment,
205 Service: annotation.Service,
206 }
207 }
208
209 func (o *DevfileState) getEndpoints(endpoints []v1alpha2.Endpoint) []Endpoint {
210 result := make([]Endpoint, 0, len(endpoints))
211 for _, ep := range endpoints {
212 result = append(result, Endpoint{
213 Name: ep.Name,
214 Exposure: string(ep.Exposure),
215 Path: ep.Path,
216 Protocol: string(ep.Protocol),
217 Secure: pointer.BoolDeref(ep.Secure, false),
218 TargetPort: int32(ep.TargetPort),
219 })
220 }
221 return result
222 }
223
224 func (o *DevfileState) getEnv(envs []v1alpha2.EnvVar) []Env {
225 result := make([]Env, 0, len(envs))
226 for _, env := range envs {
227 result = append(result, Env{
228 Name: env.Name,
229 Value: env.Value,
230 })
231 }
232 return result
233 }
234
235 func (o *DevfileState) getImages() ([]Image, error) {
236 allApplyCommands, err := o.Devfile.Data.GetCommands(common.DevfileOptions{
237 CommandOptions: common.CommandOptions{
238 CommandType: v1alpha2.ApplyCommandType,
239 },
240 })
241 if err != nil {
242 return nil, err
243 }
244
245 images, err := o.Devfile.Data.GetComponents(common.DevfileOptions{
246 ComponentOptions: common.ComponentOptions{
247 ComponentType: v1alpha2.ImageComponentType,
248 },
249 })
250 if err != nil {
251 return nil, err
252 }
253 result := make([]Image, 0, len(images))
254 for _, image := range images {
255 result = append(result, Image{
256 Name: image.Name,
257 ImageName: image.Image.ImageName,
258 Args: image.Image.Dockerfile.Args,
259 BuildContext: image.Image.Dockerfile.BuildContext,
260 RootRequired: pointer.BoolDeref(image.Image.Dockerfile.RootRequired, false),
261 Uri: image.Image.Dockerfile.Uri,
262 AutoBuild: getThreeState(image.Image.AutoBuild),
263 Orphan: !libdevfile.IsComponentReferenced(allApplyCommands, image.Name),
264 })
265 }
266 return result, nil
267 }
268
269 func getThreeState(v *bool) string {
270 if v == nil {
271 return "undefined"
272 }
273 if *v {
274 return "always"
275 }
276 return "never"
277 }
278
279 func (o *DevfileState) getResources() ([]Resource, error) {
280 allApplyCommands, err := o.Devfile.Data.GetCommands(common.DevfileOptions{
281 CommandOptions: common.CommandOptions{
282 CommandType: v1alpha2.ApplyCommandType,
283 },
284 })
285 if err != nil {
286 return nil, err
287 }
288
289 resources, err := o.Devfile.Data.GetComponents(common.DevfileOptions{
290 ComponentOptions: common.ComponentOptions{
291 ComponentType: v1alpha2.KubernetesComponentType,
292 },
293 })
294 if err != nil {
295 return nil, err
296 }
297 result := make([]Resource, 0, len(resources))
298 for _, resource := range resources {
299 result = append(result, Resource{
300 Name: resource.Name,
301 Inlined: resource.ComponentUnion.Kubernetes.Inlined,
302 Uri: resource.ComponentUnion.Kubernetes.Uri,
303 DeployByDefault: getThreeState(resource.ComponentUnion.Kubernetes.DeployByDefault),
304 Orphan: !libdevfile.IsComponentReferenced(allApplyCommands, resource.Name),
305 })
306 }
307 return result, nil
308 }
309
310 func (o *DevfileState) getVolumes() ([]Volume, error) {
311 volumes, err := o.Devfile.Data.GetComponents(common.DevfileOptions{
312 ComponentOptions: common.ComponentOptions{
313 ComponentType: v1alpha2.VolumeComponentType,
314 },
315 })
316 if err != nil {
317 return nil, err
318 }
319 result := make([]Volume, 0, len(volumes))
320 for _, volume := range volumes {
321 result = append(result, Volume{
322 Name: volume.Name,
323 Ephemeral: pointer.BoolDeref(volume.Volume.Ephemeral, false),
324 Size: volume.Volume.Size,
325 })
326 }
327 return result, nil
328 }
329
330 func (o *DevfileState) getEvents() Events {
331 events := o.Devfile.Data.GetEvents()
332 return Events{
333 PreStart: events.PreStart,
334 PostStart: events.PostStart,
335 PreStop: events.PreStop,
336 PostStop: events.PostStop,
337 }
338 }
339
View as plain text