1616package generator
1717
1818import (
19+ "errors"
1920 "fmt"
2021
22+ "github.com/devfile/api/v2/pkg/attributes"
23+ "github.com/devfile/library/v2/pkg/devfile/parser/data"
24+
2125 v1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
2226 "github.com/devfile/library/v2/pkg/devfile/parser"
2327 "github.com/devfile/library/v2/pkg/devfile/parser/data/v2/common"
@@ -31,6 +35,7 @@ import (
3135 networkingv1 "k8s.io/api/networking/v1"
3236 "k8s.io/apimachinery/pkg/api/resource"
3337 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
38+ psaapi "k8s.io/pod-security-admission/api"
3439)
3540
3641const (
@@ -71,6 +76,8 @@ func GetObjectMeta(name, namespace string, labels, annotations map[string]string
7176}
7277
7378// GetContainers iterates through all container components, filters out init containers and returns corresponding containers
79+ //
80+ // Deprecated: in favor of GetPodTemplateSpec
7481func GetContainers (devfileObj parser.DevfileObj , options common.DevfileOptions ) ([]corev1.Container , error ) {
7582 allContainers , err := getAllContainers (devfileObj , options )
7683 if err != nil {
@@ -117,6 +124,8 @@ func GetContainers(devfileObj parser.DevfileObj, options common.DevfileOptions)
117124}
118125
119126// GetInitContainers gets the init container for every preStart devfile event
127+ //
128+ // Deprecated: in favor of GetPodTemplateSpec
120129func GetInitContainers (devfileObj parser.DevfileObj ) ([]corev1.Container , error ) {
121130 containers , err := getAllContainers (devfileObj , common.DevfileOptions {})
122131 if err != nil {
@@ -167,30 +176,49 @@ func GetInitContainers(devfileObj parser.DevfileObj) ([]corev1.Container, error)
167176
168177// DeploymentParams is a struct that contains the required data to create a deployment object
169178type DeploymentParams struct {
170- TypeMeta metav1.TypeMeta
171- ObjectMeta metav1.ObjectMeta
172- InitContainers []corev1.Container
173- Containers []corev1.Container
179+ TypeMeta metav1.TypeMeta
180+ ObjectMeta metav1.ObjectMeta
181+ // Deprecated: InitContainers, Containers and Volumes are deprecated and are replaced by PodTemplateSpec.
182+ // A PodTemplateSpec value can be obtained calling GetPodTemplateSpec function, instead of calling GetContainers and GetInitContainers
183+ InitContainers []corev1.Container
184+ // Deprecated: see InitContainers
185+ Containers []corev1.Container
186+ // Deprecated: see InitContainers
174187 Volumes []corev1.Volume
188+ PodTemplateSpec * corev1.PodTemplateSpec
175189 PodSelectorLabels map [string ]string
176190 Replicas * int32
177191}
178192
179193// GetDeployment gets a deployment object
180194func GetDeployment (devfileObj parser.DevfileObj , deployParams DeploymentParams ) (* appsv1.Deployment , error ) {
181195
182- podTemplateSpecParams := podTemplateSpecParams {
183- ObjectMeta : deployParams .ObjectMeta ,
184- InitContainers : deployParams .InitContainers ,
185- Containers : deployParams .Containers ,
186- Volumes : deployParams .Volumes ,
187- }
188-
189196 deploySpecParams := deploymentSpecParams {
190- PodTemplateSpec : * getPodTemplateSpec (podTemplateSpecParams ),
191197 PodSelectorLabels : deployParams .PodSelectorLabels ,
192198 Replicas : deployParams .Replicas ,
193199 }
200+ if deployParams .PodTemplateSpec == nil {
201+ // Deprecated
202+ podTemplateSpecParams := podTemplateSpecParams {
203+ ObjectMeta : deployParams .ObjectMeta ,
204+ InitContainers : deployParams .InitContainers ,
205+ Containers : deployParams .Containers ,
206+ Volumes : deployParams .Volumes ,
207+ }
208+ podTemplateSpec , err := getPodTemplateSpec (podTemplateSpecParams )
209+ if err != nil {
210+ return nil , err
211+ }
212+ deploySpecParams .PodTemplateSpec = * podTemplateSpec
213+ } else {
214+ if len (deployParams .InitContainers ) > 0 ||
215+ len (deployParams .Containers ) > 0 ||
216+ len (deployParams .Volumes ) > 0 {
217+ return nil , errors .New ("InitContainers, Containers and Volumes cannot be set when PodTemplateSpec is set in parameters" )
218+ }
219+
220+ deploySpecParams .PodTemplateSpec = * deployParams .PodTemplateSpec
221+ }
194222
195223 containerAnnotations , err := getContainerAnnotations (devfileObj , common.DevfileOptions {})
196224 if err != nil {
@@ -207,6 +235,116 @@ func GetDeployment(devfileObj parser.DevfileObj, deployParams DeploymentParams)
207235 return deployment , nil
208236}
209237
238+ // PodTemplateParams is a struct that contains the required data to create a podtemplatespec object
239+ type PodTemplateParams struct {
240+ ObjectMeta metav1.ObjectMeta
241+ // PodSecurityAdmissionPolicy is the policy to be respected by the created pod
242+ // The pod will be patched, if necessary, to respect the policies
243+ PodSecurityAdmissionPolicy psaapi.Policy
244+ }
245+
246+ // GetPodTemplateSpec returns a pod template
247+ // The function:
248+ // - iterates through all container components, filters out init containers and gets corresponding containers
249+ // - gets the init container for every preStart devfile event
250+ // - patches the pod template and containers to satisfy PodSecurityAdmissionPolicy
251+ // - patches the pod template and containers to apply pod and container overrides
252+ func GetPodTemplateSpec (devfileObj parser.DevfileObj , podTemplateParams PodTemplateParams ) (* corev1.PodTemplateSpec , error ) {
253+ containers , err := GetContainers (devfileObj , common.DevfileOptions {})
254+ if err != nil {
255+ return nil , err
256+ }
257+ initContainers , err := GetInitContainers (devfileObj )
258+ if err != nil {
259+ return nil , err
260+ }
261+
262+ podTemplateSpecParams := podTemplateSpecParams {
263+ ObjectMeta : podTemplateParams .ObjectMeta ,
264+ InitContainers : initContainers ,
265+ Containers : containers ,
266+ }
267+ var globalAttributes attributes.Attributes
268+ // attributes is not supported in versions less than 2.1.0, so we skip it
269+ if devfileObj .Data .GetSchemaVersion () > string (data .APISchemaVersion200 ) {
270+ // the only time GetAttributes will return an error is if DevfileSchemaVersion is 2.0.0, a case we've already covered;
271+ // so we'll skip checking for error here
272+ globalAttributes , _ = devfileObj .Data .GetAttributes ()
273+ }
274+ components , err := devfileObj .Data .GetDevfileContainerComponents (common.DevfileOptions {})
275+ if err != nil {
276+ return nil , err
277+ }
278+
279+ podTemplateSpec , err := getPodTemplateSpec (podTemplateSpecParams )
280+ if err != nil {
281+ return nil , err
282+ }
283+
284+ podTemplateSpec , err = patchForPolicy (podTemplateSpec , podTemplateParams .PodSecurityAdmissionPolicy )
285+ if err != nil {
286+ return nil , err
287+ }
288+
289+ if needsPodOverrides (globalAttributes , components ) {
290+ patchedPodTemplateSpec , err := applyPodOverrides (globalAttributes , components , podTemplateSpec )
291+ if err != nil {
292+ return nil , err
293+ }
294+ patchedPodTemplateSpec .ObjectMeta = podTemplateSpecParams .ObjectMeta
295+ podTemplateSpec = patchedPodTemplateSpec
296+ }
297+
298+ podTemplateSpec .Spec .Containers , err = applyContainerOverrides (devfileObj , podTemplateSpec .Spec .Containers )
299+ if err != nil {
300+ return nil , err
301+ }
302+ podTemplateSpec .Spec .InitContainers , err = applyContainerOverrides (devfileObj , podTemplateSpec .Spec .InitContainers )
303+ if err != nil {
304+ return nil , err
305+ }
306+
307+ return podTemplateSpec , nil
308+ }
309+
310+ func applyContainerOverrides (devfileObj parser.DevfileObj , containers []corev1.Container ) ([]corev1.Container , error ) {
311+ containerComponents , err := devfileObj .Data .GetComponents (common.DevfileOptions {
312+ ComponentOptions : common.ComponentOptions {
313+ ComponentType : v1 .ContainerComponentType ,
314+ },
315+ })
316+ if err != nil {
317+ return nil , err
318+ }
319+
320+ getContainerByName := func (name string ) (* corev1.Container , bool ) {
321+ for _ , container := range containers {
322+ if container .Name == name {
323+ return & container , true
324+ }
325+ }
326+ return nil , false
327+ }
328+
329+ result := make ([]corev1.Container , 0 , len (containers ))
330+ for _ , comp := range containerComponents {
331+ container , found := getContainerByName (comp .Name )
332+ if ! found {
333+ continue
334+ }
335+ if comp .Attributes .Exists (ContainerOverridesAttribute ) {
336+ patched , err := containerOverridesHandler (comp , container )
337+ if err != nil {
338+ return nil , err
339+ }
340+ result = append (result , * patched )
341+ } else {
342+ result = append (result , * container )
343+ }
344+ }
345+ return result , nil
346+ }
347+
210348// PVCParams is a struct to create PVC
211349type PVCParams struct {
212350 TypeMeta metav1.TypeMeta
0 commit comments