285 lines
7.0 KiB
Go
285 lines
7.0 KiB
Go
package render
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
appsv1 "k8s.io/api/apps/v1"
|
|
corev1 "k8s.io/api/core/v1"
|
|
rbacv1 "k8s.io/api/rbac/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
|
monov1alpha1 "example.com/monok8s/pkg/apis/monok8s/v1alpha1"
|
|
buildinfo "example.com/monok8s/pkg/buildinfo"
|
|
)
|
|
|
|
type AgentConf struct {
|
|
Namespace string
|
|
Image string
|
|
ImagePullSecrets []string
|
|
Labels map[string]string
|
|
}
|
|
|
|
func RenderAgentDaemonSets(conf AgentConf) (string, error) {
|
|
objs, err := buildAgentDaemonSetObjects(conf)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return renderObjects(objs)
|
|
}
|
|
|
|
func buildAgentDaemonSetObjects(conf AgentConf) ([]runtime.Object, error) {
|
|
if strings.TrimSpace(conf.Namespace) == "" {
|
|
return nil, fmt.Errorf("namespace is required")
|
|
}
|
|
|
|
conf.Labels = map[string]string{
|
|
"app.kubernetes.io/name": monov1alpha1.NodeAgentName,
|
|
"app.kubernetes.io/component": "agent",
|
|
"app.kubernetes.io/part-of": "monok8s",
|
|
"app.kubernetes.io/managed-by": monov1alpha1.NodeControlName,
|
|
}
|
|
|
|
return []runtime.Object{
|
|
buildAgentServiceAccount(conf),
|
|
buildAgentClusterRole(conf),
|
|
buildAgentClusterRoleBinding(conf),
|
|
buildAgentDaemonSet(conf),
|
|
}, nil
|
|
}
|
|
|
|
func buildAgentNamespace(conf AgentConf) *corev1.Namespace {
|
|
return &corev1.Namespace{
|
|
TypeMeta: metav1.TypeMeta{
|
|
APIVersion: "v1",
|
|
Kind: "Namespace",
|
|
},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: conf.Namespace,
|
|
Labels: copyStringMap(conf.Labels),
|
|
},
|
|
}
|
|
}
|
|
|
|
func buildAgentServiceAccount(conf AgentConf) *corev1.ServiceAccount {
|
|
return &corev1.ServiceAccount{
|
|
TypeMeta: metav1.TypeMeta{
|
|
APIVersion: "v1",
|
|
Kind: "ServiceAccount",
|
|
},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: monov1alpha1.NodeAgentName,
|
|
Namespace: conf.Namespace,
|
|
Labels: copyStringMap(conf.Labels),
|
|
},
|
|
}
|
|
}
|
|
|
|
func buildAgentClusterRole(conf AgentConf) *rbacv1.ClusterRole {
|
|
wantRules := []rbacv1.PolicyRule{
|
|
{
|
|
APIGroups: []string{monov1alpha1.Group},
|
|
Resources: []string{"osupgrades"},
|
|
Verbs: []string{"get"},
|
|
},
|
|
{
|
|
APIGroups: []string{monov1alpha1.Group},
|
|
Resources: []string{"osupgradeprogresses"},
|
|
Verbs: []string{"get", "list", "watch", "create", "patch", "update"},
|
|
},
|
|
{
|
|
APIGroups: []string{monov1alpha1.Group},
|
|
Resources: []string{"osupgradeprogresses/status"},
|
|
Verbs: []string{"get", "list", "watch", "create", "patch", "update"},
|
|
},
|
|
{
|
|
APIGroups: []string{""},
|
|
Resources: []string{"nodes"},
|
|
Verbs: []string{"get", "list", "watch"},
|
|
},
|
|
}
|
|
|
|
return &rbacv1.ClusterRole{
|
|
TypeMeta: metav1.TypeMeta{
|
|
APIVersion: "rbac.authorization.k8s.io/v1",
|
|
Kind: "ClusterRole",
|
|
},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: monov1alpha1.NodeAgentName,
|
|
Labels: copyStringMap(conf.Labels),
|
|
},
|
|
Rules: wantRules,
|
|
}
|
|
}
|
|
|
|
func buildAgentClusterRoleBinding(conf AgentConf) *rbacv1.ClusterRoleBinding {
|
|
return &rbacv1.ClusterRoleBinding{
|
|
TypeMeta: metav1.TypeMeta{
|
|
APIVersion: "rbac.authorization.k8s.io/v1",
|
|
Kind: "ClusterRoleBinding",
|
|
},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: monov1alpha1.NodeAgentName,
|
|
Labels: copyStringMap(conf.Labels),
|
|
},
|
|
RoleRef: rbacv1.RoleRef{
|
|
APIGroup: rbacv1.GroupName,
|
|
Kind: "ClusterRole",
|
|
Name: monov1alpha1.NodeAgentName,
|
|
},
|
|
Subjects: []rbacv1.Subject{
|
|
{
|
|
Kind: "ServiceAccount",
|
|
Name: monov1alpha1.NodeAgentName,
|
|
Namespace: conf.Namespace,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func buildAgentDaemonSet(conf AgentConf) *appsv1.DaemonSet {
|
|
privileged := true
|
|
dsLabels := monov1alpha1.NodeAgentLabels()
|
|
|
|
image, pullPolicy := agentImage(conf)
|
|
|
|
return &appsv1.DaemonSet{
|
|
TypeMeta: metav1.TypeMeta{
|
|
APIVersion: "apps/v1",
|
|
Kind: "DaemonSet",
|
|
},
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: monov1alpha1.NodeAgentName,
|
|
Namespace: conf.Namespace,
|
|
Labels: copyStringMap(conf.Labels),
|
|
},
|
|
Spec: appsv1.DaemonSetSpec{
|
|
Selector: &metav1.LabelSelector{
|
|
MatchLabels: map[string]string{
|
|
"app.kubernetes.io/name": monov1alpha1.NodeAgentName,
|
|
},
|
|
},
|
|
Template: corev1.PodTemplateSpec{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Labels: dsLabels,
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
ServiceAccountName: monov1alpha1.NodeAgentName,
|
|
HostNetwork: true,
|
|
HostPID: true,
|
|
DNSPolicy: corev1.DNSClusterFirstWithHostNet,
|
|
ImagePullSecrets: imagePullSecrets(conf.ImagePullSecrets),
|
|
NodeSelector: map[string]string{
|
|
monov1alpha1.NodeControlKey: "true",
|
|
},
|
|
Tolerations: []corev1.Toleration{
|
|
{Operator: corev1.TolerationOpExists},
|
|
},
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: "agent",
|
|
Image: image,
|
|
ImagePullPolicy: pullPolicy,
|
|
Args: []string{"agent", "--env-file", "$(CLUSTER_ENV_FILE)"},
|
|
Env: []corev1.EnvVar{
|
|
{
|
|
Name: "NODE_NAME",
|
|
ValueFrom: &corev1.EnvVarSource{
|
|
FieldRef: &corev1.ObjectFieldSelector{
|
|
APIVersion: "v1",
|
|
FieldPath: "spec.nodeName",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "CLUSTER_ENV_FILE",
|
|
Value: "/host/opt/monok8s/config/cluster.env",
|
|
},
|
|
{
|
|
Name: "FW_ENV_CONFIG_FILE",
|
|
Value: "/host/etc/fw_env.config",
|
|
},
|
|
},
|
|
SecurityContext: &corev1.SecurityContext{
|
|
Privileged: &privileged,
|
|
},
|
|
VolumeMounts: []corev1.VolumeMount{
|
|
{
|
|
Name: "host-dev",
|
|
MountPath: "/dev",
|
|
},
|
|
{
|
|
Name: "host-etc",
|
|
MountPath: "/host/etc",
|
|
ReadOnly: true,
|
|
},
|
|
{
|
|
Name: "host-config",
|
|
MountPath: "/host/opt/monok8s/config",
|
|
ReadOnly: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Volumes: []corev1.Volume{
|
|
{
|
|
Name: "host-dev",
|
|
VolumeSource: corev1.VolumeSource{
|
|
HostPath: &corev1.HostPathVolumeSource{
|
|
Path: "/dev",
|
|
Type: hostPathType(corev1.HostPathDirectory),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "host-etc",
|
|
VolumeSource: corev1.VolumeSource{
|
|
HostPath: &corev1.HostPathVolumeSource{
|
|
Path: "/etc",
|
|
Type: hostPathType(corev1.HostPathDirectory),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "host-config",
|
|
VolumeSource: corev1.VolumeSource{
|
|
HostPath: &corev1.HostPathVolumeSource{
|
|
Path: "/opt/monok8s/config",
|
|
Type: hostPathType(corev1.HostPathDirectory),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func agentImage(conf AgentConf) (string, corev1.PullPolicy) {
|
|
if conf.Image != "" {
|
|
return conf.Image, corev1.PullIfNotPresent
|
|
}
|
|
|
|
return fmt.Sprintf("localhost/monok8s/node-control:%s", buildinfo.Version), corev1.PullNever
|
|
}
|
|
|
|
func copyStringMap(in map[string]string) map[string]string {
|
|
if len(in) == 0 {
|
|
return nil
|
|
}
|
|
|
|
out := make(map[string]string, len(in))
|
|
for k, v := range in {
|
|
out[k] = v
|
|
}
|
|
|
|
return out
|
|
}
|
|
|
|
func hostPathType(t corev1.HostPathType) *corev1.HostPathType {
|
|
return &t
|
|
}
|