mirror of https://github.com/kubernetes/kops.git
253 lines
7.1 KiB
Go
253 lines
7.1 KiB
Go
/*
|
|
Copyright 2016 The Kubernetes 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 model
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"github.com/blang/semver"
|
|
"github.com/golang/glog"
|
|
"k8s.io/kops"
|
|
"k8s.io/kops/pkg/apis/kops/util"
|
|
"k8s.io/kops/pkg/flagbuilder"
|
|
"k8s.io/kops/pkg/systemd"
|
|
"k8s.io/kops/upup/pkg/fi"
|
|
"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// ProtokubeBuilder configures protokube
|
|
type ProtokubeBuilder struct {
|
|
*NodeupModelContext
|
|
}
|
|
|
|
var _ fi.ModelBuilder = &ProtokubeBuilder{}
|
|
|
|
func (b *ProtokubeBuilder) Build(c *fi.ModelBuilderContext) error {
|
|
if b.IsMaster {
|
|
kubeconfig, err := b.buildPKIKubeconfig("kops")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.AddTask(&nodetasks.File{
|
|
Path: "/var/lib/kops/kubeconfig",
|
|
Contents: fi.NewStringResource(kubeconfig),
|
|
Type: nodetasks.FileType_File,
|
|
Mode: s("0400"),
|
|
})
|
|
}
|
|
|
|
// TODO: Should we run _protokube on the nodes?
|
|
service, err := b.buildSystemdService()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.AddTask(service)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *ProtokubeBuilder) buildSystemdService() (*nodetasks.Service, error) {
|
|
k8sVersion, err := util.ParseKubernetesVersion(b.Cluster.Spec.KubernetesVersion)
|
|
if err != nil || k8sVersion == nil {
|
|
return nil, fmt.Errorf("unable to parse KubernetesVersion %q", b.Cluster.Spec.KubernetesVersion)
|
|
}
|
|
|
|
protokubeFlags := b.ProtokubeFlags(*k8sVersion)
|
|
protokubeFlagsArgs, err := flagbuilder.BuildFlags(protokubeFlags)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dockerArgs := []string{
|
|
"/usr/bin/docker",
|
|
"run",
|
|
"-v", "/:/rootfs/",
|
|
"-v", "/var/run/dbus:/var/run/dbus",
|
|
"-v", "/run/systemd:/run/systemd",
|
|
"--net=host",
|
|
"--privileged",
|
|
"--env", "KUBECONFIG=/rootfs/var/lib/kops/kubeconfig",
|
|
b.ProtokubeEnvironmentVariables(),
|
|
b.ProtokubeImageName(),
|
|
"/usr/bin/protokube",
|
|
}
|
|
protokubeCommand := strings.Join(dockerArgs, " ") + " " + protokubeFlagsArgs
|
|
|
|
manifest := &systemd.Manifest{}
|
|
manifest.Set("Unit", "Description", "Kubernetes Protokube Service")
|
|
manifest.Set("Unit", "Documentation", "https://github.com/kubernetes/kops")
|
|
|
|
//manifest.Set("Service", "EnvironmentFile", "/etc/sysconfig/protokube")
|
|
manifest.Set("Service", "ExecStartPre", b.ProtokubeImagePullCommand())
|
|
manifest.Set("Service", "ExecStart", protokubeCommand)
|
|
manifest.Set("Service", "Restart", "always")
|
|
manifest.Set("Service", "RestartSec", "2s")
|
|
manifest.Set("Service", "StartLimitInterval", "0")
|
|
|
|
manifest.Set("Install", "WantedBy", "multi-user.target")
|
|
|
|
manifestString := manifest.Render()
|
|
glog.V(8).Infof("Built service manifest %q\n%s", "protokube", manifestString)
|
|
|
|
service := &nodetasks.Service{
|
|
Name: "protokube.service",
|
|
Definition: s(manifestString),
|
|
}
|
|
|
|
service.InitDefaults()
|
|
|
|
return service, nil
|
|
}
|
|
|
|
// ProtokubeImageName returns the docker image for protokube
|
|
func (t *ProtokubeBuilder) ProtokubeImageName() string {
|
|
name := ""
|
|
if t.NodeupConfig.ProtokubeImage != nil && t.NodeupConfig.ProtokubeImage.Name != "" {
|
|
name = t.NodeupConfig.ProtokubeImage.Name
|
|
}
|
|
if name == "" {
|
|
// use current default corresponding to this version of nodeup
|
|
name = kops.DefaultProtokubeImageName()
|
|
}
|
|
return name
|
|
}
|
|
|
|
// ProtokubeImagePullCommand returns the command to pull the image
|
|
func (t *ProtokubeBuilder) ProtokubeImagePullCommand() string {
|
|
source := ""
|
|
if t.NodeupConfig.ProtokubeImage != nil {
|
|
source = t.NodeupConfig.ProtokubeImage.Source
|
|
}
|
|
if source == "" {
|
|
// Nothing to pull; return dummy value
|
|
return "/bin/true"
|
|
}
|
|
if strings.HasPrefix(source, "http:") || strings.HasPrefix(source, "https:") || strings.HasPrefix(source, "s3:") {
|
|
// We preloaded the image; return a dummy value
|
|
return "/bin/true"
|
|
}
|
|
return "/usr/bin/docker pull " + t.NodeupConfig.ProtokubeImage.Source
|
|
}
|
|
|
|
type ProtokubeFlags struct {
|
|
Master *bool `json:"master,omitempty" flag:"master"`
|
|
Containerized *bool `json:"containerized,omitempty" flag:"containerized"`
|
|
LogLevel *int32 `json:"logLevel,omitempty" flag:"v"`
|
|
|
|
InitializeRBAC *bool `json:"initializeRBAC,omitempty" flag:"initialize-rbac"`
|
|
|
|
DNSProvider *string `json:"dnsProvider,omitempty" flag:"dns"`
|
|
|
|
Zone []string `json:"zone,omitempty" flag:"zone"`
|
|
|
|
Channels []string `json:"channels,omitempty" flag:"channels"`
|
|
|
|
DNSInternalSuffix *string `json:"dnsInternalSuffix,omitempty" flag:"dns-internal-suffix"`
|
|
Cloud *string `json:"cloud,omitempty" flag:"cloud"`
|
|
|
|
ApplyTaints *bool `json:"applyTaints,omitempty" flag:"apply-taints"`
|
|
}
|
|
|
|
// ProtokubeFlags returns the flags object for protokube
|
|
func (t *ProtokubeBuilder) ProtokubeFlags(k8sVersion semver.Version) *ProtokubeFlags {
|
|
f := &ProtokubeFlags{}
|
|
|
|
master := t.IsMaster
|
|
|
|
f.Master = fi.Bool(master)
|
|
if master {
|
|
f.Channels = t.NodeupConfig.Channels
|
|
}
|
|
|
|
if k8sVersion.Major == 1 && k8sVersion.Minor >= 6 {
|
|
if master {
|
|
f.InitializeRBAC = fi.Bool(true)
|
|
}
|
|
}
|
|
|
|
f.LogLevel = fi.Int32(4)
|
|
f.Containerized = fi.Bool(true)
|
|
|
|
zone := t.Cluster.Spec.DNSZone
|
|
if zone != "" {
|
|
if strings.Contains(zone, ".") {
|
|
// match by name
|
|
f.Zone = append(f.Zone, zone)
|
|
} else {
|
|
// match by id
|
|
f.Zone = append(f.Zone, "*/"+zone)
|
|
}
|
|
} else {
|
|
glog.Warningf("DNSZone not specified; protokube won't be able to update DNS")
|
|
// TODO: Should we permit wildcard updates if zone is not specified?
|
|
//argv = append(argv, "--zone=*/*")
|
|
}
|
|
|
|
if t.Cluster.Spec.CloudProvider != "" {
|
|
f.Cloud = fi.String(t.Cluster.Spec.CloudProvider)
|
|
|
|
switch fi.CloudProviderID(t.Cluster.Spec.CloudProvider) {
|
|
case fi.CloudProviderAWS:
|
|
f.DNSProvider = fi.String("aws-route53")
|
|
case fi.CloudProviderGCE:
|
|
f.DNSProvider = fi.String("google-clouddns")
|
|
default:
|
|
glog.Warningf("Unknown cloudprovider %q; won't set DNS provider")
|
|
}
|
|
}
|
|
|
|
f.DNSInternalSuffix = fi.String(".internal." + t.Cluster.ObjectMeta.Name)
|
|
|
|
if k8sVersion.Major == 1 && k8sVersion.Minor <= 5 {
|
|
f.ApplyTaints = fi.Bool(true)
|
|
}
|
|
|
|
return f
|
|
}
|
|
|
|
func (t *ProtokubeBuilder) ProtokubeEnvironmentVariables() string {
|
|
// Pass in required credentials when using user-defined s3 endpoint
|
|
if os.Getenv("S3_ENDPOINT") != "" {
|
|
var buffer bytes.Buffer
|
|
buffer.WriteString(" ")
|
|
buffer.WriteString("-e S3_ENDPOINT=")
|
|
buffer.WriteString("'")
|
|
buffer.WriteString(os.Getenv("S3_ENDPOINT"))
|
|
buffer.WriteString("'")
|
|
buffer.WriteString(" -e S3_REGION=")
|
|
buffer.WriteString("'")
|
|
buffer.WriteString(os.Getenv("S3_REGION"))
|
|
buffer.WriteString("'")
|
|
buffer.WriteString(" -e S3_ACCESS_KEY_ID=")
|
|
buffer.WriteString("'")
|
|
buffer.WriteString(os.Getenv("S3_ACCESS_KEY_ID"))
|
|
buffer.WriteString("'")
|
|
buffer.WriteString(" -e S3_SECRET_ACCESS_KEY=")
|
|
buffer.WriteString("'")
|
|
buffer.WriteString(os.Getenv("S3_SECRET_ACCESS_KEY"))
|
|
buffer.WriteString("'")
|
|
buffer.WriteString(" ")
|
|
|
|
return buffer.String()
|
|
}
|
|
|
|
return ""
|
|
}
|