Skip to content
/*
Licensed under the Apache License, Version 2.0 (the "License");
Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
https://www.gnu.org/licenses/agpl-3.0.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
......@@ -28,18 +28,73 @@ type Pod struct {
// Parameters parameters.Parameters `json:"parameters,omitempty"`
}
// PodSpec is the specification of the desired behavior of the Pod.
// It is a stripped down version of https://godoc.org/k8s.io/api/core/v1#PodSpec
// with only user definied specs
//
// Here we consider that a pod has a main container that is embedded in the PodSpec definition
//
// Extra and init containers can also be definied
//
// This is similar to the container / sidecar container pattern
//
// +kubebuilder:object:generate=true
type PodSpec struct {
*meta.ObjectMeta `json:"meta,omitempty"`
Resources corev1.ResourceRequirements `json:"resources,omitempty" protobuf:"bytes,8,opt,name=resources"`
SecurityContext *corev1.PodSecurityContext `json:"securityContext,omitempty" protobuf:"bytes,14,opt,name=securityContext"`
Affinity *corev1.Affinity `json:"affinity,omitempty"`
RestartPolicy corev1.RestartPolicy `json:"restartPolicy,omitempty"`
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
*meta.ObjectMeta `json:"meta,omitempty"`
Resources corev1.ResourceRequirements `json:"resources,omitempty" protobuf:"bytes,8,opt,name=resources"`
// SecurityContext holds pod-level security attributes and common container settings.
// Optional: Defaults to empty. See type description for default values of each field.
// +optional
SecurityContext *corev1.PodSecurityContext `json:"securityContext,omitempty" protobuf:"bytes,14,opt,name=securityContext"`
// If specified, the pod's scheduling constraints
// +optional
Affinity *corev1.Affinity `json:"affinity,omitempty"`
// Restart policy for all containers within the pod.
// One of Always, OnFailure, Never.
// Default to Always.
// More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy
// +optional
RestartPolicy corev1.RestartPolicy `json:"restartPolicy,omitempty"`
// If specified, the pod's tolerations.
// +optional
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
// NodeSelector is a selector which must be true for the pod to fit on a node.
// Selector which must match a node's labels for the pod to be scheduled on that node.
// More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
// +optional
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
container.Container `json:",inline"`
ExtraContainers []container.Container `json:"extraContainers,omitempty"`
InitContainers []container.Container `json:"initContainers,omitempty"`
// List of containers belonging to the pod.
// Containers cannot currently be added or removed.
// There must be at least one container in a Pod.
// Cannot be updated.
// +patchMergeKey=name
// +patchStrategy=merge
ExtraContainers []container.Container `json:"extraContainers,omitempty"`
// List of initialization containers belonging to the pod.
// Init containers are executed in order prior to containers being started. If any
// init container fails, the pod is considered to have failed and is handled according
// to its restartPolicy. The name for an init container or normal container must be
// unique among all containers.
// Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes.
// The resourceRequirements of an init container are taken into account during scheduling
// by finding the highest request/limit for each resource type, and then using the max of
// of that value or the sum of the normal containers. Limits are applied to init containers
// in a similar fashion.
// Init containers cannot currently be added or removed.
// Cannot be updated.
// More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
// +patchMergeKey=name
// +patchStrategy=merge
InitContainers []container.Container `json:"initContainers,omitempty"`
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
// in the case of docker, only DockerConfig type secrets are honored.
// More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod
// +optional
// +patchMergeKey=name
// +patchStrategy=merge
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
}
func (r *PodSpec) GetPodAffinity() *corev1.Affinity { return r.Affinity }
......@@ -56,8 +111,8 @@ func (o *PodSpec) Mutate(obj interfaces.Object) error {
}
func (spec *PodSpec) GetContainers() []container.Mutate {
if len(spec.Container.TemplateSpec.Name) == 0 {
spec.Container.TemplateSpec.Name = spec.ObjectMeta.GetComponent()
if len(spec.Container.ContainerSpec.Name) == 0 {
spec.Container.ContainerSpec.Name = spec.ObjectMeta.GetComponent()
}
containers := []container.Mutate{}
......
package pod_test
import (
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestPod(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Pod Suite")
}
package pod_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"k8s.libre.sh/meta"
container "k8s.libre.sh/objects/container"
. "k8s.libre.sh/objects/pod"
parameters "k8s.libre.sh/settings"
corev1 "k8s.io/api/core/v1"
)
var _ = Describe("Pod", func() {
Describe("Mutate Pod", func() {
Context("With a single container", func() {
It("should generate pod with single container", func() {
pod := Pod{
PodSpec: &PodSpec{
ObjectMeta: &meta.ObjectMeta{
Name: "test",
Namespace: "test",
// Labels:
},
// Resources: corev1.ResourceRequirements{},
// SecurityContext: &corev1.PodSecurityContext{},
// Affinity: &corev1.Affinity{},
// RestartPolicy: "restart",
// Tolerations: []corev1.Toleration{},
// NodeSelector: map[string]string{},
Container: container.Container{
TemplateSpec: &container.TemplateSpec{
Name: "mycontainer",
},
Settings: parameters.Settings{
// TODO FIX PARAMETERS HAS TO BE INITIALIZE OR NIL POINTER RECEIVER ERROR
// ENVFROM & ENV returns empty array it should return nil
Parameters: new(parameters.Parameters),
},
},
// ExtraContainers: []container.Container{},
// InitContainers: []container.Container{},
},
}
// initialObject := &corev1.Pod{
// Spec: corev1.PodSpec{
// Containers: []corev1.Container{
// corev1.Container{
// Name: "mycontainer",
// },
// },
// },
// }
initialObject := &corev1.PodTemplateSpec{}
expectedObj := corev1.PodSpec{
Containers: []corev1.Container{
corev1.Container{
Name: "mycontainer",
},
},
}
err := MutatePod(pod, initialObject)
Expect(initialObject.Spec).To(Equal(expectedObj))
Expect(err).NotTo(HaveOccurred())
})
})
})
})
......@@ -93,6 +93,11 @@ func (in *PodSpec) DeepCopyInto(out *PodSpec) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.ImagePullSecrets != nil {
in, out := &in.ImagePullSecrets, &out.ImagePullSecrets
*out = make([]v1.LocalObjectReference, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodSpec.
......
/*
Licensed under the Apache License, Version 2.0 (the "License");
Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
https://www.gnu.org/licenses/agpl-3.0.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
......@@ -16,6 +16,8 @@ limitations under the License.
package secret
import (
"strings"
corev1 "k8s.io/api/core/v1"
meta "k8s.libre.sh/meta"
)
......@@ -28,20 +30,28 @@ func MutateSecret(r Mutate, obj *corev1.Secret, m meta.Meta) error {
data := r.GetData()
genParams := strings.Split(obj.ObjectMeta.Annotations["settings.k8s.libre.sh/generate"], ",")
for _, p := range genParams {
delete(data, p)
}
if len(obj.Data) == 0 {
obj.Data = make(map[string][]byte, len(data))
}
if len(data) > 0 {
for k, v := range data {
// TODO IMPROVE SECRET GENERATION CYCLE
if len(obj.Data[k]) == 0 {
obj.Data[k] = []byte(v)
/* // TODO TOFIX IMPROVE SECRET GENERATION CYCLE, only generated secrets should not be updated unless asked for
if len(obj.Data[k]) == 0 {
obj.Data[k] = []byte(v)
}
} */
obj.Data[k] = []byte(v)
}
}
// TOD TO FIX
meta.MutateMeta(m, obj)
return nil
......
/*
Licensed under the Apache License, Version 2.0 (the "License");
Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
https://www.gnu.org/licenses/agpl-3.0.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
......@@ -16,9 +16,9 @@ limitations under the License.
package secret
import (
settings "k8s.libre.sh/application/settings/parameters"
interfaces "k8s.libre.sh/interfaces"
meta "k8s.libre.sh/meta"
settings "k8s.libre.sh/settings"
corev1 "k8s.io/api/core/v1"
)
......
......@@ -20,8 +20,8 @@ limitations under the License.
package secret
import (
"k8s.libre.sh/application/settings/parameters"
"k8s.libre.sh/meta"
"k8s.libre.sh/settings"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
......@@ -34,11 +34,11 @@ func (in *Secret) DeepCopyInto(out *Secret) {
}
if in.Parameters != nil {
in, out := &in.Parameters, &out.Parameters
*out = make(settings.Parameters, len(*in))
*out = make(parameters.Parameters, len(*in))
for i := range *in {
if (*in)[i] != nil {
in, out := &(*in)[i], &(*out)[i]
*out = new(settings.Parameter)
*out = new(parameters.Parameter)
**out = **in
}
}
......
/*
Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.gnu.org/licenses/agpl-3.0.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package service
import (
meta "k8s.libre.sh/meta"
corev1 "k8s.io/api/core/v1"
meta "k8s.libre.sh/meta"
)
type Mutate interface {
......
/*
Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.gnu.org/licenses/agpl-3.0.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package service
import (
interfaces "k8s.libre.sh/interfaces"
meta "k8s.libre.sh/meta"
settings "k8s.libre.sh/settings"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"
......@@ -23,8 +37,30 @@ type Service struct {
// +kubebuilder:object:generate=true
type ServiceSpec struct {
Ports []Port `json:"ports,omitempty"`
Type corev1.ServiceType `json:"type,omitempty"`
// The list of ports that are exposed by this service.
// More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
// +patchMergeKey=port
// +patchStrategy=merge
// +listType=map
// +listMapKey=port
// +listMapKey=protocol
Ports []Port `json:"ports,omitempty"`
// type determines how the Service is exposed. Defaults to ClusterIP. Valid
// options are ExternalName, ClusterIP, NodePort, and LoadBalancer.
// "ExternalName" maps to the specified externalName.
// "ClusterIP" allocates a cluster-internal IP address for load-balancing to
// endpoints. Endpoints are determined by the selector or if that is not
// specified, by manual construction of an Endpoints object. If clusterIP is
// "None", no virtual IP is allocated and the endpoints are published as a
// set of endpoints rather than a stable IP.
// "NodePort" builds on ClusterIP and allocates a port on every node which
// routes to the clusterIP.
// "LoadBalancer" builds on NodePort and creates an
// external load-balancer (if supported in the current cloud) which routes
// to the clusterIP.
// More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
// +optional
Type corev1.ServiceType `json:"type,omitempty"`
}
type Port struct {
......@@ -34,14 +70,6 @@ type Port struct {
// Ingress Ingress `json:"ingress,omitempty"`
}
// type Ingress struct {
// Path string `json:"ingress,omitempty"`
// Host Host `json:"host,omitempty"`
// TLS bool `json:"tls,omitempty"`
//}
func (o *Service) SetSettings(parameters settings.Parameters) {}
func (r *ServiceSpec) GetServiceType() corev1.ServiceType { return r.Type }
func (r *ServiceSpec) GetServicePorts() []corev1.ServicePort {
......@@ -73,7 +101,6 @@ func (p *Port) GetServicePort() corev1.ServicePort {
func (o *Service) Mutate(obj interfaces.Object) error {
MutateService(o, obj.(*corev1.Service), o.ObjectMeta)
meta.MutateMeta(o, obj)
// mutate.MutateMetaService(o, obj)
return nil
}
......
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package settings
type Interface interface {
// GetConfigParameters() *Parameters
// SetConfigParameters(*Parameters)
GetConfigRefs() []string
SetConfigRefs([]string)
GetParameters() *Parameters
SetParameters(*Parameters)
// GetSecretParameters() *Parameters
// SetSecretParameters(*Parameters)
GetSecretRefs() []string
SetSecretRefs([]string)
}
func MergeSettings(dependencies, settings Interface) Interface {
if settings == nil {
settings = dependencies
} else {
settings.SetConfigRefs(append(settings.GetConfigRefs(), dependencies.GetConfigRefs()...))
settings.SetSecretRefs(append(settings.GetSecretRefs(), dependencies.GetSecretRefs()...))
params := *settings.GetParameters()
if params == nil {
params = *dependencies.GetParameters()
} else {
for _, p := range *dependencies.GetParameters() {
params = append(params, p)
}
}
settings.SetParameters(&params)
}
return settings
}
/* type Env interface {
GetName() string // GetKey()
SetName(string) // GetKey()
GetValue() string
SetValue(string)
GetLocalObjectRef() string
SetLocalObjectRef(string)
GetFromKey() string // GetKey() if GetName() ??
SetFromKey(string) // GetKey() if GetName() ??
GetType() ParameterType
// GetMountType() MountType
} */
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package settings
import (
corev1 "k8s.io/api/core/v1"
)
type Settings struct {
*EnvFrom `json:",inline"`
*Parameters `json:"parameters,omitempty"`
}
// +kubebuilder:object:generate=true
type EnvFrom struct {
SecretRefs []string `json:"secretRefs,omitempty"`
ConfigRefs []string `json:"configRefs,omitempty"`
}
func (s *Settings) SetParameters(parameters *Parameters) {
s.Parameters = parameters
}
func (s *Settings) GetParameters() *Parameters {
if s.Parameters == nil {
s.Parameters = new(Parameters)
}
return s.Parameters
}
func (s *Settings) GetSecretRefs() []string {
if s.EnvFrom != nil {
return s.EnvFrom.SecretRefs
}
return nil
}
func (s *Settings) SetSecretRefs(refs []string) {
if s.EnvFrom == nil {
s.EnvFrom = new(EnvFrom)
}
s.SecretRefs = refs
}
func (s *Settings) GetConfigRefs() []string {
if s.EnvFrom != nil {
return s.EnvFrom.ConfigRefs
}
return nil
}
func (s *Settings) SetConfigRefs(refs []string) {
if s.EnvFrom == nil {
s.EnvFrom = new(EnvFrom)
}
s.ConfigRefs = refs
}
/*
type SecretParameters struct {
Refs []string `json:"configRefs,omitempty"`
*Parameters `json:"parameters,omitempty"`
}
func (s *Settings) GetEnvFrom() []corev1.EnvFromSource {
envFrom := []corev1.EnvFromSource{}
if len(s.Secrets.GetEnvFrom()) > 0 {
envFrom = append(envFrom, s.Secrets.GetEnvFrom()...)
}
if len(s.Parameters.GetEnvFrom()) > 0 {
envFrom = append(envFrom, s.Parameters.GetEnvFrom()...)
}
return envFrom
}
func (e *SecretParameters) GetEnvFrom() []corev1.EnvFromSource {
envFroms := []corev1.EnvFromSource{}
envFrom := corev1.EnvFromSource{}
if e != nil {
// if len(e.Refs) > 0 {
for _, ref := range e.Refs {
envFrom = corev1.EnvFromSource{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: ref,
},
},
}
envFroms = append(envFroms, envFrom)
}
// }
}
if len(envFroms) > 0 {
return envFroms
}
return nil
}
type ConfigParameters struct {
Refs []string `json:"configRefs,omitempty"`
*Parameters `json:"parameters,omitempty"`
}
func (e *ConfigParameters) GetEnvFrom() []corev1.EnvFromSource {
envFroms := []corev1.EnvFromSource{}
envFrom := corev1.EnvFromSource{}
if e != nil {
// if len(e.Refs) > 0 {
for _, ref := range e.Refs {
envFrom = corev1.EnvFromSource{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: ref,
},
},
}
envFroms = append(envFroms, envFrom)
}
// }
}
if len(envFroms) > 0 {
return envFroms
}
return nil
}
*/
func (e *EnvFrom) GetEnvFrom() []corev1.EnvFromSource {
envFroms := []corev1.EnvFromSource{}
envFrom := corev1.EnvFromSource{}
if e != nil {
if len(e.ConfigRefs) > 0 {
for _, configRef := range e.ConfigRefs {
envFrom = corev1.EnvFromSource{
ConfigMapRef: &corev1.ConfigMapEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: configRef,
},
},
}
envFroms = append(envFroms, envFrom)
}
}
if len(e.SecretRefs) > 0 {
for _, secretRef := range e.SecretRefs {
envFrom = corev1.EnvFromSource{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretRef,
},
},
}
envFroms = append(envFroms, envFrom)
}
}
}
if len(envFroms) > 0 {
return envFroms
}
return nil
}
// We need to manually change this autogenerated function as it is broken with Paramete drs type, its trying to do new([]*Parameter) instead of new(Parameters)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Settings) DeepCopyInto(out *Settings) {
*out = *in
if in.EnvFrom != nil {
in, out := &in.EnvFrom, &out.EnvFrom
*out = new(EnvFrom)
(*in).DeepCopyInto(*out)
}
if in.Parameters != nil {
in, out := &in.Parameters, &out.Parameters
*out = new(Parameters)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Settings.
func (in *Settings) DeepCopy() *Settings {
if in == nil {
return nil
}
out := new(Settings)
in.DeepCopyInto(out)
return out
}
/*
Licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.gnu.org/licenses/agpl-3.0.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package utils
// Uniquer returns a unique list of strings
func Unique(stringSlice []string) []string {
keys := make(map[string]bool)
list := []string{}
for _, entry := range stringSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return list
}