From 5c20619dd181e91defaaf1a4318c784c15859797 Mon Sep 17 00:00:00 2001 From: Artiom Diomin Date: Sun, 12 May 2019 01:23:30 +0300 Subject: [PATCH] add weave-net as a CNI plugin Signed-off-by: Artiom Diomin --- config.yaml.dist | 16 +- pkg/apis/kubeone/types.go | 24 + pkg/apis/kubeone/v1alpha1/defaults.go | 5 + pkg/apis/kubeone/v1alpha1/types.go | 24 + .../v1alpha1/zz_generated.conversion.go | 34 ++ .../kubeone/v1alpha1/zz_generated.deepcopy.go | 23 +- pkg/apis/kubeone/validation/validation.go | 13 + pkg/apis/kubeone/zz_generated.deepcopy.go | 23 +- pkg/installer/installation/cni.go | 22 +- pkg/installer/installation/install.go | 2 +- pkg/templates/canal/canal.go | 52 +- pkg/templates/weave/helper.go | 31 ++ pkg/templates/weave/weave-net.go | 466 ++++++++++++++++++ 13 files changed, 703 insertions(+), 32 deletions(-) create mode 100644 pkg/templates/weave/helper.go create mode 100644 pkg/templates/weave/weave-net.go diff --git a/config.yaml.dist b/config.yaml.dist index 9b182ee47..8cada74c4 100644 --- a/config.yaml.dist +++ b/config.yaml.dist @@ -31,6 +31,16 @@ clusterNetwork: serviceDomainName: "" # a nodePort range to reserve for services (default: 30000-32767) nodePortRange: "" + # CNI plugin choise + cni: + # possible values: + # * canal + # * weave-net + provider: canal + # when selected CNI provider support encryption and `encrypted: true` is + # set, secret will be automatically generated and referenced in appropriate + # manifests + encrypted: false cloudProvider: # Supported cloud provider names: @@ -42,7 +52,8 @@ cloudProvider: # * packet # * vsphere name: "" - # Set the kubelet flag '--cloud-provider=external' and deploy the external CCM for supported providers + # Set the kubelet flag '--cloud-provider=external' and deploy the external CCM + # for supported providers external: false # Path to file that will be uploaded and used as custom '--cloud-config' file. cloudConfig: "" @@ -132,7 +143,8 @@ features: # case, anything you configure in your "workers" sections is ignored. # machineController: # deploy: false -# # Defines for what provider the machine-controller will be configured (defaults to cloudProvider.Name) +# # Defines for what provider the machine-controller will be configured +# # (defaults to cloudProvider.Name) # provider: "" # Proxy is used to configure HTTP_PROXY, HTTPS_PROXY and NO_PROXY diff --git a/pkg/apis/kubeone/types.go b/pkg/apis/kubeone/types.go index b741b6655..d4be7a713 100644 --- a/pkg/apis/kubeone/types.go +++ b/pkg/apis/kubeone/types.go @@ -111,6 +111,30 @@ type ClusterNetworkConfig struct { ServiceSubnet string `json:"serviceSubnet"` ServiceDomainName string `json:"serviceDomainName"` NodePortRange string `json:"nodePortRange"` + CNI *CNI `json:"cni,omitempty"` +} + +// CNIProvider type +type CNIProvider string + +// List of CNI Providers +const ( + // https://docs.projectcalico.org/v3.7/getting-started/kubernetes/installation/flannel + // This provider does not support encryption. + CNIProviderCanal = CNIProvider("canal") + + // https://www.weave.works/docs/net/latest/kubernetes/kube-addon/ + // This provider support optional encryption. + // Strong secret will be autogenerated. + CNIProviderWeaveNet = CNIProvider("weave-net") +) + +// CNI config +type CNI struct { + // Provider choise + Provider CNIProvider `json:"provider"` + // Some of providers do provide optional encryption + Encrypted bool `json:"encrypted"` } // ProxyConfig configures proxy for the Docker daemon and is used by KubeOne scripts diff --git a/pkg/apis/kubeone/v1alpha1/defaults.go b/pkg/apis/kubeone/v1alpha1/defaults.go index e76ea1bfd..d9f2afc2e 100644 --- a/pkg/apis/kubeone/v1alpha1/defaults.go +++ b/pkg/apis/kubeone/v1alpha1/defaults.go @@ -86,6 +86,11 @@ func SetDefaults_ClusterNetwork(obj *KubeOneCluster) { if len(obj.ClusterNetwork.NodePortRange) == 0 { obj.ClusterNetwork.NodePortRange = DefaultNodePortRange } + if obj.ClusterNetwork.CNI == nil { + obj.ClusterNetwork.CNI = &CNI{ + Provider: CNIProviderCanal, + } + } } func SetDefaults_MachineController(obj *KubeOneCluster) { diff --git a/pkg/apis/kubeone/v1alpha1/types.go b/pkg/apis/kubeone/v1alpha1/types.go index 778fabae4..102879dd9 100644 --- a/pkg/apis/kubeone/v1alpha1/types.go +++ b/pkg/apis/kubeone/v1alpha1/types.go @@ -111,6 +111,30 @@ type ClusterNetworkConfig struct { ServiceSubnet string `json:"serviceSubnet"` ServiceDomainName string `json:"serviceDomainName"` NodePortRange string `json:"nodePortRange"` + CNI *CNI `json:"cni,omitempty"` +} + +// CNIProvider type +type CNIProvider string + +// List of CNI Providers +const ( + // https://docs.projectcalico.org/v3.7/getting-started/kubernetes/installation/flannel + // This provider does not support encryption. + CNIProviderCanal = CNIProvider("canal") + + // https://www.weave.works/docs/net/latest/kubernetes/kube-addon/ + // This provider support optional encryption. + // Strong secret will be autogenerated. + CNIProviderWeaveNet = CNIProvider("weave-net") +) + +// CNI config +type CNI struct { + // Provider choise + Provider CNIProvider `json:"provider"` + // Some of providers do provide optional encryption + Encrypted bool `json:"encrypted"` } // ProxyConfig configures proxy for the Docker daemon and is used by KubeOne scripts diff --git a/pkg/apis/kubeone/v1alpha1/zz_generated.conversion.go b/pkg/apis/kubeone/v1alpha1/zz_generated.conversion.go index 917901225..1761f0e0a 100644 --- a/pkg/apis/kubeone/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/kubeone/v1alpha1/zz_generated.conversion.go @@ -46,6 +46,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*CNI)(nil), (*kubeone.CNI)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_CNI_To_kubeone_CNI(a.(*CNI), b.(*kubeone.CNI), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*kubeone.CNI)(nil), (*CNI)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_kubeone_CNI_To_v1alpha1_CNI(a.(*kubeone.CNI), b.(*CNI), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*CloudProviderSpec)(nil), (*kubeone.CloudProviderSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_CloudProviderSpec_To_kubeone_CloudProviderSpec(a.(*CloudProviderSpec), b.(*kubeone.CloudProviderSpec), scope) }); err != nil { @@ -221,6 +231,28 @@ func Convert_kubeone_APIEndpoint_To_v1alpha1_APIEndpoint(in *kubeone.APIEndpoint return autoConvert_kubeone_APIEndpoint_To_v1alpha1_APIEndpoint(in, out, s) } +func autoConvert_v1alpha1_CNI_To_kubeone_CNI(in *CNI, out *kubeone.CNI, s conversion.Scope) error { + out.Provider = kubeone.CNIProvider(in.Provider) + out.Encrypted = in.Encrypted + return nil +} + +// Convert_v1alpha1_CNI_To_kubeone_CNI is an autogenerated conversion function. +func Convert_v1alpha1_CNI_To_kubeone_CNI(in *CNI, out *kubeone.CNI, s conversion.Scope) error { + return autoConvert_v1alpha1_CNI_To_kubeone_CNI(in, out, s) +} + +func autoConvert_kubeone_CNI_To_v1alpha1_CNI(in *kubeone.CNI, out *CNI, s conversion.Scope) error { + out.Provider = CNIProvider(in.Provider) + out.Encrypted = in.Encrypted + return nil +} + +// Convert_kubeone_CNI_To_v1alpha1_CNI is an autogenerated conversion function. +func Convert_kubeone_CNI_To_v1alpha1_CNI(in *kubeone.CNI, out *CNI, s conversion.Scope) error { + return autoConvert_kubeone_CNI_To_v1alpha1_CNI(in, out, s) +} + func autoConvert_v1alpha1_CloudProviderSpec_To_kubeone_CloudProviderSpec(in *CloudProviderSpec, out *kubeone.CloudProviderSpec, s conversion.Scope) error { out.Name = kubeone.CloudProviderName(in.Name) out.External = in.External @@ -250,6 +282,7 @@ func autoConvert_v1alpha1_ClusterNetworkConfig_To_kubeone_ClusterNetworkConfig(i out.ServiceSubnet = in.ServiceSubnet out.ServiceDomainName = in.ServiceDomainName out.NodePortRange = in.NodePortRange + out.CNI = (*kubeone.CNI)(unsafe.Pointer(in.CNI)) return nil } @@ -263,6 +296,7 @@ func autoConvert_kubeone_ClusterNetworkConfig_To_v1alpha1_ClusterNetworkConfig(i out.ServiceSubnet = in.ServiceSubnet out.ServiceDomainName = in.ServiceDomainName out.NodePortRange = in.NodePortRange + out.CNI = (*CNI)(unsafe.Pointer(in.CNI)) return nil } diff --git a/pkg/apis/kubeone/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/kubeone/v1alpha1/zz_generated.deepcopy.go index 19fac670c..2ca29cb50 100644 --- a/pkg/apis/kubeone/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/kubeone/v1alpha1/zz_generated.deepcopy.go @@ -42,6 +42,22 @@ func (in *APIEndpoint) DeepCopy() *APIEndpoint { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CNI) DeepCopyInto(out *CNI) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNI. +func (in *CNI) DeepCopy() *CNI { + if in == nil { + return nil + } + out := new(CNI) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CloudProviderSpec) DeepCopyInto(out *CloudProviderSpec) { *out = *in @@ -61,6 +77,11 @@ func (in *CloudProviderSpec) DeepCopy() *CloudProviderSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterNetworkConfig) DeepCopyInto(out *ClusterNetworkConfig) { *out = *in + if in.CNI != nil { + in, out := &in.CNI, &out.CNI + *out = new(CNI) + **out = **in + } return } @@ -154,7 +175,7 @@ func (in *KubeOneCluster) DeepCopyInto(out *KubeOneCluster) { out.APIEndpoint = in.APIEndpoint out.CloudProvider = in.CloudProvider out.Versions = in.Versions - out.ClusterNetwork = in.ClusterNetwork + in.ClusterNetwork.DeepCopyInto(&out.ClusterNetwork) out.Proxy = in.Proxy if in.Workers != nil { in, out := &in.Workers, &out.Workers diff --git a/pkg/apis/kubeone/validation/validation.go b/pkg/apis/kubeone/validation/validation.go index 248a56d74..262f09ad7 100644 --- a/pkg/apis/kubeone/validation/validation.go +++ b/pkg/apis/kubeone/validation/validation.go @@ -167,6 +167,19 @@ func ValidateClusterNetworkConfig(c kubeone.ClusterNetworkConfig, fldPath *field } } + if c.CNI != nil { + switch c.CNI.Provider { + case kubeone.CNIProviderCanal: + case kubeone.CNIProviderWeaveNet: + default: + allErrs = append(allErrs, field.Invalid(fldPath, c.CNI.Provider, "unknown CNI provider")) + } + + if c.CNI.Encrypted && c.CNI.Provider != kubeone.CNIProviderWeaveNet { + allErrs = append(allErrs, field.Invalid(fldPath, c.CNI, "only `weave-net` cni provider support `encrypted: true`")) + } + } + return allErrs } diff --git a/pkg/apis/kubeone/zz_generated.deepcopy.go b/pkg/apis/kubeone/zz_generated.deepcopy.go index a473e8b3e..ad3cf797d 100644 --- a/pkg/apis/kubeone/zz_generated.deepcopy.go +++ b/pkg/apis/kubeone/zz_generated.deepcopy.go @@ -42,6 +42,22 @@ func (in *APIEndpoint) DeepCopy() *APIEndpoint { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CNI) DeepCopyInto(out *CNI) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNI. +func (in *CNI) DeepCopy() *CNI { + if in == nil { + return nil + } + out := new(CNI) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CloudProviderSpec) DeepCopyInto(out *CloudProviderSpec) { *out = *in @@ -61,6 +77,11 @@ func (in *CloudProviderSpec) DeepCopy() *CloudProviderSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterNetworkConfig) DeepCopyInto(out *ClusterNetworkConfig) { *out = *in + if in.CNI != nil { + in, out := &in.CNI, &out.CNI + *out = new(CNI) + **out = **in + } return } @@ -154,7 +175,7 @@ func (in *KubeOneCluster) DeepCopyInto(out *KubeOneCluster) { out.APIEndpoint = in.APIEndpoint out.CloudProvider = in.CloudProvider out.Versions = in.Versions - out.ClusterNetwork = in.ClusterNetwork + in.ClusterNetwork.DeepCopyInto(&out.ClusterNetwork) out.Proxy = in.Proxy if in.Workers != nil { in, out := &in.Workers, &out.Workers diff --git a/pkg/installer/installation/cni.go b/pkg/installer/installation/cni.go index 0f1fb76c4..b8152bab7 100644 --- a/pkg/installer/installation/cni.go +++ b/pkg/installer/installation/cni.go @@ -17,11 +17,31 @@ limitations under the License. package installation import ( + "github.com/pkg/errors" + + "github.com/kubermatic/kubeone/pkg/apis/kubeone" "github.com/kubermatic/kubeone/pkg/templates/canal" + "github.com/kubermatic/kubeone/pkg/templates/weave" "github.com/kubermatic/kubeone/pkg/util" ) -func applyCanalCNI(ctx *util.Context) error { +func ensureCNI(ctx *util.Context) error { + switch ctx.Cluster.ClusterNetwork.CNI.Provider { + case kubeone.CNIProviderCanal: + return ensureCNICanal(ctx) + case kubeone.CNIProviderWeaveNet: + return ensureCNIWeaveNet(ctx) + } + + return errors.Errorf("unknown CNI provider: %s", ctx.Cluster.ClusterNetwork.CNI.Provider) +} + +func ensureCNIWeaveNet(ctx *util.Context) error { + ctx.Logger.Infoln("Applying weave-net CNI plugin…") + return weave.Deploy(ctx) +} + +func ensureCNICanal(ctx *util.Context) error { ctx.Logger.Infoln("Applying canal CNI plugin…") return canal.Deploy(ctx) } diff --git a/pkg/installer/installation/install.go b/pkg/installer/installation/install.go index 30d36b913..be94875b1 100644 --- a/pkg/installer/installation/install.go +++ b/pkg/installer/installation/install.go @@ -47,7 +47,7 @@ func Install(ctx *util.Context) error { {Fn: credentials.Ensure, ErrMsg: "unable to ensure credentials secret"}, {Fn: externalccm.Ensure, ErrMsg: "failed to install external CCM"}, {Fn: patchCoreDNS, ErrMsg: "failed to patch CoreDNS", Retries: 3}, - {Fn: applyCanalCNI, ErrMsg: "failed to install cni plugin canal", Retries: 3}, + {Fn: ensureCNI, ErrMsg: "failed to install cni plugin", Retries: 3}, {Fn: machinecontroller.Ensure, ErrMsg: "failed to install machine-controller", Retries: 3}, {Fn: machinecontroller.WaitReady, ErrMsg: "failed to wait for machine-controller", Retries: 3}, {Fn: createWorkerMachines, ErrMsg: "failed to create worker machines", Retries: 3}, diff --git a/pkg/templates/canal/canal.go b/pkg/templates/canal/canal.go index eb8ae38f7..3314fe03f 100644 --- a/pkg/templates/canal/canal.go +++ b/pkg/templates/canal/canal.go @@ -39,38 +39,38 @@ const ( cniNetworkConfig = ` { "name": "k8s-pod-network", - "cniVersion": "0.3.0", - "plugins": [ - { - "type": "calico", - "log_level": "info", - "datastore_type": "kubernetes", - "nodename": "__KUBERNETES_NODE_NAME__", - "ipam": { - "type": "host-local", - "subnet": "usePodCidr" - }, - "policy": { - "type": "k8s" - }, - "kubernetes": { - "kubeconfig": "__KUBECONFIG_FILEPATH__" - } - }, - { - "type": "portmap", - "snat": true, - "capabilities": {"portMappings": true} - } - ] + "cniVersion": "0.3.0", + "plugins": [ + { + "type": "calico", + "log_level": "info", + "datastore_type": "kubernetes", + "nodename": "__KUBERNETES_NODE_NAME__", + "ipam": { + "type": "host-local", + "subnet": "usePodCidr" + }, + "policy": { + "type": "k8s" + }, + "kubernetes": { + "kubeconfig": "__KUBECONFIG_FILEPATH__" + } + }, + { + "type": "portmap", + "snat": true, + "capabilities": {"portMappings": true} + } + ] } ` // Flannel network configuration (mounted into the flannel container) flannelNetworkConfig = ` { "Network": "{{ .POD_SUBNET }}", - "Backend": { - "Type": "vxlan" + "Backend": { + "Type": "vxlan" } } ` diff --git a/pkg/templates/weave/helper.go b/pkg/templates/weave/helper.go new file mode 100644 index 000000000..254bd0663 --- /dev/null +++ b/pkg/templates/weave/helper.go @@ -0,0 +1,31 @@ +/* +Copyright 2019 The KubeOne Authors. + +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 weave + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + dynclient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +func simpleCreateOrUpdate(ctx context.Context, client dynclient.Client, obj runtime.Object) error { + okFunc := func(runtime.Object) error { return nil } + _, err := controllerutil.CreateOrUpdate(ctx, client, obj, okFunc) + return err +} diff --git a/pkg/templates/weave/weave-net.go b/pkg/templates/weave/weave-net.go new file mode 100644 index 000000000..05920462d --- /dev/null +++ b/pkg/templates/weave/weave-net.go @@ -0,0 +1,466 @@ +/* +Copyright 2019 The KubeOne Authors. + +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 weave + +import ( + "context" + "crypto/rand" + "encoding/base64" + + "github.com/pkg/errors" + + "github.com/kubermatic/kubeone/pkg/util" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ( + version = ":2.5.1" + weaveKubeImage = "docker.io/weaveworks/weave-kube" + weaveNPCImage = "docker.io/weaveworks/weave-npc" +) + +// Deploy ensure weave-net resources exists in the cluster +func Deploy(ctx *util.Context) error { + if ctx.DynamicClient == nil { + return errors.New("kubernetes dynamic client is not initialized") + } + + bgCtx := context.Background() + + if err := simpleCreateOrUpdate(bgCtx, ctx.DynamicClient, serviceAccount()); err != nil { + return errors.Wrap(err, "failed to ensure weave ServiceAccount") + } + + if err := simpleCreateOrUpdate(bgCtx, ctx.DynamicClient, clusterRole()); err != nil { + return errors.Wrap(err, "failed to ensure weave ClusterRole") + } + + if err := simpleCreateOrUpdate(bgCtx, ctx.DynamicClient, clusterRoleBinding()); err != nil { + return errors.Wrap(err, "failed to ensure weave ClusterRoleBinding") + } + + if err := simpleCreateOrUpdate(bgCtx, ctx.DynamicClient, role()); err != nil { + return errors.Wrap(err, "failed to ensure weave Role") + } + + if err := simpleCreateOrUpdate(bgCtx, ctx.DynamicClient, roleBinding()); err != nil { + return errors.Wrap(err, "failed to ensure weave RoleBinding") + } + + if ctx.Cluster.ClusterNetwork.CNI.Encrypted { + pass, err := genPassword() + sec := secret(pass) + key := client.ObjectKey{ + Name: sec.GetName(), + Namespace: sec.GetNamespace(), + } + + err = ctx.DynamicClient.Get(bgCtx, key, sec) + if err != nil && !k8serrors.IsNotFound(err) { + return errors.Wrap(err, "failed to get weave-net Secret") + } + + err = ctx.DynamicClient.Create(bgCtx, sec) + if err != nil { + return errors.Wrap(err, "failed to create weave-net Secret") + } + } + + if err := simpleCreateOrUpdate(bgCtx, ctx.DynamicClient, daemonSet(ctx.Cluster.ClusterNetwork.CNI.Encrypted)); err != nil { + return errors.Wrap(err, "failed to ensure weave DaemonSet") + } + + return nil +} + +func genPassword() (string, error) { + pi := make([]byte, 32) + _, err := rand.Reader.Read(pi) + if err != nil { + return "", errors.Wrap(err, "failed to read random bytes") + } + return base64.StdEncoding.EncodeToString(pi), nil +} + +func serviceAccount() *corev1.ServiceAccount { + return &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: "weave-net", + Namespace: metav1.NamespaceSystem, + Labels: map[string]string{ + "name": "weave-net", + }, + }, + } +} + +func clusterRole() *rbacv1.ClusterRole { + return &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "weave-net", + Labels: map[string]string{ + "name": "weave-net", + }, + }, + Rules: []rbacv1.PolicyRule{ + { + APIGroups: []string{""}, + Resources: []string{ + "pods", + "nodes", + "namespaces", + }, + Verbs: []string{ + "get", + "list", + "watch", + }, + }, + { + APIGroups: []string{"networking.k8s.io"}, + Resources: []string{ + "networkpolicies", + }, + Verbs: []string{ + "watch", + "list", + "get", + }, + }, + { + APIGroups: []string{""}, + Resources: []string{ + "nodes/status", + }, + Verbs: []string{ + "patch", + "update", + }, + }, + }, + } +} + +func clusterRoleBinding() *rbacv1.ClusterRoleBinding { + return &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "weave-net", + Labels: map[string]string{ + "name": "weave-net", + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: rbacv1.GroupName, + Kind: "ClusterRole", + Name: "weave-net", + }, + Subjects: []rbacv1.Subject{ + { + Kind: "ServiceAccount", + Name: "weave-net", + Namespace: metav1.NamespaceSystem, + }, + }, + } +} + +func role() *rbacv1.Role { + return &rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "weave-net", + Namespace: metav1.NamespaceSystem, + Labels: map[string]string{ + "name": "weave-net", + }, + }, + Rules: []rbacv1.PolicyRule{ + { + APIGroups: []string{""}, + Resources: []string{"configmaps"}, + ResourceNames: []string{"weave-net"}, + Verbs: []string{"get", "update"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"configmaps"}, + Verbs: []string{"create"}, + }, + }, + } +} + +func roleBinding() *rbacv1.RoleBinding { + return &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "weave-net", + Namespace: metav1.NamespaceSystem, + Labels: map[string]string{ + "name": "weave-net", + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: rbacv1.GroupName, + Kind: "Role", + Name: "weave-name", + }, + Subjects: []rbacv1.Subject{ + rbacv1.Subject{ + Kind: "ServiceAccount", + Name: "weave-net", + Namespace: metav1.NamespaceSystem, + }, + }, + } +} + +func secret(pass string) *corev1.Secret { + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "weave-passwd", + Namespace: metav1.NamespaceSystem, + Labels: map[string]string{ + "name": "weave-net", + }, + }, + StringData: map[string]string{ + "weave-passwd": pass, + }, + } +} + +func dsEnv(passwordRef bool) []corev1.EnvVar { + env := []corev1.EnvVar{ + corev1.EnvVar{ + Name: "HOSTNAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "spec.nodeName", + }, + }, + }, + } + + if passwordRef { + env = append(env, corev1.EnvVar{ + Name: "WEAVE_PASSWORD", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + Key: "weave-passwd", + LocalObjectReference: corev1.LocalObjectReference{ + Name: "weave-passwd", + }, + }, + }, + }) + } + + return env +} + +func daemonSet(passwordRef bool) *appsv1.DaemonSet { + var ( + priviledged = true + fileOrCreate = corev1.HostPathFileOrCreate + ) + + return &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "weave-net", + Namespace: metav1.NamespaceSystem, + Labels: map[string]string{ + "name": "weave-net", + }, + }, + Spec: appsv1.DaemonSetSpec{ + MinReadySeconds: 5, + UpdateStrategy: appsv1.DaemonSetUpdateStrategy{ + Type: appsv1.RollingUpdateDaemonSetStrategyType, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "name": "weave-net", + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "weave", + Command: []string{"/home/weave/launch.sh"}, + Env: dsEnv(passwordRef), + Image: weaveKubeImage + version, + ReadinessProbe: &corev1.Probe{ + Handler: corev1.Handler{ + HTTPGet: &corev1.HTTPGetAction{ + Host: "127.0.0.1", + Path: "/status", + Port: intstr.FromInt(6784), + }, + }, + }, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("10m"), + }, + }, + SecurityContext: &corev1.SecurityContext{ + Privileged: &priviledged, + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "weavedb", + MountPath: "/weavedb", + }, + { + Name: "cni-bin", + MountPath: "/host/opt", + }, + { + Name: "cni-bin2", + MountPath: "/host/home", + }, + { + Name: "cni-conf", + MountPath: "/host/etc", + }, + { + Name: "dbus", + MountPath: "/host/var/lib/dbus", + }, + { + Name: "lib-modules", + MountPath: "/lib/modules", + }, + { + Name: "xtables-lock", + MountPath: "/run/xtables.lock", + }, + }, + }, + corev1.Container{ + Name: "weave-npc", + Env: []corev1.EnvVar{ + corev1.EnvVar{ + Name: "HOSTNAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "spec.nodeName", + }, + }, + }, + }, + Image: weaveNPCImage + version, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("10m"), + }, + }, + SecurityContext: &corev1.SecurityContext{ + Privileged: &priviledged, + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "xtables-lock", + MountPath: "/run/xtables.lock", + }, + }, + }, + }, + HostNetwork: true, + HostPID: true, + RestartPolicy: corev1.RestartPolicyAlways, + ServiceAccountName: "weave-net", + Tolerations: []corev1.Toleration{ + { + Effect: corev1.TaintEffectNoSchedule, + Operator: corev1.TolerationOpExists, + }, + }, + Volumes: []corev1.Volume{ + { + Name: "weavedb", + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: "/var/lib/weave", + }, + }, + }, + { + Name: "cni-bin", + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: "/opt", + }, + }, + }, + { + Name: "cni-bin2", + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: "/home", + }, + }, + }, + { + Name: "cni-conf", + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: "/etc", + }, + }, + }, + { + Name: "dbus", + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: "/var/lib/dbus", + }, + }, + }, + { + Name: "lib-modules", + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: "/lib/modules", + }, + }, + }, + { + Name: "xtables-lock", + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: "/run/xtables.lock", + Type: &fileOrCreate, + }, + }, + }, + }, + }, + }, + }, + } +}