Add builder pattern
This builder pattern refactors things so that we can use the same code to generate manifests/etc. This means that if we make sure that we exclusively use those, we can do testing there and keep something common. Change-Id: Ibc39f9b9e3e21b18fb255ba2a67d2d8ba3b5c585
This commit is contained in:
parent
d03a182dbc
commit
cc5d82883c
@ -15,7 +15,9 @@ RUN go mod download
|
|||||||
# Copy the go source
|
# Copy the go source
|
||||||
COPY main.go main.go
|
COPY main.go main.go
|
||||||
COPY api/ api/
|
COPY api/ api/
|
||||||
|
COPY builders/ builders/
|
||||||
COPY controllers/ controllers/
|
COPY controllers/ controllers/
|
||||||
|
COPY utils/ utils/
|
||||||
COPY version/ version/
|
COPY version/ version/
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
|
37
builders/config_map.go
Executable file
37
builders/config_map.go
Executable file
@ -0,0 +1,37 @@
|
|||||||
|
package builders
|
||||||
|
|
||||||
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConfigMapBuilder defines the interface to build a ConfigMap
|
||||||
|
type ConfigMapBuilder struct {
|
||||||
|
obj *corev1.ConfigMap
|
||||||
|
owner metav1.Object
|
||||||
|
scheme *runtime.Scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigMap returns a new service builder
|
||||||
|
func ConfigMap(existing *corev1.ConfigMap, owner metav1.Object, scheme *runtime.Scheme) *ConfigMapBuilder {
|
||||||
|
existing.Data = map[string]string{}
|
||||||
|
|
||||||
|
return &ConfigMapBuilder{
|
||||||
|
obj: existing,
|
||||||
|
owner: owner,
|
||||||
|
scheme: scheme,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data sets a key inside this ConfigMap
|
||||||
|
func (cm *ConfigMapBuilder) Data(key, value string) *ConfigMapBuilder {
|
||||||
|
cm.obj.Data[key] = value
|
||||||
|
return cm
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build returns a complete ConfigMap object
|
||||||
|
func (cm *ConfigMapBuilder) Build() error {
|
||||||
|
return controllerutil.SetControllerReference(cm.owner, cm.obj, cm.scheme)
|
||||||
|
}
|
148
builders/container.go
Executable file
148
builders/container.go
Executable file
@ -0,0 +1,148 @@
|
|||||||
|
package builders
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/alecthomas/units"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContainerBuilder provides an interface to build containers
|
||||||
|
type ContainerBuilder struct {
|
||||||
|
obj *corev1.Container
|
||||||
|
securityContext *SecurityContextBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container returns a new container builder
|
||||||
|
func Container(name string, image string) *ContainerBuilder {
|
||||||
|
container := &corev1.Container{
|
||||||
|
Name: name,
|
||||||
|
Image: image,
|
||||||
|
ImagePullPolicy: corev1.PullAlways,
|
||||||
|
TerminationMessagePath: "/dev/termination-log",
|
||||||
|
TerminationMessagePolicy: corev1.TerminationMessageReadFile,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ContainerBuilder{
|
||||||
|
obj: container,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Args sets the arguments for that container
|
||||||
|
func (c *ContainerBuilder) Args(args ...string) *ContainerBuilder {
|
||||||
|
c.obj.Args = args
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecurityContext sets the SecurityContext for that container
|
||||||
|
func (c *ContainerBuilder) SecurityContext(SecurityContext *SecurityContextBuilder) *ContainerBuilder {
|
||||||
|
c.securityContext = SecurityContext
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Port appends a port to the container
|
||||||
|
func (c *ContainerBuilder) Port(name string, port int32) *ContainerBuilder {
|
||||||
|
c.obj.Ports = append(c.obj.Ports, v1.ContainerPort{
|
||||||
|
Name: name,
|
||||||
|
ContainerPort: port,
|
||||||
|
Protocol: corev1.ProtocolTCP,
|
||||||
|
})
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Volume appends a volume to the container
|
||||||
|
func (c *ContainerBuilder) Volume(name string, path string) *ContainerBuilder {
|
||||||
|
c.obj.VolumeMounts = append(c.obj.VolumeMounts, v1.VolumeMount{
|
||||||
|
Name: name,
|
||||||
|
MountPath: path,
|
||||||
|
})
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resources defines the resource configuration for the container
|
||||||
|
func (c *ContainerBuilder) Resources(cpu int64, memory int64, storage int64, factor float64) *ContainerBuilder {
|
||||||
|
memory = memory * int64(units.Mebibyte)
|
||||||
|
storage = storage * int64(units.Megabyte)
|
||||||
|
|
||||||
|
cpuLimit := int64(float64(cpu) * factor)
|
||||||
|
memoryLimit := int64(float64(memory) * factor)
|
||||||
|
storageLimit := int64(float64(storage) * factor)
|
||||||
|
|
||||||
|
c.obj.Resources = v1.ResourceRequirements{
|
||||||
|
Limits: v1.ResourceList{
|
||||||
|
v1.ResourceCPU: *resource.NewMilliQuantity(cpuLimit, resource.DecimalSI),
|
||||||
|
v1.ResourceMemory: *resource.NewQuantity(memoryLimit, resource.BinarySI),
|
||||||
|
v1.ResourceEphemeralStorage: *resource.NewQuantity(storageLimit, resource.DecimalSI),
|
||||||
|
},
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceCPU: *resource.NewMilliQuantity(cpu, resource.DecimalSI),
|
||||||
|
v1.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI),
|
||||||
|
v1.ResourceEphemeralStorage: *resource.NewQuantity(storage, resource.DecimalSI),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPProbe creates both a readiness and liveness probe with provided intervals
|
||||||
|
func (c *ContainerBuilder) HTTPProbe(port string, path string, readyInterval int32, liveInterval int32) *ContainerBuilder {
|
||||||
|
handler := v1.Handler{
|
||||||
|
HTTPGet: &v1.HTTPGetAction{
|
||||||
|
Path: path,
|
||||||
|
Port: intstr.FromString(port),
|
||||||
|
Scheme: v1.URISchemeHTTP,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Probe(handler, readyInterval, liveInterval)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PortProbe creates both a readiness and liveness probe with provided intervals
|
||||||
|
func (c *ContainerBuilder) PortProbe(port string, readyInterval int32, liveInterval int32) *ContainerBuilder {
|
||||||
|
handler := v1.Handler{
|
||||||
|
TCPSocket: &v1.TCPSocketAction{
|
||||||
|
Port: intstr.FromString(port),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Probe(handler, readyInterval, liveInterval)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Probe creates both a readiness and liveness probe based on a handler provided
|
||||||
|
func (c *ContainerBuilder) Probe(handler v1.Handler, readyInterval int32, liveInterval int32) *ContainerBuilder {
|
||||||
|
c.obj.ReadinessProbe = &v1.Probe{
|
||||||
|
Handler: handler,
|
||||||
|
InitialDelaySeconds: 0,
|
||||||
|
PeriodSeconds: readyInterval,
|
||||||
|
TimeoutSeconds: 1,
|
||||||
|
SuccessThreshold: 1,
|
||||||
|
FailureThreshold: 3,
|
||||||
|
}
|
||||||
|
c.obj.LivenessProbe = &v1.Probe{
|
||||||
|
Handler: handler,
|
||||||
|
InitialDelaySeconds: 0,
|
||||||
|
PeriodSeconds: liveInterval,
|
||||||
|
TimeoutSeconds: 1,
|
||||||
|
SuccessThreshold: 1,
|
||||||
|
FailureThreshold: 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build returns the object after making certain assertions
|
||||||
|
func (c *ContainerBuilder) Build() (corev1.Container, error) {
|
||||||
|
if c.securityContext == nil {
|
||||||
|
return corev1.Container{}, errors.New("missing security context")
|
||||||
|
}
|
||||||
|
securityContext, err := c.securityContext.Build()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return corev1.Container{}, err
|
||||||
|
}
|
||||||
|
c.obj.SecurityContext = &securityContext
|
||||||
|
return *c.obj, nil
|
||||||
|
}
|
59
builders/deployment.go
Executable file
59
builders/deployment.go
Executable file
@ -0,0 +1,59 @@
|
|||||||
|
package builders
|
||||||
|
|
||||||
|
import (
|
||||||
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeploymentBuilder defines the interface to build a deployment
|
||||||
|
type DeploymentBuilder struct {
|
||||||
|
obj *appsv1.Deployment
|
||||||
|
podTemplateSpec *PodTemplateSpecBuilder
|
||||||
|
owner metav1.Object
|
||||||
|
scheme *runtime.Scheme
|
||||||
|
labels map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deployment returns a new deployment builder
|
||||||
|
func Deployment(existing *appsv1.Deployment, owner metav1.Object, scheme *runtime.Scheme) *DeploymentBuilder {
|
||||||
|
return &DeploymentBuilder{
|
||||||
|
obj: existing,
|
||||||
|
labels: map[string]string{},
|
||||||
|
owner: owner,
|
||||||
|
scheme: scheme,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Labels specifies labels for the deployment
|
||||||
|
func (d *DeploymentBuilder) Labels(labels map[string]string) *DeploymentBuilder {
|
||||||
|
d.labels = labels
|
||||||
|
d.obj.ObjectMeta.Labels = d.labels
|
||||||
|
d.obj.Spec.Selector = &metav1.LabelSelector{MatchLabels: d.labels}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replicas defines the number of replicas
|
||||||
|
func (d *DeploymentBuilder) Replicas(replicas int32) *DeploymentBuilder {
|
||||||
|
d.obj.Spec.Replicas = pointer.Int32Ptr(replicas)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// PodTemplateSpec defines a builder for the pod template spec
|
||||||
|
func (d *DeploymentBuilder) PodTemplateSpec(podTemplateSpec *PodTemplateSpecBuilder) *DeploymentBuilder {
|
||||||
|
d.podTemplateSpec = podTemplateSpec
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build creates a final deployment objet
|
||||||
|
func (d *DeploymentBuilder) Build() error {
|
||||||
|
podTemplateSpec, err := d.podTemplateSpec.Labels(d.labels).Build()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.obj.Spec.Template = podTemplateSpec
|
||||||
|
return controllerutil.SetControllerReference(d.owner, d.obj, d.scheme)
|
||||||
|
}
|
74
builders/pod_spec.go
Executable file
74
builders/pod_spec.go
Executable file
@ -0,0 +1,74 @@
|
|||||||
|
package builders
|
||||||
|
|
||||||
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PodSpecBuilder is an interface for building a PodSpec
|
||||||
|
type PodSpecBuilder struct {
|
||||||
|
obj *corev1.PodSpec
|
||||||
|
containers []*ContainerBuilder
|
||||||
|
volumes []*VolumeBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
// PodSpec returns a builder object for a PodSpec
|
||||||
|
func PodSpec() *PodSpecBuilder {
|
||||||
|
podSpec := &corev1.PodSpec{
|
||||||
|
DNSPolicy: corev1.DNSClusterFirst,
|
||||||
|
RestartPolicy: corev1.RestartPolicyAlways,
|
||||||
|
SchedulerName: "default-scheduler",
|
||||||
|
// SecurityContext: &v1.PodSecurityContext{
|
||||||
|
// RunAsNonRoot: pointer.BoolPtr(true),
|
||||||
|
// },
|
||||||
|
TerminationGracePeriodSeconds: pointer.Int64Ptr(10),
|
||||||
|
}
|
||||||
|
|
||||||
|
return &PodSpecBuilder{
|
||||||
|
obj: podSpec,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Containers appends a container builder to the PodSpec
|
||||||
|
func (ps *PodSpecBuilder) Containers(c ...*ContainerBuilder) *PodSpecBuilder {
|
||||||
|
ps.containers = c
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Volumes appends a volume builder to the PodSpec
|
||||||
|
func (ps *PodSpecBuilder) Volumes(v ...*VolumeBuilder) *PodSpecBuilder {
|
||||||
|
ps.volumes = v
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeSelector defines a NodeSelector for PodSpec
|
||||||
|
func (ps *PodSpecBuilder) NodeSelector(selector map[string]string) *PodSpecBuilder {
|
||||||
|
ps.obj.NodeSelector = selector
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tolerations defines tolerations for PodSpec
|
||||||
|
func (ps *PodSpecBuilder) Tolerations(tolerations []v1.Toleration) *PodSpecBuilder {
|
||||||
|
ps.obj.Tolerations = tolerations
|
||||||
|
return ps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build generates an object ensuring that all sub-objects work
|
||||||
|
func (ps *PodSpecBuilder) Build() (corev1.PodSpec, error) {
|
||||||
|
for _, c := range ps.containers {
|
||||||
|
container, err := c.Build()
|
||||||
|
if err != nil {
|
||||||
|
return corev1.PodSpec{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ps.obj.Containers = append(ps.obj.Containers, container)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range ps.volumes {
|
||||||
|
volume := v.Build()
|
||||||
|
ps.obj.Volumes = append(ps.obj.Volumes, volume)
|
||||||
|
}
|
||||||
|
|
||||||
|
return *ps.obj, nil
|
||||||
|
}
|
46
builders/pod_template_spec.go
Executable file
46
builders/pod_template_spec.go
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
package builders
|
||||||
|
|
||||||
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PodTemplateSpecBuilder is an interface for building a PodTemplateSpecBuilder
|
||||||
|
type PodTemplateSpecBuilder struct {
|
||||||
|
obj *corev1.PodTemplateSpec
|
||||||
|
podSpec *PodSpecBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
// PodTemplateSpec returns a builder object for a PodTemplateSpec
|
||||||
|
func PodTemplateSpec() *PodTemplateSpecBuilder {
|
||||||
|
podTemplateSpec := &corev1.PodTemplateSpec{}
|
||||||
|
|
||||||
|
return &PodTemplateSpecBuilder{
|
||||||
|
obj: podTemplateSpec,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Labels sets up the labels for a PodTemplateSpec
|
||||||
|
func (pts *PodTemplateSpecBuilder) Labels(labels map[string]string) *PodTemplateSpecBuilder {
|
||||||
|
pts.obj.ObjectMeta = metav1.ObjectMeta{
|
||||||
|
Labels: labels,
|
||||||
|
}
|
||||||
|
return pts
|
||||||
|
}
|
||||||
|
|
||||||
|
// PodSpec points this builder to PodSpec builder
|
||||||
|
func (pts *PodTemplateSpecBuilder) PodSpec(podSpec *PodSpecBuilder) *PodTemplateSpecBuilder {
|
||||||
|
pts.podSpec = podSpec
|
||||||
|
return pts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build generates an object ensuring that all sub-objects work
|
||||||
|
func (pts *PodTemplateSpecBuilder) Build() (corev1.PodTemplateSpec, error) {
|
||||||
|
podSpec, err := pts.podSpec.Build()
|
||||||
|
if err != nil {
|
||||||
|
return corev1.PodTemplateSpec{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pts.obj.Spec = podSpec
|
||||||
|
return *pts.obj, nil
|
||||||
|
}
|
42
builders/security_context.go
Executable file
42
builders/security_context.go
Executable file
@ -0,0 +1,42 @@
|
|||||||
|
package builders
|
||||||
|
|
||||||
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SecurityContextBuilder defines the interface to build a securityContext
|
||||||
|
type SecurityContextBuilder struct {
|
||||||
|
obj *corev1.SecurityContext
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecurityContext returns a new SecurityContext builder
|
||||||
|
func SecurityContext() *SecurityContextBuilder {
|
||||||
|
securityContext := &corev1.SecurityContext{}
|
||||||
|
return &SecurityContextBuilder{
|
||||||
|
obj: securityContext,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunAsUser sets the RunAsUser inside this SecurityContext
|
||||||
|
func (sc *SecurityContextBuilder) RunAsUser(userID int64) *SecurityContextBuilder {
|
||||||
|
sc.obj.RunAsUser = pointer.Int64Ptr(userID)
|
||||||
|
return sc
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunAsGroup sets the RunAsGroup inside this SecurityContext
|
||||||
|
func (sc *SecurityContextBuilder) RunAsGroup(groupID int64) *SecurityContextBuilder {
|
||||||
|
sc.obj.RunAsGroup = pointer.Int64Ptr(groupID)
|
||||||
|
return sc
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunAsNonRoot sets the RunAsNonRoot inside this SecurityContext
|
||||||
|
func (sc *SecurityContextBuilder) RunAsNonRoot(flag bool) *SecurityContextBuilder {
|
||||||
|
sc.obj.RunAsNonRoot = pointer.BoolPtr(flag)
|
||||||
|
return sc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build returns a complete ConfigMap object
|
||||||
|
func (sc *SecurityContextBuilder) Build() (corev1.SecurityContext, error) {
|
||||||
|
return *sc.obj, nil
|
||||||
|
}
|
50
builders/service.go
Executable file
50
builders/service.go
Executable file
@ -0,0 +1,50 @@
|
|||||||
|
package builders
|
||||||
|
|
||||||
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServiceBuilder defines the interface to build a service
|
||||||
|
type ServiceBuilder struct {
|
||||||
|
obj *corev1.Service
|
||||||
|
owner metav1.Object
|
||||||
|
scheme *runtime.Scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service returns a new service builder
|
||||||
|
func Service(existing *corev1.Service, owner metav1.Object, scheme *runtime.Scheme) *ServiceBuilder {
|
||||||
|
existing.Spec.Ports = []corev1.ServicePort{}
|
||||||
|
|
||||||
|
return &ServiceBuilder{
|
||||||
|
obj: existing,
|
||||||
|
owner: owner,
|
||||||
|
scheme: scheme,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Port appends a port to the service
|
||||||
|
func (s *ServiceBuilder) Port(name string, port int32) *ServiceBuilder {
|
||||||
|
s.obj.Spec.Ports = append(s.obj.Spec.Ports, corev1.ServicePort{
|
||||||
|
Name: name,
|
||||||
|
Protocol: v1.ProtocolTCP,
|
||||||
|
Port: port,
|
||||||
|
TargetPort: intstr.FromString(name),
|
||||||
|
})
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Selector defines the service selectors
|
||||||
|
func (s *ServiceBuilder) Selector(labels map[string]string) *ServiceBuilder {
|
||||||
|
s.obj.Spec.Selector = labels
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build returns a complete Service object
|
||||||
|
func (s *ServiceBuilder) Build() error {
|
||||||
|
return controllerutil.SetControllerReference(s.owner, s.obj, s.scheme)
|
||||||
|
}
|
39
builders/volume.go
Executable file
39
builders/volume.go
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
package builders
|
||||||
|
|
||||||
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VolumeBuilder provides an interface to build volumes
|
||||||
|
type VolumeBuilder struct {
|
||||||
|
obj *corev1.Volume
|
||||||
|
}
|
||||||
|
|
||||||
|
// Volume returns a new volume builder
|
||||||
|
func Volume(name string) *VolumeBuilder {
|
||||||
|
volume := &corev1.Volume{
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &VolumeBuilder{
|
||||||
|
obj: volume,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromConfigMap sets the source of the volume from a ConfigMap
|
||||||
|
func (v *VolumeBuilder) FromConfigMap(name string) *VolumeBuilder {
|
||||||
|
v.obj.VolumeSource = corev1.VolumeSource{
|
||||||
|
ConfigMap: &corev1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: v1.LocalObjectReference{Name: name},
|
||||||
|
DefaultMode: pointer.Int32Ptr(420),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build returns the object after checking assertions
|
||||||
|
func (v *VolumeBuilder) Build() corev1.Volume {
|
||||||
|
return *v.obj
|
||||||
|
}
|
@ -1,2 +1,8 @@
|
|||||||
resources:
|
resources:
|
||||||
- manager.yaml
|
- manager.yaml
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
images:
|
||||||
|
- name: controller
|
||||||
|
newName: controller
|
||||||
|
newTag: latest
|
||||||
|
@ -5,22 +5,17 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/alecthomas/units"
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
|
||||||
"k8s.io/utils/pointer"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
|
||||||
|
|
||||||
infrastructurev1alpha1 "opendev.org/vexxhost/openstack-operator/api/v1alpha1"
|
infrastructurev1alpha1 "opendev.org/vexxhost/openstack-operator/api/v1alpha1"
|
||||||
"opendev.org/vexxhost/openstack-operator/version"
|
"opendev.org/vexxhost/openstack-operator/builders"
|
||||||
|
"opendev.org/vexxhost/openstack-operator/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// McrouterReconciler reconciles a Mcrouter object
|
// McrouterReconciler reconciles a Mcrouter object
|
||||||
@ -57,20 +52,17 @@ func (r *McrouterReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
|||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Namespace: req.Namespace,
|
Namespace: req.Namespace,
|
||||||
Name: fmt.Sprintf("mcrouter-%s", req.Name),
|
Name: fmt.Sprintf("mcrouter-%s", req.Name),
|
||||||
Labels: labels,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
op, err := controllerutil.CreateOrUpdate(ctx, r, configMap, func() error {
|
op, err := utils.CreateOrUpdate(ctx, r, configMap, func() error {
|
||||||
b, err := json.Marshal(mcrouter.Spec)
|
b, err := json.Marshal(mcrouter.Spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
configMap.Data = map[string]string{
|
return builders.ConfigMap(configMap, &mcrouter, r.Scheme).
|
||||||
"config.json": string(b),
|
Data("config.json", string(b)).
|
||||||
}
|
Build()
|
||||||
|
|
||||||
return controllerutil.SetControllerReference(&mcrouter, configMap, r.Scheme)
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
@ -82,133 +74,44 @@ func (r *McrouterReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
|||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Namespace: req.Namespace,
|
Namespace: req.Namespace,
|
||||||
Name: fmt.Sprintf("mcrouter-%s", req.Name),
|
Name: fmt.Sprintf("mcrouter-%s", req.Name),
|
||||||
Labels: labels,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
op, err = controllerutil.CreateOrUpdate(ctx, r, deployment, func() error {
|
op, err = utils.CreateOrUpdate(ctx, r, deployment, func() error {
|
||||||
if deployment.ObjectMeta.CreationTimestamp.IsZero() {
|
return builders.Deployment(deployment, &mcrouter, r.Scheme).
|
||||||
deployment.Spec.Selector = &metav1.LabelSelector{
|
Labels(labels).
|
||||||
MatchLabels: labels,
|
Replicas(2).
|
||||||
}
|
PodTemplateSpec(
|
||||||
}
|
builders.PodTemplateSpec().
|
||||||
|
PodSpec(
|
||||||
deployment.Spec.Replicas = pointer.Int32Ptr(2)
|
builders.PodSpec().
|
||||||
deployment.Spec.Template = corev1.PodTemplateSpec{
|
NodeSelector(mcrouter.Spec.NodeSelector).
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
Tolerations(mcrouter.Spec.Tolerations).
|
||||||
Labels: labels,
|
Containers(
|
||||||
},
|
builders.Container("mcrouter", "vexxhost/mcrouter:latest").
|
||||||
Spec: corev1.PodSpec{
|
Args("-p", "11211", "-f", "/data/config.json").
|
||||||
Containers: []corev1.Container{
|
Port("mcrouter", 11211).PortProbe("mcrouter", 10, 30).
|
||||||
{
|
Resources(500, 128, 500, 2).
|
||||||
Name: "mcrouter",
|
Volume("config", "/data").
|
||||||
Image: fmt.Sprintf("vexxhost/mcrouter:%s", version.Revision),
|
SecurityContext(
|
||||||
Args: []string{"-p", "11211", "-f", "/data/config.json"},
|
builders.SecurityContext().
|
||||||
Ports: []v1.ContainerPort{
|
RunAsUser(999).
|
||||||
{
|
RunAsGroup(999),
|
||||||
Name: "mcrouter",
|
),
|
||||||
ContainerPort: int32(11211),
|
builders.Container("exporter", "vexxhost/mcrouter_exporter:latest").
|
||||||
},
|
Args("-mcrouter.address", "localhost:11211").
|
||||||
},
|
Port("metrics", 9442).HTTPProbe("metrics", "/metrics", 10, 30).
|
||||||
VolumeMounts: []v1.VolumeMount{
|
Resources(500, 128, 500, 2).
|
||||||
{
|
SecurityContext(
|
||||||
Name: "config",
|
builders.SecurityContext().
|
||||||
MountPath: "/data",
|
RunAsUser(1001),
|
||||||
},
|
),
|
||||||
},
|
).
|
||||||
Resources: v1.ResourceRequirements{
|
Volumes(
|
||||||
Limits: v1.ResourceList{
|
builders.Volume("config").FromConfigMap(configMap.GetName()),
|
||||||
v1.ResourceCPU: *resource.NewMilliQuantity(1000, resource.DecimalSI),
|
),
|
||||||
v1.ResourceMemory: *resource.NewQuantity(int64(units.Mebibyte)*256, resource.BinarySI),
|
),
|
||||||
v1.ResourceEphemeralStorage: *resource.NewQuantity(int64(units.MB)*1000, resource.DecimalSI),
|
).
|
||||||
},
|
Build()
|
||||||
Requests: v1.ResourceList{
|
|
||||||
v1.ResourceCPU: *resource.NewMilliQuantity(100, resource.DecimalSI),
|
|
||||||
v1.ResourceMemory: *resource.NewQuantity(int64(units.Mebibyte)*128, resource.BinarySI),
|
|
||||||
v1.ResourceEphemeralStorage: *resource.NewQuantity(int64(units.MB)*500, resource.DecimalSI),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
StartupProbe: &v1.Probe{},
|
|
||||||
ReadinessProbe: &v1.Probe{
|
|
||||||
Handler: v1.Handler{
|
|
||||||
TCPSocket: &v1.TCPSocketAction{
|
|
||||||
Port: intstr.FromString("mcrouter"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PeriodSeconds: int32(10),
|
|
||||||
},
|
|
||||||
LivenessProbe: &v1.Probe{
|
|
||||||
Handler: v1.Handler{
|
|
||||||
TCPSocket: &v1.TCPSocketAction{
|
|
||||||
Port: intstr.FromString("mcrouter"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
InitialDelaySeconds: int32(15),
|
|
||||||
PeriodSeconds: int32(30),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "exporter",
|
|
||||||
Image: fmt.Sprintf("vexxhost/mcrouter_exporter:%s", version.Revision),
|
|
||||||
Args: []string{"-mcrouter.address", "localhost:11211"},
|
|
||||||
Ports: []v1.ContainerPort{
|
|
||||||
{
|
|
||||||
Name: "metrics",
|
|
||||||
ContainerPort: int32(9442),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Resources: v1.ResourceRequirements{
|
|
||||||
Limits: v1.ResourceList{
|
|
||||||
v1.ResourceCPU: *resource.NewMilliQuantity(1000, resource.DecimalSI),
|
|
||||||
v1.ResourceMemory: *resource.NewQuantity(int64(units.Mebibyte)*256, resource.BinarySI),
|
|
||||||
v1.ResourceEphemeralStorage: *resource.NewQuantity(int64(units.MB)*1000, resource.DecimalSI),
|
|
||||||
},
|
|
||||||
Requests: v1.ResourceList{
|
|
||||||
v1.ResourceCPU: *resource.NewMilliQuantity(100, resource.DecimalSI),
|
|
||||||
v1.ResourceMemory: *resource.NewQuantity(int64(units.Mebibyte)*128, resource.BinarySI),
|
|
||||||
v1.ResourceEphemeralStorage: *resource.NewQuantity(int64(units.MB)*500, resource.DecimalSI),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
StartupProbe: &v1.Probe{},
|
|
||||||
ReadinessProbe: &v1.Probe{
|
|
||||||
Handler: v1.Handler{
|
|
||||||
HTTPGet: &v1.HTTPGetAction{
|
|
||||||
Path: string("/metrics"),
|
|
||||||
Port: intstr.FromString("metrics"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
InitialDelaySeconds: int32(5),
|
|
||||||
PeriodSeconds: int32(10),
|
|
||||||
},
|
|
||||||
LivenessProbe: &v1.Probe{
|
|
||||||
Handler: v1.Handler{
|
|
||||||
HTTPGet: &v1.HTTPGetAction{
|
|
||||||
Path: string("/metrics"),
|
|
||||||
Port: intstr.FromString("metrics"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
InitialDelaySeconds: int32(15),
|
|
||||||
PeriodSeconds: int32(30),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Volumes: []corev1.Volume{
|
|
||||||
{
|
|
||||||
Name: "config",
|
|
||||||
VolumeSource: corev1.VolumeSource{
|
|
||||||
ConfigMap: &corev1.ConfigMapVolumeSource{
|
|
||||||
LocalObjectReference: v1.LocalObjectReference{Name: configMap.GetName()},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
NodeSelector: mcrouter.Spec.NodeSelector,
|
|
||||||
Tolerations: mcrouter.Spec.Tolerations,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return controllerutil.SetControllerReference(&mcrouter, deployment, r.Scheme)
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
@ -220,21 +123,13 @@ func (r *McrouterReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
|||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Namespace: req.Namespace,
|
Namespace: req.Namespace,
|
||||||
Name: fmt.Sprintf("mcrouter-%s", req.Name),
|
Name: fmt.Sprintf("mcrouter-%s", req.Name),
|
||||||
Labels: labels,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
op, err = controllerutil.CreateOrUpdate(ctx, r, service, func() error {
|
op, err = utils.CreateOrUpdate(ctx, r, service, func() error {
|
||||||
service.Spec.Type = corev1.ServiceTypeClusterIP
|
return builders.Service(service, &mcrouter, r.Scheme).
|
||||||
service.Spec.Ports = []v1.ServicePort{
|
Port("mcrouter", 11211).
|
||||||
{
|
Selector(labels).
|
||||||
Name: "mcrouter",
|
Build()
|
||||||
Port: int32(11211),
|
|
||||||
TargetPort: intstr.FromString("mcrouter"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
service.Spec.Selector = labels
|
|
||||||
|
|
||||||
return controllerutil.SetControllerReference(&mcrouter, service, r.Scheme)
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
|
@ -19,24 +19,21 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/alecthomas/units"
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
|
||||||
"k8s.io/utils/pointer"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||||
|
|
||||||
infrastructurev1alpha1 "opendev.org/vexxhost/openstack-operator/api/v1alpha1"
|
infrastructurev1alpha1 "opendev.org/vexxhost/openstack-operator/api/v1alpha1"
|
||||||
"opendev.org/vexxhost/openstack-operator/version"
|
"opendev.org/vexxhost/openstack-operator/builders"
|
||||||
|
"opendev.org/vexxhost/openstack-operator/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MemcachedReconciler reconciles a Memcached object
|
// MemcachedReconciler reconciles a Memcached object
|
||||||
@ -79,108 +76,37 @@ func (r *MemcachedReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
|||||||
Labels: labels,
|
Labels: labels,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
op, err := controllerutil.CreateOrUpdate(ctx, r, deployment, func() error {
|
op, err := utils.CreateOrUpdate(ctx, r, deployment, func() error {
|
||||||
if deployment.ObjectMeta.CreationTimestamp.IsZero() {
|
return builders.Deployment(deployment, &memcached, r.Scheme).
|
||||||
deployment.Spec.Selector = &metav1.LabelSelector{
|
Labels(labels).
|
||||||
MatchLabels: labels,
|
Replicas(2).
|
||||||
}
|
PodTemplateSpec(
|
||||||
}
|
builders.PodTemplateSpec().
|
||||||
|
Labels(labels).
|
||||||
deployment.Spec.Replicas = pointer.Int32Ptr(2)
|
PodSpec(
|
||||||
deployment.Spec.Template = corev1.PodTemplateSpec{
|
builders.PodSpec().
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
NodeSelector(memcached.Spec.NodeSelector).
|
||||||
Labels: labels,
|
Tolerations(memcached.Spec.Tolerations).
|
||||||
},
|
Containers(
|
||||||
Spec: corev1.PodSpec{
|
builders.Container("memcached", "vexxhost/memcached:latest").
|
||||||
Containers: []corev1.Container{
|
Args("-m", strconv.Itoa(size)).
|
||||||
{
|
Port("memcached", 11211).PortProbe("memcached", 10, 30).
|
||||||
Name: "memcached",
|
Resources(1000, int64(size), 500, 1.10).
|
||||||
Image: fmt.Sprintf("vexxhost/memcached:%s", version.Revision),
|
SecurityContext(
|
||||||
Args: []string{"-m", strconv.Itoa(size)},
|
builders.SecurityContext().
|
||||||
Ports: []v1.ContainerPort{
|
RunAsUser(1001),
|
||||||
{
|
),
|
||||||
Name: "memcached",
|
builders.Container("exporter", "vexxhost/memcached_exporter:latest").
|
||||||
ContainerPort: int32(11211),
|
Port("metrics", 9150).HTTPProbe("metrics", "/metrics", 10, 30).
|
||||||
},
|
Resources(500, 128, 500, 2).
|
||||||
},
|
SecurityContext(
|
||||||
Resources: v1.ResourceRequirements{
|
builders.SecurityContext().
|
||||||
Limits: v1.ResourceList{
|
RunAsUser(1001),
|
||||||
v1.ResourceCPU: *resource.NewMilliQuantity(1000, resource.DecimalSI),
|
),
|
||||||
v1.ResourceMemory: *resource.NewQuantity(int64(size)*int64(units.MiB)+int64(size)*102*int64(units.KiB), resource.BinarySI),
|
),
|
||||||
v1.ResourceEphemeralStorage: *resource.NewQuantity(int64(units.MB)*1000, resource.DecimalSI),
|
),
|
||||||
},
|
).
|
||||||
Requests: v1.ResourceList{
|
Build()
|
||||||
v1.ResourceCPU: *resource.NewMilliQuantity(100, resource.DecimalSI),
|
|
||||||
v1.ResourceMemory: *resource.NewQuantity(int64(size)*int64(units.MiB), resource.BinarySI),
|
|
||||||
v1.ResourceEphemeralStorage: *resource.NewQuantity(int64(units.MB)*500, resource.DecimalSI),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
StartupProbe: &v1.Probe{},
|
|
||||||
ReadinessProbe: &v1.Probe{
|
|
||||||
Handler: v1.Handler{
|
|
||||||
TCPSocket: &v1.TCPSocketAction{
|
|
||||||
Port: intstr.FromString("memcached"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PeriodSeconds: int32(10),
|
|
||||||
},
|
|
||||||
LivenessProbe: &v1.Probe{
|
|
||||||
Handler: v1.Handler{
|
|
||||||
TCPSocket: &v1.TCPSocketAction{
|
|
||||||
Port: intstr.FromString("memcached"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
InitialDelaySeconds: int32(15),
|
|
||||||
PeriodSeconds: int32(30),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "exporter",
|
|
||||||
Image: fmt.Sprintf("vexxhost/memcached_exporter:%s", version.Revision),
|
|
||||||
Ports: []v1.ContainerPort{
|
|
||||||
{
|
|
||||||
Name: "metrics",
|
|
||||||
ContainerPort: int32(9150),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Resources: v1.ResourceRequirements{
|
|
||||||
Limits: v1.ResourceList{
|
|
||||||
v1.ResourceCPU: *resource.NewMilliQuantity(1000, resource.DecimalSI),
|
|
||||||
v1.ResourceMemory: *resource.NewQuantity(int64(units.Mebibyte)*256, resource.BinarySI),
|
|
||||||
v1.ResourceEphemeralStorage: *resource.NewQuantity(int64(units.MB)*1000, resource.DecimalSI),
|
|
||||||
},
|
|
||||||
Requests: v1.ResourceList{
|
|
||||||
v1.ResourceCPU: *resource.NewMilliQuantity(100, resource.DecimalSI),
|
|
||||||
v1.ResourceMemory: *resource.NewQuantity(int64(units.Mebibyte)*128, resource.BinarySI),
|
|
||||||
v1.ResourceEphemeralStorage: *resource.NewQuantity(int64(units.MB)*500, resource.DecimalSI),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
StartupProbe: &v1.Probe{},
|
|
||||||
ReadinessProbe: &v1.Probe{
|
|
||||||
Handler: v1.Handler{
|
|
||||||
HTTPGet: &v1.HTTPGetAction{
|
|
||||||
Path: string("/metrics"),
|
|
||||||
Port: intstr.FromString("metrics"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PeriodSeconds: int32(10),
|
|
||||||
},
|
|
||||||
LivenessProbe: &v1.Probe{
|
|
||||||
Handler: v1.Handler{
|
|
||||||
HTTPGet: &v1.HTTPGetAction{
|
|
||||||
Path: string("/metrics"),
|
|
||||||
Port: intstr.FromString("metrics"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
InitialDelaySeconds: int32(15),
|
|
||||||
PeriodSeconds: int32(20),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return controllerutil.SetControllerReference(&memcached, deployment, r.Scheme)
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
@ -211,6 +137,9 @@ func (r *MemcachedReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
|||||||
return ctrl.Result{Requeue: true}, nil
|
return ctrl.Result{Requeue: true}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure that they're sorted so we're idempotent
|
||||||
|
sort.Strings(servers)
|
||||||
|
|
||||||
// Mcrouter
|
// Mcrouter
|
||||||
mcrouter := &infrastructurev1alpha1.Mcrouter{
|
mcrouter := &infrastructurev1alpha1.Mcrouter{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -245,5 +174,6 @@ func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
|||||||
return ctrl.NewControllerManagedBy(mgr).
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
For(&infrastructurev1alpha1.Memcached{}).
|
For(&infrastructurev1alpha1.Memcached{}).
|
||||||
Owns(&appsv1.Deployment{}).
|
Owns(&appsv1.Deployment{}).
|
||||||
|
Owns(&infrastructurev1alpha1.Mcrouter{}).
|
||||||
Complete(r)
|
Complete(r)
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,6 @@ var _ = BeforeSuite(func(done Done) {
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
// +kubebuilder:scaffold:scheme
|
// +kubebuilder:scaffold:scheme
|
||||||
|
|
||||||
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
|
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(k8sClient).ToNot(BeNil())
|
Expect(k8sClient).ToNot(BeNil())
|
||||||
|
1
go.mod
1
go.mod
@ -5,6 +5,7 @@ go 1.13
|
|||||||
require (
|
require (
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf
|
||||||
github.com/go-logr/logr v0.1.0
|
github.com/go-logr/logr v0.1.0
|
||||||
|
github.com/google/go-cmp v0.3.0
|
||||||
github.com/onsi/ginkgo v1.11.0
|
github.com/onsi/ginkgo v1.11.0
|
||||||
github.com/onsi/gomega v1.8.1
|
github.com/onsi/gomega v1.8.1
|
||||||
k8s.io/api v0.17.2
|
k8s.io/api v0.17.2
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
FROM ubuntu:bionic
|
FROM ubuntu:bionic
|
||||||
|
RUN groupadd -r mcrouter \
|
||||||
|
&& useradd -r -g mcrouter mcrouter
|
||||||
RUN apt update && \
|
RUN apt update && \
|
||||||
apt install -y --no-install-recommends ca-certificates wget gnupg && \
|
apt install -y --no-install-recommends ca-certificates wget gnupg && \
|
||||||
wget -O - https://facebook.github.io/mcrouter/debrepo/bionic/PUBLIC.KEY | apt-key add && \
|
wget -O - https://facebook.github.io/mcrouter/debrepo/bionic/PUBLIC.KEY | apt-key add && \
|
||||||
@ -9,5 +10,8 @@ RUN apt update && \
|
|||||||
apt remove -y wget gnupg && \
|
apt remove -y wget gnupg && \
|
||||||
apt autoremove -y && \
|
apt autoremove -y && \
|
||||||
apt clean all
|
apt clean all
|
||||||
|
RUN chown -R mcrouter:mcrouter /var/spool/mcrouter
|
||||||
|
RUN chown -R mcrouter:mcrouter /var/mcrouter
|
||||||
|
RUN chown -R mcrouter:mcrouter /usr/bin/mcrouter
|
||||||
|
USER mcrouter
|
||||||
ENTRYPOINT ["/usr/bin/mcrouter"]
|
ENTRYPOINT ["/usr/bin/mcrouter"]
|
1
playbooks/functional/post.yaml
Normal file → Executable file
1
playbooks/functional/post.yaml
Normal file → Executable file
@ -1,3 +1,4 @@
|
|||||||
- hosts: all
|
- hosts: all
|
||||||
roles:
|
roles:
|
||||||
- collect-container-logs
|
- collect-container-logs
|
||||||
|
- collect-kubernetes-logs
|
35
utils/kubernetes.go
Normal file
35
utils/kubernetes.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateOrUpdate wraps the function provided by controller-runtime to include
|
||||||
|
// some additional logging and common functionality across all resources.
|
||||||
|
func CreateOrUpdate(ctx context.Context, c client.Client, obj runtime.Object, f controllerutil.MutateFn) (controllerutil.OperationResult, error) {
|
||||||
|
return controllerutil.CreateOrUpdate(ctx, c, obj, func() error {
|
||||||
|
original := obj.DeepCopyObject()
|
||||||
|
|
||||||
|
err := f()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
generateObjectDiff(original, obj)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateObjectDiff(original runtime.Object, modified runtime.Object) {
|
||||||
|
diff := cmp.Diff(original, modified)
|
||||||
|
|
||||||
|
if len(diff) != 0 {
|
||||||
|
fmt.Println(diff)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user