-
Notifications
You must be signed in to change notification settings - Fork 36
Feature: pod security admission #165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
614deae
ffdff05
e68438e
800b0c1
d93f82c
63502cd
e342737
faef587
2eeebfe
497d2a0
d797fca
91e86b5
5985a28
2239fa9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,7 @@ jobs: | |
- name: Setup Go environment | ||
uses: actions/[email protected] | ||
with: | ||
go-version: 1.16 | ||
go-version: 1.19 | ||
id: go | ||
|
||
- name: Check out code into the Go module directory | ||
|
@@ -45,7 +45,7 @@ jobs: | |
|
||
- name: Check license | ||
run: | | ||
go get github.com/google/addlicense@latest | ||
go install github.com/google/addlicense@latest | ||
git reset HEAD --hard | ||
make check_license | ||
if [[ $? != 0 ]] | ||
|
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -16,6 +16,7 @@ | |||
package generator | ||||
|
||||
import ( | ||||
"errors" | ||||
"fmt" | ||||
|
||||
"github.com/devfile/api/v2/pkg/attributes" | ||||
|
@@ -34,6 +35,7 @@ import ( | |||
networkingv1 "k8s.io/api/networking/v1" | ||||
"k8s.io/apimachinery/pkg/api/resource" | ||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
psaapi "k8s.io/pod-security-admission/api" | ||||
) | ||||
|
||||
const ( | ||||
|
@@ -74,6 +76,8 @@ func GetObjectMeta(name, namespace string, labels, annotations map[string]string | |||
} | ||||
|
||||
// GetContainers iterates through all container components, filters out init containers and returns corresponding containers | ||||
// | ||||
// Deprecated: in favor of GetPodTemplateSpec | ||||
func GetContainers(devfileObj parser.DevfileObj, options common.DevfileOptions) ([]corev1.Container, error) { | ||||
allContainers, err := getAllContainers(devfileObj, options) | ||||
if err != nil { | ||||
|
@@ -120,6 +124,8 @@ func GetContainers(devfileObj parser.DevfileObj, options common.DevfileOptions) | |||
} | ||||
|
||||
// GetInitContainers gets the init container for every preStart devfile event | ||||
// | ||||
// Deprecated: in favor of GetPodTemplateSpec | ||||
func GetInitContainers(devfileObj parser.DevfileObj) ([]corev1.Container, error) { | ||||
containers, err := getAllContainers(devfileObj, common.DevfileOptions{}) | ||||
if err != nil { | ||||
|
@@ -170,23 +176,93 @@ func GetInitContainers(devfileObj parser.DevfileObj) ([]corev1.Container, error) | |||
|
||||
// DeploymentParams is a struct that contains the required data to create a deployment object | ||||
type DeploymentParams struct { | ||||
TypeMeta metav1.TypeMeta | ||||
ObjectMeta metav1.ObjectMeta | ||||
InitContainers []corev1.Container | ||||
Containers []corev1.Container | ||||
TypeMeta metav1.TypeMeta | ||||
ObjectMeta metav1.ObjectMeta | ||||
// Deprecated: InitContainers, Containers and Volumes are deprecated and are replaced by PodTemplateSpec. | ||||
// A PodTemplateSpec value can be obtained calling GetPodTemplateSpec function, instead of calling GetContainers and GetInitContainers | ||||
InitContainers []corev1.Container | ||||
// Deprecated: see InitContainers | ||||
Containers []corev1.Container | ||||
// Deprecated: see InitContainers | ||||
Volumes []corev1.Volume | ||||
PodTemplateSpec *corev1.PodTemplateSpec | ||||
PodSelectorLabels map[string]string | ||||
Replicas *int32 | ||||
} | ||||
|
||||
// GetDeployment gets a deployment object | ||||
func GetDeployment(devfileObj parser.DevfileObj, deployParams DeploymentParams) (*appsv1.Deployment, error) { | ||||
|
||||
deploySpecParams := deploymentSpecParams{ | ||||
PodSelectorLabels: deployParams.PodSelectorLabels, | ||||
Replicas: deployParams.Replicas, | ||||
} | ||||
if deployParams.PodTemplateSpec == nil { | ||||
// Deprecated | ||||
podTemplateSpecParams := podTemplateSpecParams{ | ||||
ObjectMeta: deployParams.ObjectMeta, | ||||
InitContainers: deployParams.InitContainers, | ||||
Containers: deployParams.Containers, | ||||
Volumes: deployParams.Volumes, | ||||
} | ||||
podTemplateSpec, err := getPodTemplateSpec(podTemplateSpecParams) | ||||
if err != nil { | ||||
return nil, err | ||||
} | ||||
deploySpecParams.PodTemplateSpec = *podTemplateSpec | ||||
} else { | ||||
if len(deployParams.InitContainers) > 0 || | ||||
len(deployParams.Containers) > 0 || | ||||
len(deployParams.Volumes) > 0 { | ||||
return nil, errors.New("InitContainers, Containers and Volumes cannot be set when PodTemplateSpec is set in parameters") | ||||
} | ||||
|
||||
deploySpecParams.PodTemplateSpec = *deployParams.PodTemplateSpec | ||||
} | ||||
|
||||
containerAnnotations, err := getContainerAnnotations(devfileObj, common.DevfileOptions{}) | ||||
if err != nil { | ||||
return nil, err | ||||
} | ||||
deployParams.ObjectMeta.Annotations = mergeMaps(deployParams.ObjectMeta.Annotations, containerAnnotations.Deployment) | ||||
|
||||
deployment := &appsv1.Deployment{ | ||||
TypeMeta: deployParams.TypeMeta, | ||||
ObjectMeta: deployParams.ObjectMeta, | ||||
Spec: *getDeploymentSpec(deploySpecParams), | ||||
} | ||||
|
||||
return deployment, nil | ||||
} | ||||
|
||||
// PodTemplateParams is a struct that contains the required data to create a podtemplatespec object | ||||
type PodTemplateParams struct { | ||||
ObjectMeta metav1.ObjectMeta | ||||
// PodSecurityAdmissionPolicy is the policy to be respected by the created pod | ||||
// The pod will be patched, if necessary, to respect the policies | ||||
PodSecurityAdmissionPolicy psaapi.Policy | ||||
} | ||||
|
||||
// GetPodTemplateSpec returns a pod template | ||||
// The function: | ||||
// - iterates through all container components, filters out init containers and gets corresponding containers | ||||
// - gets the init container for every preStart devfile event | ||||
// - patches the pod template and containers to satisfy PodSecurityAdmissionPolicy | ||||
// - patches the pod template and containers to apply pod and container overrides | ||||
func GetPodTemplateSpec(devfileObj parser.DevfileObj, podTemplateParams PodTemplateParams) (*corev1.PodTemplateSpec, error) { | ||||
containers, err := GetContainers(devfileObj, common.DevfileOptions{}) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, the GetContainers/GetInitContainers could be removed later from the library interface, by renaming them as getContainers/getInitContainers |
||||
if err != nil { | ||||
return nil, err | ||||
} | ||||
initContainers, err := GetInitContainers(devfileObj) | ||||
if err != nil { | ||||
return nil, err | ||||
} | ||||
|
||||
podTemplateSpecParams := podTemplateSpecParams{ | ||||
ObjectMeta: deployParams.ObjectMeta, | ||||
InitContainers: deployParams.InitContainers, | ||||
Containers: deployParams.Containers, | ||||
Volumes: deployParams.Volumes, | ||||
ObjectMeta: podTemplateParams.ObjectMeta, | ||||
InitContainers: initContainers, | ||||
Containers: containers, | ||||
feloy marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
} | ||||
var globalAttributes attributes.Attributes | ||||
// attributes is not supported in versions less than 2.1.0, so we skip it | ||||
|
@@ -199,29 +275,74 @@ func GetDeployment(devfileObj parser.DevfileObj, deployParams DeploymentParams) | |||
if err != nil { | ||||
return nil, err | ||||
} | ||||
podTemplateSpec, err := getPodTemplateSpec(globalAttributes, components, podTemplateSpecParams) | ||||
|
||||
podTemplateSpec, err := getPodTemplateSpec(podTemplateSpecParams) | ||||
if err != nil { | ||||
return nil, err | ||||
} | ||||
deploySpecParams := deploymentSpecParams{ | ||||
PodTemplateSpec: *podTemplateSpec, | ||||
PodSelectorLabels: deployParams.PodSelectorLabels, | ||||
Replicas: deployParams.Replicas, | ||||
|
||||
podTemplateSpec, err = patchForPolicy(podTemplateSpec, podTemplateParams.PodSecurityAdmissionPolicy) | ||||
if err != nil { | ||||
return nil, err | ||||
} | ||||
|
||||
containerAnnotations, err := getContainerAnnotations(devfileObj, common.DevfileOptions{}) | ||||
if needsPodOverrides(globalAttributes, components) { | ||||
patchedPodTemplateSpec, err := applyPodOverrides(globalAttributes, components, podTemplateSpec) | ||||
if err != nil { | ||||
return nil, err | ||||
} | ||||
patchedPodTemplateSpec.ObjectMeta = podTemplateSpecParams.ObjectMeta | ||||
podTemplateSpec = patchedPodTemplateSpec | ||||
} | ||||
|
||||
podTemplateSpec.Spec.Containers, err = applyContainerOverrides(devfileObj, podTemplateSpec.Spec.Containers) | ||||
if err != nil { | ||||
return nil, err | ||||
} | ||||
podTemplateSpec.Spec.InitContainers, err = applyContainerOverrides(devfileObj, podTemplateSpec.Spec.InitContainers) | ||||
if err != nil { | ||||
return nil, err | ||||
} | ||||
deployParams.ObjectMeta.Annotations = mergeMaps(deployParams.ObjectMeta.Annotations, containerAnnotations.Deployment) | ||||
|
||||
deployment := &appsv1.Deployment{ | ||||
TypeMeta: deployParams.TypeMeta, | ||||
ObjectMeta: deployParams.ObjectMeta, | ||||
Spec: *getDeploymentSpec(deploySpecParams), | ||||
return podTemplateSpec, nil | ||||
} | ||||
|
||||
func applyContainerOverrides(devfileObj parser.DevfileObj, containers []corev1.Container) ([]corev1.Container, error) { | ||||
containerComponents, err := devfileObj.Data.GetComponents(common.DevfileOptions{ | ||||
ComponentOptions: common.ComponentOptions{ | ||||
ComponentType: v1.ContainerComponentType, | ||||
}, | ||||
}) | ||||
if err != nil { | ||||
return nil, err | ||||
} | ||||
|
||||
return deployment, nil | ||||
getContainerByName := func(name string) (*corev1.Container, bool) { | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you do not need to introduce a new function for this purpose.
DevfileOptions.FilterByName = <the containerName>
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you sure? |
||||
for _, container := range containers { | ||||
if container.Name == name { | ||||
return &container, true | ||||
} | ||||
} | ||||
return nil, false | ||||
} | ||||
|
||||
result := make([]corev1.Container, 0, len(containers)) | ||||
for _, comp := range containerComponents { | ||||
container, found := getContainerByName(comp.Name) | ||||
if !found { | ||||
continue | ||||
} | ||||
if comp.Attributes.Exists(ContainerOverridesAttribute) { | ||||
patched, err := containerOverridesHandler(comp, container) | ||||
if err != nil { | ||||
return nil, err | ||||
} | ||||
result = append(result, *patched) | ||||
} else { | ||||
result = append(result, *container) | ||||
} | ||||
} | ||||
return result, nil | ||||
} | ||||
|
||||
// PVCParams is a struct to create PVC | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we also need to update the Go version in
codecov.yml
? I can see that this workflow is not triggered on PRs, but only upon a push onmain
, which makes me think that this may no longer pass onmain
once this PR is merged.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, wondering if we should not update the version in
go.mod
to reflect this? This way, all calls to thesetup-go
action could simply use the version declared ingo.mod
(see https://github.com/actions/setup-go#getting-go-version-from-the-gomod-file). But I am not sure about the implications on consumers of the library if the Go version ingo.mod
is updated. This might be a different issue, that said..