mirror of https://github.com/k3s-io/k3s
parent
2e250c308b
commit
287e0f44c9
|
@ -1,10 +1,9 @@
|
|||
./bin
|
||||
./build
|
||||
./pkg/data/zz_generated_bindata.go
|
||||
./package/data.tar.gz
|
||||
./.vagrant
|
||||
./.dapper
|
||||
./data-dir
|
||||
./dist
|
||||
./.trash-cache
|
||||
./image/root
|
||||
./image/agent
|
||||
./image/go_build_agent
|
||||
./image/main.squashfs
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
/image/go_build_agent
|
||||
/image/main.squashfs
|
||||
/package/k3s
|
||||
/package/data.tar.gz
|
||||
/pkg/data/zz_generated_bindata.go
|
||||
__pycache__
|
||||
/tests/.pytest_cache/
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
FROM golang:1.11-alpine3.8
|
||||
FROM golang:1.11.4-alpine3.8
|
||||
# FROM arm=golang@sha256:fe81149b4e7f07ecb558fd16cdbcdb11e739846a046e38cc6e170aa39a67e7ec arm64=golang@sha256:da9c2d140ed4bf911ef8f6d9437912b80497c256ef2235c65836eac83d1c0ce7
|
||||
|
||||
RUN apk -U --no-cache add bash git gcc musl-dev docker vim less file curl wget ca-certificates jq linux-headers zlib-dev tar zip squashfs-tools npm coreutils \
|
||||
python3 py3-pip python3-dev openssl-dev libffi-dev libseccomp libseccomp-dev make
|
||||
|
@ -6,14 +7,15 @@ RUN pip3 install 'tox==3.6.0'
|
|||
RUN apk -U --no-cache --repository http://dl-3.alpinelinux.org/alpine/edge/main/ add sqlite-dev sqlite-static
|
||||
RUN go get -d golang.org/x/lint/golint && \
|
||||
git -C /go/src/golang.org/x/lint/golint checkout -b current 06c8688daad7faa9da5a0c2f163a3d14aac986ca && \
|
||||
go install golang.org/x/lint/golint && \
|
||||
rm -rf /go/src /go/pkg
|
||||
go install golang.org/x/lint/golint
|
||||
RUN go get -d github.com/alecthomas/gometalinter && \
|
||||
git -C /go/src/github.com/alecthomas/gometalinter checkout -b current v2.0.11 && \
|
||||
go install github.com/alecthomas/gometalinter && \
|
||||
gometalinter --install && \
|
||||
rm -rf /go/src /go/pkg
|
||||
gometalinter --install
|
||||
RUN rm -rf /go/src /go/pkg
|
||||
|
||||
ARG DAPPER_HOST_ARCH
|
||||
ENV ARCH $DAPPER_HOST_ARCH
|
||||
ENV DAPPER_RUN_ARGS --privileged
|
||||
ENV DAPPER_ENV REPO TAG DRONE_TAG IMAGE_NAME
|
||||
ENV DAPPER_SOURCE /go/src/github.com/rancher/k3s/
|
||||
|
|
|
@ -72,13 +72,13 @@ func getAssetAndDir(dataDir string) (string, string) {
|
|||
}
|
||||
|
||||
func extract(asset, dir string) error {
|
||||
logrus.Infof("Asset dir %s", dir)
|
||||
logrus.Debugf("Asset dir %s", dir)
|
||||
|
||||
if _, err := os.Stat(dir); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
logrus.Infof("Staging to dir %s", dir)
|
||||
logrus.Infof("Preparing data dir %s", dir)
|
||||
|
||||
content, err := data.Asset(asset)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
version: '3'
|
||||
services:
|
||||
server:
|
||||
image: rancher/k3s:fa08d60-dirty-amd64
|
||||
command: server --disable-agent
|
||||
environment:
|
||||
- K3S_CLUSTER_SECRET=somethingtotallyrandom
|
||||
- K3S_KUBECONFIG_OUTPUT=/output/kubeconfig.yaml
|
||||
- K3S_KUBECONFIG_MODE=666
|
||||
volumes:
|
||||
- k3s-server:/var/lib/rancher/k3s
|
||||
# This is just so that we get the kubeconfig file out
|
||||
- .:/output
|
||||
ports:
|
||||
- 6443:6443
|
||||
|
||||
node:
|
||||
image: rancher/k3s:fa08d60-dirty-amd64
|
||||
tmpfs:
|
||||
- /run
|
||||
- /var/run
|
||||
privileged: true
|
||||
environment:
|
||||
- K3S_URL=https://server:6443
|
||||
- K3S_CLUSTER_SECRET=somethingtotallyrandom
|
||||
|
||||
volumes:
|
||||
k3s-server: {}
|
|
@ -0,0 +1,175 @@
|
|||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: coredns
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
labels:
|
||||
kubernetes.io/bootstrapping: rbac-defaults
|
||||
name: system:coredns
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- endpoints
|
||||
- services
|
||||
- pods
|
||||
- namespaces
|
||||
verbs:
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- nodes
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
annotations:
|
||||
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||
labels:
|
||||
kubernetes.io/bootstrapping: rbac-defaults
|
||||
name: system:coredns
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: system:coredns
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: coredns
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: coredns
|
||||
namespace: kube-system
|
||||
data:
|
||||
Corefile: |
|
||||
.:53 {
|
||||
errors
|
||||
health
|
||||
kubernetes cluster.local in-addr.arpa ip6.arpa {
|
||||
pods insecure
|
||||
upstream
|
||||
fallthrough in-addr.arpa ip6.arpa
|
||||
}
|
||||
prometheus :9153
|
||||
proxy . 1.1.1.1
|
||||
cache 30
|
||||
loop
|
||||
reload
|
||||
loadbalance
|
||||
}
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: coredns
|
||||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: kube-dns
|
||||
kubernetes.io/name: "CoreDNS"
|
||||
spec:
|
||||
#replicas: 1
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s-app: kube-dns
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: kube-dns
|
||||
spec:
|
||||
serviceAccountName: coredns
|
||||
tolerations:
|
||||
- key: "CriticalAddonsOnly"
|
||||
operator: "Exists"
|
||||
nodeSelector:
|
||||
beta.kubernetes.io/os: linux
|
||||
containers:
|
||||
- name: coredns
|
||||
image: coredns/coredns:1.3.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits:
|
||||
memory: 170Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 70Mi
|
||||
args: [ "-conf", "/etc/coredns/Corefile" ]
|
||||
volumeMounts:
|
||||
- name: config-volume
|
||||
mountPath: /etc/coredns
|
||||
readOnly: true
|
||||
ports:
|
||||
- containerPort: 53
|
||||
name: dns
|
||||
protocol: UDP
|
||||
- containerPort: 53
|
||||
name: dns-tcp
|
||||
protocol: TCP
|
||||
- containerPort: 9153
|
||||
name: metrics
|
||||
protocol: TCP
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
add:
|
||||
- NET_BIND_SERVICE
|
||||
drop:
|
||||
- all
|
||||
readOnlyRootFilesystem: true
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 60
|
||||
timeoutSeconds: 5
|
||||
successThreshold: 1
|
||||
failureThreshold: 5
|
||||
dnsPolicy: Default
|
||||
volumes:
|
||||
- name: config-volume
|
||||
configMap:
|
||||
name: coredns
|
||||
items:
|
||||
- key: Corefile
|
||||
path: Corefile
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: kube-dns
|
||||
namespace: kube-system
|
||||
annotations:
|
||||
prometheus.io/port: "9153"
|
||||
prometheus.io/scrape: "true"
|
||||
labels:
|
||||
k8s-app: kube-dns
|
||||
kubernetes.io/cluster-service: "true"
|
||||
kubernetes.io/name: "CoreDNS"
|
||||
spec:
|
||||
selector:
|
||||
k8s-app: kube-dns
|
||||
clusterIP: 10.43.0.10
|
||||
ports:
|
||||
- name: dns
|
||||
port: 53
|
||||
protocol: UDP
|
||||
- name: dns-tcp
|
||||
port: 53
|
||||
protocol: TCP
|
||||
- name: metrics
|
||||
port: 9153
|
||||
protocol: TCP
|
|
@ -12,8 +12,6 @@ import (
|
|||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/deviceplugin/v1beta1"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rancher/k3s/pkg/cli/cmds"
|
||||
"github.com/rancher/k3s/pkg/daemons/config"
|
||||
|
@ -22,6 +20,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/client-go/util/cert"
|
||||
"k8s.io/kubernetes/pkg/kubelet/apis/deviceplugin/v1beta1"
|
||||
)
|
||||
|
||||
func Get(ctx context.Context, agent cmds.Agent) *config.Node {
|
||||
|
|
|
@ -6,8 +6,6 @@ import (
|
|||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/rancher/k3s/pkg/agent/config"
|
||||
"github.com/rancher/k3s/pkg/agent/containerd"
|
||||
"github.com/rancher/k3s/pkg/agent/flannel"
|
||||
|
@ -17,6 +15,7 @@ import (
|
|||
"github.com/rancher/k3s/pkg/cli/cmds"
|
||||
"github.com/rancher/k3s/pkg/daemons/agent"
|
||||
"github.com/rancher/norman/pkg/clientaccess"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func run(ctx context.Context, cfg cmds.Agent) error {
|
||||
|
@ -65,6 +64,10 @@ func run(ctx context.Context, cfg cmds.Agent) error {
|
|||
func Run(ctx context.Context, cfg cmds.Agent) error {
|
||||
cfg.DataDir = filepath.Join(cfg.DataDir, "agent")
|
||||
|
||||
if cfg.ClusterSecret != "" {
|
||||
cfg.Token = "K10node:" + cfg.ClusterSecret
|
||||
}
|
||||
|
||||
for {
|
||||
tmpFile, err := clientaccess.AgentAccessInfoToTempKubeConfig("", cfg.ServerURL, cfg.Token)
|
||||
if err != nil {
|
||||
|
|
|
@ -17,7 +17,7 @@ func Run(ctx *cli.Context) error {
|
|||
return fmt.Errorf("agent must be ran as root")
|
||||
}
|
||||
|
||||
if cmds.AgentConfig.Token == "" {
|
||||
if cmds.AgentConfig.Token == "" && cmds.AgentConfig.ClusterSecret == "" {
|
||||
return fmt.Errorf("--token is required")
|
||||
}
|
||||
|
||||
|
|
|
@ -8,14 +8,15 @@ import (
|
|||
)
|
||||
|
||||
type Agent struct {
|
||||
Token string
|
||||
ServerURL string
|
||||
DataDir string
|
||||
NodeIP string
|
||||
NodeName string
|
||||
Docker bool
|
||||
NoFlannel bool
|
||||
Debug bool
|
||||
Token string
|
||||
ServerURL string
|
||||
DataDir string
|
||||
NodeIP string
|
||||
NodeName string
|
||||
ClusterSecret string
|
||||
Docker bool
|
||||
NoFlannel bool
|
||||
Debug bool
|
||||
AgentShared
|
||||
}
|
||||
|
||||
|
@ -74,6 +75,12 @@ func NewAgentCommand(action func(ctx *cli.Context) error) cli.Command {
|
|||
Usage: "Disable embedded flannel",
|
||||
Destination: &AgentConfig.NoFlannel,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cluster-secret",
|
||||
Usage: "Shared secret used to bootstrap a cluster",
|
||||
Destination: &AgentConfig.ClusterSecret,
|
||||
EnvVar: "K3S_CLUSTER_SECRET",
|
||||
},
|
||||
NodeNameFlag,
|
||||
NodeIPFlag,
|
||||
},
|
||||
|
|
|
@ -5,13 +5,16 @@ import (
|
|||
)
|
||||
|
||||
type Server struct {
|
||||
Log string
|
||||
ClusterCIDR string
|
||||
ServiceCIDR string
|
||||
HTTPSPort int
|
||||
HTTPPort int
|
||||
DataDir string
|
||||
DisableAgent bool
|
||||
Log string
|
||||
ClusterCIDR string
|
||||
ClusterSecret string
|
||||
ServiceCIDR string
|
||||
HTTPSPort int
|
||||
HTTPPort int
|
||||
DataDir string
|
||||
DisableAgent bool
|
||||
KubeConfigOutput string
|
||||
KubeConfigMode string
|
||||
}
|
||||
|
||||
var ServerConfig Server
|
||||
|
@ -55,6 +58,28 @@ func NewServerCommand(action func(*cli.Context) error) cli.Command {
|
|||
Usage: "Network CIDR to use for pod IPs",
|
||||
Destination: &ServerConfig.ClusterCIDR,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cluster-secret",
|
||||
Usage: "Shared secret used to bootstrap a cluster",
|
||||
Destination: &ServerConfig.ClusterSecret,
|
||||
EnvVar: "K3S_CLUSTER_SECRET",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "no-deploy",
|
||||
Usage: "Do not deploy packaged manifests (example: coredns)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "write-kubeconfig,o",
|
||||
Usage: "Write kubeconfig for admin client to this file",
|
||||
Destination: &ServerConfig.KubeConfigOutput,
|
||||
EnvVar: "K3S_KUBECONFIG_OUTPUT",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "write-kubeconfig-mode",
|
||||
Usage: "Write kubeconfig with this mode",
|
||||
Destination: &ServerConfig.KubeConfigMode,
|
||||
EnvVar: "K3S_KUBECONFIG_MODE",
|
||||
},
|
||||
NodeIPFlag,
|
||||
NodeNameFlag,
|
||||
},
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/natefinch/lumberjack"
|
||||
|
@ -15,6 +16,8 @@ import (
|
|||
"github.com/rancher/norman/signal"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3" // ensure we have sqlite
|
||||
)
|
||||
|
||||
func setupLogging(app *cli.Context) {
|
||||
|
@ -60,10 +63,23 @@ func run(app *cli.Context, cfg *cmds.Server) error {
|
|||
}
|
||||
|
||||
serverConfig := server.Config{}
|
||||
serverConfig.ControlConfig.ClusterSecret = cfg.ClusterSecret
|
||||
serverConfig.ControlConfig.DataDir = cfg.DataDir
|
||||
serverConfig.ControlConfig.KubeConfigOutput = cfg.KubeConfigOutput
|
||||
serverConfig.ControlConfig.KubeConfigMode = cfg.KubeConfigMode
|
||||
serverConfig.TLSConfig.HTTPSPort = cfg.HTTPSPort
|
||||
serverConfig.TLSConfig.HTTPPort = cfg.HTTPPort
|
||||
|
||||
// TODO: support etcd
|
||||
serverConfig.ControlConfig.NoLeaderElect = true
|
||||
|
||||
for _, noDeploy := range app.StringSlice("no-deploy") {
|
||||
if !strings.HasSuffix(noDeploy, ".yaml") {
|
||||
noDeploy = noDeploy + ".yaml"
|
||||
}
|
||||
serverConfig.ControlConfig.Skips = append(serverConfig.ControlConfig.Skips, noDeploy)
|
||||
}
|
||||
|
||||
logrus.Info("Starting k3s ", app.App.Version)
|
||||
ctx := signal.SigTermCancelContext(context.Background())
|
||||
certs, err := server.StartServer(ctx, &serverConfig)
|
||||
|
@ -82,7 +98,7 @@ func run(app *cli.Context, cfg *cmds.Server) error {
|
|||
token := server.FormatToken(serverConfig.ControlConfig.Runtime.NodeToken, certs)
|
||||
|
||||
agentConfig := cmds.AgentConfig
|
||||
agentConfig.DataDir = serverConfig.ControlConfig.DataDir
|
||||
agentConfig.DataDir = filepath.Dir(serverConfig.ControlConfig.DataDir)
|
||||
agentConfig.ServerURL = url
|
||||
agentConfig.Token = token
|
||||
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
package agent
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/net"
|
||||
|
||||
"github.com/rancher/k3s/pkg/daemons/config"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apiserver/pkg/util/logs"
|
||||
app2 "k8s.io/kubernetes/cmd/kube-proxy/app"
|
||||
"k8s.io/kubernetes/cmd/kubelet/app"
|
||||
|
@ -56,7 +58,6 @@ func kubelet(cfg *config.Agent) {
|
|||
"--kubeconfig", cfg.KubeConfig,
|
||||
"--eviction-hard", "imagefs.available<5%,nodefs.available<5%",
|
||||
"--eviction-minimum-reclaim", "imagefs.available=10%,nodefs.available=10%",
|
||||
"--node-ip", cfg.NodeIP,
|
||||
"--fail-swap-on=false",
|
||||
//"--cgroup-root", "/k3s",
|
||||
"--cgroup-driver", "cgroupfs",
|
||||
|
@ -92,6 +93,10 @@ func kubelet(cfg *config.Agent) {
|
|||
if err != nil || defaultIP.String() != cfg.NodeIP {
|
||||
args = append(args, "--node-ip", cfg.NodeIP)
|
||||
}
|
||||
if !hasCFS() {
|
||||
logrus.Warn("Disabling CPU quotas due to missing cpu.cfs_period_us")
|
||||
args = append(args, "--cpu-cfs-quota=false")
|
||||
}
|
||||
args = append(args, cfg.ExtraKubeletArgs...)
|
||||
|
||||
command.SetArgs(args)
|
||||
|
@ -101,3 +106,30 @@ func kubelet(cfg *config.Agent) {
|
|||
logrus.Fatalf("kubelet exited: %v", command.Execute())
|
||||
}()
|
||||
}
|
||||
|
||||
func hasCFS() bool {
|
||||
f, err := os.Open("/proc/self/cgroup")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scan := bufio.NewScanner(f)
|
||||
for scan.Scan() {
|
||||
parts := strings.Split(scan.Text(), ":")
|
||||
if len(parts) < 3 {
|
||||
continue
|
||||
}
|
||||
systems := strings.Split(parts[1], ",")
|
||||
for _, system := range systems {
|
||||
if system == "cpu" {
|
||||
p := filepath.Join("/sys/fs/cgroup", parts[1], parts[2], "cpu.cfs_period_us")
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -48,11 +48,15 @@ type Agent struct {
|
|||
type Control struct {
|
||||
AdvertisePort int
|
||||
ListenPort int
|
||||
ClusterSecret string
|
||||
ClusterIPRange *net.IPNet
|
||||
ServiceIPRange *net.IPNet
|
||||
ClusterDNS net.IP
|
||||
NoCoreDNS bool
|
||||
KubeConfigOutput string
|
||||
KubeConfigMode string
|
||||
DataDir string
|
||||
Skips []string
|
||||
ETCDEndpoints []string
|
||||
ETCDKeyFile string
|
||||
ETCDCertFile string
|
||||
|
@ -61,7 +65,7 @@ type Control struct {
|
|||
ExtraAPIArgs []string
|
||||
ExtraControllerArgs []string
|
||||
ExtraSchedulerAPIArgs []string
|
||||
//NodeConfig Node
|
||||
NoLeaderElect bool
|
||||
|
||||
Runtime *ControlRuntime `json:"-"`
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package control
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
cryptorand "crypto/rand"
|
||||
"crypto/rsa"
|
||||
|
@ -23,8 +24,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/rancher/k3s/pkg/daemons/config"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3" // sqlite
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
|
@ -96,7 +95,6 @@ func Server(ctx context.Context, cfg *config.Control) error {
|
|||
func controllerManager(cfg *config.Control, runtime *config.ControlRuntime) {
|
||||
args := []string{
|
||||
"--kubeconfig", runtime.KubeConfigSystem,
|
||||
"--leader-elect=true",
|
||||
"--service-account-private-key-file", runtime.ServiceKey,
|
||||
"--allocate-node-cidrs",
|
||||
"--cluster-cidr", cfg.ClusterIPRange.String(),
|
||||
|
@ -104,6 +102,9 @@ func controllerManager(cfg *config.Control, runtime *config.ControlRuntime) {
|
|||
"--port", "0",
|
||||
"--secure-port", "0",
|
||||
}
|
||||
if cfg.NoLeaderElect {
|
||||
args = append(args, "--leader-elect=false")
|
||||
}
|
||||
args = append(args, cfg.ExtraControllerArgs...)
|
||||
command := cmapp.NewControllerManagerCommand()
|
||||
command.SetArgs(args)
|
||||
|
@ -120,6 +121,9 @@ func scheduler(cfg *config.Control, runtime *config.ControlRuntime) {
|
|||
"--port", "0",
|
||||
"--secure-port", "0",
|
||||
}
|
||||
if cfg.NoLeaderElect {
|
||||
args = append(args, "--leader-elect=false")
|
||||
}
|
||||
args = append(args, cfg.ExtraSchedulerAPIArgs...)
|
||||
command := sapp.NewSchedulerCommand()
|
||||
command.SetArgs(args)
|
||||
|
@ -299,9 +303,47 @@ func readTokens(runtime *config.ControlRuntime) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func ensureNodeToken(config *config.Control, runtime *config.ControlRuntime) error {
|
||||
if config.ClusterSecret == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
f, err := os.Open(runtime.PasswdFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
buf := &strings.Builder{}
|
||||
scan := bufio.NewScanner(f)
|
||||
for scan.Scan() {
|
||||
line := scan.Text()
|
||||
parts := strings.Split(line, ",")
|
||||
if len(parts) < 4 {
|
||||
continue
|
||||
}
|
||||
if parts[1] == "node" {
|
||||
if parts[0] == config.ClusterSecret {
|
||||
return nil
|
||||
}
|
||||
parts[0] = config.ClusterSecret
|
||||
line = strings.Join(parts, ",")
|
||||
}
|
||||
buf.WriteString(line)
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
|
||||
if scan.Err() != nil {
|
||||
return scan.Err()
|
||||
}
|
||||
|
||||
f.Close()
|
||||
return ioutil.WriteFile(runtime.PasswdFile, []byte(buf.String()), 0600)
|
||||
}
|
||||
|
||||
func genUsers(config *config.Control, runtime *config.ControlRuntime) error {
|
||||
if s, err := os.Stat(runtime.PasswdFile); err == nil && s.Size() > 0 {
|
||||
return nil
|
||||
return ensureNodeToken(config, runtime)
|
||||
}
|
||||
|
||||
adminToken, err := getToken()
|
||||
|
@ -317,6 +359,10 @@ func genUsers(config *config.Control, runtime *config.ControlRuntime) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if config.ClusterSecret != "" {
|
||||
nodeToken = config.ClusterSecret
|
||||
}
|
||||
|
||||
passwd := fmt.Sprintf(`%s,admin,admin,system:masters
|
||||
%s,system,system,system:masters
|
||||
%s,node,node,system:masters
|
||||
|
|
|
@ -0,0 +1,281 @@
|
|||
package deploy
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
errors2 "github.com/pkg/errors"
|
||||
|
||||
v1 "github.com/rancher/k3s/types/apis/k3s.cattle.io/v1"
|
||||
"github.com/rancher/norman"
|
||||
"github.com/rancher/norman/objectclient"
|
||||
"github.com/rancher/norman/pkg/objectset"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
yamlDecoder "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
ns = "kube-system"
|
||||
)
|
||||
|
||||
func WatchFiles(ctx context.Context, skips []string, bases ...string) error {
|
||||
server := norman.GetServer(ctx)
|
||||
addons := v1.ClientsFrom(ctx).Addon
|
||||
|
||||
w := &watcher{
|
||||
addonCache: addons.Cache(),
|
||||
addons: addons,
|
||||
skips: skips,
|
||||
bases: bases,
|
||||
restConfig: *server.Runtime.LocalConfig,
|
||||
discovery: server.K8sClient.Discovery(),
|
||||
clients: map[schema.GroupVersionKind]*objectclient.ObjectClient{},
|
||||
}
|
||||
|
||||
addons.Enqueue("", "_start_")
|
||||
addons.Interface().AddHandler(ctx, "addon-start", func(key string, _ *v1.Addon) (runtime.Object, error) {
|
||||
w.started = true
|
||||
return nil, w.listFiles(true)
|
||||
})
|
||||
|
||||
w.start(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
type watcher struct {
|
||||
started bool
|
||||
addonCache v1.AddonClientCache
|
||||
addons v1.AddonClient
|
||||
bases []string
|
||||
skips []string
|
||||
restConfig rest.Config
|
||||
discovery discovery.DiscoveryInterface
|
||||
clients map[schema.GroupVersionKind]*objectclient.ObjectClient
|
||||
}
|
||||
|
||||
func (w *watcher) start(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-time.After(15 * time.Second):
|
||||
if err := w.listFiles(false); err != nil {
|
||||
logrus.Errorf("failed to process config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *watcher) listFiles(force bool) error {
|
||||
var errs []error
|
||||
for _, base := range w.bases {
|
||||
if err := w.listFilesIn(base, force); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
}
|
||||
return types.NewErrors(errs...)
|
||||
}
|
||||
|
||||
func (w *watcher) listFilesIn(base string, force bool) error {
|
||||
if !w.started {
|
||||
return nil
|
||||
}
|
||||
|
||||
files, err := ioutil.ReadDir(base)
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
skips := map[string]bool{}
|
||||
for _, skip := range w.skips {
|
||||
skips[skip] = true
|
||||
}
|
||||
for _, file := range files {
|
||||
if strings.HasSuffix(file.Name(), ".skip") {
|
||||
skips[strings.TrimSuffix(file.Name(), ".skip")] = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var errs []error
|
||||
for _, file := range files {
|
||||
if strings.HasSuffix(file.Name(), ".skip") || skips[file.Name()] {
|
||||
continue
|
||||
}
|
||||
p := filepath.Join(base, file.Name())
|
||||
if err := w.deploy(p, !force); err != nil {
|
||||
errs = append(errs, errors2.Wrapf(err, "failed to process %s", p))
|
||||
}
|
||||
}
|
||||
|
||||
return types.NewErrors(errs...)
|
||||
}
|
||||
|
||||
func (w *watcher) deploy(path string, compareChecksum bool) error {
|
||||
content, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := name(path)
|
||||
addon, err := w.addon(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
checksum := checksum(content)
|
||||
if compareChecksum && checksum == addon.Spec.Checksum {
|
||||
return nil
|
||||
}
|
||||
|
||||
objectSet, err := objectSet(content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clients, err := w.apply(addon, objectSet)
|
||||
if w.clients == nil {
|
||||
w.clients = map[schema.GroupVersionKind]*objectclient.ObjectClient{}
|
||||
}
|
||||
|
||||
addon.Spec.Source = path
|
||||
addon.Spec.Checksum = checksum
|
||||
addon.Status.GVKs = nil
|
||||
|
||||
for gvk, client := range clients {
|
||||
addon.Status.GVKs = append(addon.Status.GVKs, gvk)
|
||||
w.clients[gvk] = client
|
||||
}
|
||||
|
||||
if addon.UID == "" {
|
||||
_, err := w.addons.Create(&addon)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.addons.Update(&addon)
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *watcher) addon(name string) (v1.Addon, error) {
|
||||
addon, err := w.addonCache.Get(ns, name)
|
||||
if errors.IsNotFound(err) {
|
||||
addon = v1.NewAddon(ns, name, v1.Addon{})
|
||||
} else if err != nil {
|
||||
return v1.Addon{}, err
|
||||
}
|
||||
return *addon, nil
|
||||
}
|
||||
|
||||
func (w *watcher) apply(addon v1.Addon, set *objectset.ObjectSet) (map[schema.GroupVersionKind]*objectclient.ObjectClient, error) {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
op := objectset.NewProcessor(addon.Name)
|
||||
op.AllowDiscovery(w.discovery, w.restConfig)
|
||||
|
||||
ds := op.NewDesiredSet(nil, set)
|
||||
|
||||
for _, gvk := range addon.Status.GVKs {
|
||||
client, ok := w.clients[gvk]
|
||||
if !ok {
|
||||
client, err = objectset.NewDiscoveredClient(gvk, w.restConfig, w.discovery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
ds.AddDiscoveredClient(gvk, client)
|
||||
}
|
||||
|
||||
if err := ds.Apply(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ds.DiscoveredClients(), nil
|
||||
}
|
||||
|
||||
func objectSet(content []byte) (*objectset.ObjectSet, error) {
|
||||
objs, err := yamlToObjects(bytes.NewBuffer(content))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
os := objectset.NewObjectSet()
|
||||
os.Add(objs...)
|
||||
return os, nil
|
||||
}
|
||||
|
||||
func name(path string) string {
|
||||
name := filepath.Base(path)
|
||||
return strings.SplitN(name, ".", 2)[0]
|
||||
}
|
||||
|
||||
func checksum(bytes []byte) string {
|
||||
d := sha256.Sum256(bytes)
|
||||
return hex.EncodeToString(d[:])
|
||||
}
|
||||
|
||||
func yamlToObjects(in io.Reader) ([]runtime.Object, error) {
|
||||
var result []runtime.Object
|
||||
reader := yamlDecoder.NewYAMLReader(bufio.NewReaderSize(in, 4096))
|
||||
for {
|
||||
raw, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
obj, err := toObjects(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result = append(result, obj...)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func toObjects(bytes []byte) ([]runtime.Object, error) {
|
||||
bytes, err := yamlDecoder.ToJSON(bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
obj, _, err := unstructured.UnstructuredJSONScheme.Decode(bytes, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if l, ok := obj.(*unstructured.UnstructuredList); ok {
|
||||
var result []runtime.Object
|
||||
for _, obj := range l.Items {
|
||||
copy := obj
|
||||
result = append(result, ©)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
return []runtime.Object{obj}, nil
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package deploy
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func Stage(dataDir string) error {
|
||||
os.MkdirAll(dataDir, 0700)
|
||||
|
||||
for _, name := range AssetNames() {
|
||||
content, err := Asset(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p := filepath.Join(dataDir, name)
|
||||
logrus.Info("Writing manifest: ", p)
|
||||
if err := ioutil.WriteFile(p, content, 0600); err != nil {
|
||||
return errors.Wrapf(err, "failed to write to %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
// Code generated by go-bindata.
|
||||
// sources:
|
||||
// manifests/coredns.yaml
|
||||
// DO NOT EDIT!
|
||||
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func bindataRead(data []byte, name string) ([]byte, error) {
|
||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, gz)
|
||||
clErr := gz.Close()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
if clErr != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
type asset struct {
|
||||
bytes []byte
|
||||
info os.FileInfo
|
||||
}
|
||||
|
||||
type bindataFileInfo struct {
|
||||
name string
|
||||
size int64
|
||||
mode os.FileMode
|
||||
modTime time.Time
|
||||
}
|
||||
|
||||
func (fi bindataFileInfo) Name() string {
|
||||
return fi.name
|
||||
}
|
||||
func (fi bindataFileInfo) Size() int64 {
|
||||
return fi.size
|
||||
}
|
||||
func (fi bindataFileInfo) Mode() os.FileMode {
|
||||
return fi.mode
|
||||
}
|
||||
func (fi bindataFileInfo) ModTime() time.Time {
|
||||
return fi.modTime
|
||||
}
|
||||
func (fi bindataFileInfo) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
func (fi bindataFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _corednsYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x56\x4d\x73\xdb\x36\x13\xbe\xeb\x57\x60\xf8\x5e\x5f\xca\xd2\xb8\x49\x5d\xdc\x12\xdb\x4d\x3d\xd3\xb8\x1a\xdb\xc9\xa5\xd3\xc9\xac\xc0\x95\x88\x1a\xc4\xa2\xc0\x52\xb1\xda\xe6\xbf\x77\xc0\x2f\x83\x34\x9d\x49\x32\xa1\x0e\x02\xb0\xd8\x67\x81\xfd\x78\x16\xe0\xf4\x7b\xf4\x41\x93\x95\xe2\xb0\x5e\xdc\x6b\x5b\x48\x71\x8b\xfe\xa0\x15\xbe\x52\x8a\x6a\xcb\x8b\x0a\x19\x0a\x60\x90\x0b\x21\x2c\x54\x28\x85\x22\x8f\x85\x0d\xdd\x3c\x38\x50\x28\xc5\x7d\xbd\xc5\x3c\x1c\x03\x63\xb5\xc8\xf3\x7c\x91\x42\xfb\x2d\xa8\x25\xd4\x5c\x92\xd7\x7f\x03\x6b\xb2\xcb\xfb\xb3\xb0\xd4\x74\x72\x58\x6f\x91\xa1\xb7\x7c\x6e\xea\xc0\xe8\x6f\xc8\xe0\xc8\xac\x81\x2d\x9a\x10\x47\xa2\xb1\xe3\x2d\x32\x36\xfa\x5b\x22\x0e\xec\xc1\x39\x6d\xf7\xad\xa1\xbc\xc0\x1d\xd4\x86\xc3\x70\xde\xf6\x54\xb2\x3f\xb6\xaf\x0d\x06\xb9\xc8\x05\x38\xfd\xc6\x53\xed\x1a\xe4\x5c\x64\xd9\x42\x08\x8f\x81\x6a\xaf\xb0\x5b\x43\x5b\x38\xd2\xb6\x01\xcb\x45\x68\x3d\xd3\x4e\x1c\x15\xed\x60\x70\x42\x9c\x1e\xd0\x6f\x3b\x5d\xa3\x03\x37\x83\x8f\xc0\xaa\xfc\x32\x7b\x96\x8a\x29\xcc\x1e\xf9\x7b\x38\xf4\xb5\xb6\x85\xb6\xfb\x91\x5f\xc1\x5a\xe2\x46\xbd\x73\xee\x1c\xee\xc8\xdf\x50\x33\xd5\xae\x00\x46\x29\x32\xf6\x35\x66\xdf\x3f\x3c\x64\xf0\x06\x77\xcd\xf9\x3a\x87\x7d\xe6\xc2\x0b\x21\x9e\xe6\xce\x33\xc8\xa1\xde\xfe\x89\x8a\x9b\xd8\xcf\xa6\xfa\x37\x27\xf8\x50\x3b\xe7\x64\x77\x7a\xff\x16\xdc\xb7\x94\x4d\xbf\xfd\x9c\x3c\xee\xb4\x41\x29\xfe\x6d\x7c\xba\x94\x2f\x4e\xc5\x3f\xcd\x30\x7e\xe8\x3d\xf9\x30\x4c\x4b\x04\xc3\xe5\x30\x7d\x0c\x80\x50\xad\x4b\x96\x86\x14\x18\xa1\x6d\x0e\x45\xe1\x97\xe0\x1d\x08\xed\x5e\xb6\x83\x47\x58\xd1\x64\xb4\xd0\x36\xa0\xaa\x3d\x26\xeb\xb5\x0b\xec\x11\xaa\x64\x69\x07\xc6\x70\xe9\xa9\xde\x97\xf3\xc0\xc3\xde\x4f\xc3\xc8\x79\xaa\x90\x4b\xac\x83\x90\x3f\xad\x5f\x9c\xa6\x82\x87\xa3\x58\x8a\xf5\xb2\xf9\x0d\xeb\x0a\x54\x89\xe2\x74\x35\x2c\x18\x22\x37\x4c\x3c\x1a\x82\x22\x91\x41\xb1\x05\x03\x56\xb5\x47\xff\xf4\x24\x48\xf8\xc0\x68\xe3\x30\x4c\xaa\xe4\x02\x9d\xa1\x63\x85\xdf\x46\x76\x93\xfc\x3f\x0b\x39\x38\xd7\x6d\x69\x15\xa7\x55\xd1\x02\x67\x31\xcc\x17\xd7\xb7\xd9\x22\x38\x54\x51\xfb\x7f\x1e\x9d\xd1\x0a\x82\x14\xd1\x09\xb1\x70\x18\xf7\xc7\x16\x98\x8f\x0e\xa5\xb8\x21\x63\xb4\xdd\xbf\x6b\x4a\xb0\x2d\xd9\x74\x45\x76\xee\xa8\xe0\xe1\x9d\x85\x03\x68\x03\xdb\x98\x47\x0d\x1c\x1a\x54\x4c\xbe\xdd\x53\x45\x4e\xfa\x35\x39\xf8\xfc\xd1\x19\x2b\x67\x06\xe0\xd4\x3b\x8d\xcf\x47\xfa\xcf\x5d\xbe\xbf\x5e\x33\x1e\x15\xdc\xf5\xc4\xc3\xcd\x3d\xc9\xa0\x4f\x39\x29\x7e\xb9\xb8\xc7\x63\x74\x99\xd7\xac\x15\x98\x57\x45\x41\x36\xfc\x66\xcd\x31\x4b\x92\x92\x5c\xd4\x24\x2f\x45\x76\xf9\xa0\x03\x87\x5e\x18\x59\xf5\x76\x74\xfd\xf8\xc5\x14\x98\xd0\x1b\x05\x29\x8c\xb6\xf5\x43\xb7\x49\x91\x65\xd0\x16\xfd\x70\x96\xfc\x49\x5a\xb4\x9f\xae\x60\xff\xb8\x7c\xd2\xfd\xcb\xf5\xf2\x74\xb9\x1a\x6f\xda\xd4\xc6\x6c\xc8\x68\x75\x94\xe2\x6a\x77\x4d\xbc\xf1\x18\xb0\x61\x9f\x3e\xb1\x93\x96\x30\xa4\xb7\xae\x34\x8f\x56\x62\x38\x2a\xf2\x47\x29\xd6\x3f\xae\xde\xea\x44\xe2\xf1\xaf\x1a\xc3\x74\xb7\x72\xb5\x14\xeb\xd5\xaa\x9a\xc5\x18\x41\x80\xdf\x07\x29\x7e\x17\x59\xae\xc8\xee\xb2\xff\x8b\xec\x04\x59\xf5\x97\x3a\xe9\xf9\x29\x13\x7f\x0c\x2a\x07\x32\x75\x85\x6f\x63\x54\x47\x71\xeb\xbd\x15\x69\x31\x6f\x37\x25\xf6\xab\xb8\x7f\x03\x5c\x4a\x91\x5a\x18\xdd\x05\x8a\x18\x67\x29\x62\xb7\x79\xa4\x0c\xf2\x63\x3b\x43\xa4\x36\xe4\x59\x8a\x84\x5d\xfa\x42\x1e\xe3\x3a\x4f\x4c\x8a\x8c\x14\xef\x2e\x36\x5f\x8b\x93\xb3\x72\xb3\x58\x77\xe7\x9f\xc1\x1a\x71\x5e\x8f\x56\x21\x7b\xad\xe6\x4f\x96\xa2\x35\xa4\xac\xf9\x78\x4e\x96\xf1\x81\xd3\xd0\x82\x31\xf4\x71\xe3\xf5\x41\x1b\xdc\xe3\x65\x50\x60\x9a\xfa\x91\x91\xa5\x43\xea\x6e\x05\x0e\xb6\xda\x68\xd6\x38\x49\x0e\x28\x8a\xf1\x42\x2e\xae\x2f\xef\x3e\xbc\xbe\xba\xbe\xf8\x70\x7b\x79\xf3\xfe\xea\xfc\x72\x24\x2e\x3c\xb9\xa9\x02\x18\x33\x13\xb8\x1b\x22\xfe\x59\x1b\xec\x7a\xf1\x38\x8c\x46\x1f\xd0\x62\x08\x1b\x4f\x5b\x4c\xf1\x4a\x66\xf7\x06\x79\x6c\xc2\xb5\x89\x32\x69\x78\xa2\x4b\x07\x29\xce\x56\x67\xab\xd1\x72\x50\x25\x46\x27\xff\x72\x77\xb7\x49\x04\xda\x6a\xd6\x60\x2e\xd0\xc0\xf1\x16\x15\xd9\x22\x48\xf1\x32\x55\x65\x5d\x21\xd5\x3c\x08\x5f\x24\xb2\x50\x2b\x85\x21\xdc\x95\x1e\x43\x49\xa6\x68\xd9\xb5\xff\x76\xa0\x4d\xed\x31\x91\xf6\xba\x85\x0d\x7d\xd9\x5f\xb4\x4f\xa0\x4e\xd0\x56\xc5\x57\x54\x8d\xea\x1f\x19\x63\xf7\xcc\x13\x53\x73\x61\xc6\x2a\x4c\xc3\xd5\x30\x6a\x5f\xca\x23\x59\xef\xe9\x41\xf8\xec\x73\xa7\x7b\x3f\xcd\xb4\xcd\xa4\x03\x3c\xdb\x37\x9f\x3c\x3f\x1f\x5f\x08\x91\x8c\xdb\xa0\x66\xb1\x6c\xb2\x19\x71\x50\x1e\xdc\xb3\xcf\xd0\x2f\x68\xc3\xdd\xf3\x28\xef\x7a\x52\x82\xf4\xa5\x0d\x7b\xdc\x52\xe7\x6c\x76\x36\xae\x36\x91\x7a\x97\x3f\x9c\x2e\x57\xcb\x75\x4c\xb4\x81\xbf\xf2\x09\x3b\xb9\x94\x76\xa6\x24\x95\xcf\x50\xd0\x33\x0a\x2d\x77\xe4\x33\x2c\xe3\xc6\x64\x34\x56\xf9\x2f\x00\x00\xff\xff\x73\x85\x8d\x7b\x11\x0e\x00\x00")
|
||||
|
||||
func corednsYamlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_corednsYaml,
|
||||
"coredns.yaml",
|
||||
)
|
||||
}
|
||||
|
||||
func corednsYaml() (*asset, error) {
|
||||
bytes, err := corednsYamlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "coredns.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Asset loads and returns the asset for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func Asset(name string) ([]byte, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.bytes, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
|
||||
// MustAsset is like Asset but panics when Asset would return an error.
|
||||
// It simplifies safe initialization of global variables.
|
||||
func MustAsset(name string) []byte {
|
||||
a, err := Asset(name)
|
||||
if err != nil {
|
||||
panic("asset: Asset(" + name + "): " + err.Error())
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// AssetInfo loads and returns the asset info for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func AssetInfo(name string) (os.FileInfo, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.info, nil
|
||||
}
|
||||
return nil, fmt.Errorf("AssetInfo %s not found", name)
|
||||
}
|
||||
|
||||
// AssetNames returns the names of the assets.
|
||||
func AssetNames() []string {
|
||||
names := make([]string, 0, len(_bindata))
|
||||
for name := range _bindata {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() (*asset, error){
|
||||
"coredns.yaml": corednsYaml,
|
||||
}
|
||||
|
||||
// AssetDir returns the file names below a certain
|
||||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
// AssetDir("") will return []string{"data"}.
|
||||
func AssetDir(name string) ([]string, error) {
|
||||
node := _bintree
|
||||
if len(name) != 0 {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
pathList := strings.Split(cannonicalName, "/")
|
||||
for _, p := range pathList {
|
||||
node = node.Children[p]
|
||||
if node == nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.Func != nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
rv := make([]string, 0, len(node.Children))
|
||||
for childName := range node.Children {
|
||||
rv = append(rv, childName)
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
type bintree struct {
|
||||
Func func() (*asset, error)
|
||||
Children map[string]*bintree
|
||||
}
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"coredns.yaml": &bintree{corednsYaml, map[string]*bintree{}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory
|
||||
func RestoreAsset(dir, name string) error {
|
||||
data, err := Asset(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := AssetInfo(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RestoreAssets restores an asset under the given directory recursively
|
||||
func RestoreAssets(dir, name string) error {
|
||||
children, err := AssetDir(name)
|
||||
// File
|
||||
if err != nil {
|
||||
return RestoreAsset(dir, name)
|
||||
}
|
||||
// Dir
|
||||
for _, child := range children {
|
||||
err = RestoreAssets(dir, filepath.Join(name, child))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func _filePath(dir, name string) string {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
|
||||
}
|
||||
|
|
@ -9,12 +9,14 @@ import (
|
|||
net2 "net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rancher/k3s/pkg/daemons/config"
|
||||
"github.com/rancher/k3s/pkg/daemons/control"
|
||||
"github.com/rancher/k3s/pkg/deploy"
|
||||
"github.com/rancher/k3s/pkg/tls"
|
||||
v1 "github.com/rancher/k3s/types/apis/k3s.cattle.io/v1"
|
||||
"github.com/rancher/norman"
|
||||
|
@ -89,6 +91,7 @@ func startNorman(ctx context.Context, tlsConfig *dynamiclistener.UserConfig, con
|
|||
CRDs: map[*types.APIVersion][]string{
|
||||
&v1.APIVersion: {
|
||||
v1.ListenerConfigGroupVersionKind.Kind,
|
||||
v1.AddonGroupVersionKind.Kind,
|
||||
},
|
||||
},
|
||||
IgnoredKubeConfigEnv: true,
|
||||
|
@ -96,6 +99,18 @@ func startNorman(ctx context.Context, tlsConfig *dynamiclistener.UserConfig, con
|
|||
tlsServer, err = tls.NewServer(ctx, v1.ClientsFrom(ctx).ListenerConfig, *tlsConfig)
|
||||
return ctx, err
|
||||
},
|
||||
MasterControllers: []norman.ControllerRegister{
|
||||
func(ctx context.Context) error {
|
||||
dataDir := filepath.Join(config.DataDir, "manifests")
|
||||
if err := deploy.Stage(dataDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deploy.WatchFiles(ctx, config.Skips, dataDir); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ctx, _, err = normanConfig.Build(ctx, nil)
|
||||
|
@ -136,7 +151,7 @@ func printTokens(certs, advertiseIP string, tlsConfig *dynamiclistener.UserConfi
|
|||
}
|
||||
|
||||
if len(nodeFile) > 0 {
|
||||
printToken(tlsConfig.HTTPSPort, advertiseIP, "To join node to cluster:", nodeFile, "agent")
|
||||
printToken(tlsConfig.HTTPSPort, advertiseIP, "To join node to cluster:", "agent")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -151,10 +166,23 @@ func writeKubeConfig(certs string, tlsConfig *dynamiclistener.UserConfig, config
|
|||
def = false
|
||||
}
|
||||
|
||||
if config.KubeConfigOutput != "" {
|
||||
kubeConfig = config.KubeConfigOutput
|
||||
}
|
||||
|
||||
if err = clientaccess.AgentAccessInfoToKubeConfig(kubeConfig, url, clientToken); err != nil {
|
||||
logrus.Errorf("Failed to generate kubeconfig: %v", err)
|
||||
}
|
||||
|
||||
if config.KubeConfigMode != "" {
|
||||
mode, err := strconv.ParseInt(config.KubeConfigMode, 8, 0)
|
||||
if err == nil {
|
||||
os.Chmod(kubeConfig, os.FileMode(mode))
|
||||
} else {
|
||||
logrus.Errorf("failed to set %s to mode %s: %v", kubeConfig, mode, err)
|
||||
}
|
||||
}
|
||||
|
||||
logrus.Infof("Wrote kubeconfig %s", kubeConfig)
|
||||
if def {
|
||||
logrus.Infof("Run: %s kubectl", filepath.Base(os.Args[0]))
|
||||
|
@ -193,12 +221,7 @@ func readTokenFile(file string) (string, error) {
|
|||
return strings.TrimSpace(string(content)), nil
|
||||
}
|
||||
|
||||
func printToken(httpsPort int, advertiseIP, prefix, file, cmd string) {
|
||||
token, err := readTokenFile(file)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
|
||||
func printToken(httpsPort int, advertiseIP, prefix, cmd string) {
|
||||
ip := advertiseIP
|
||||
if ip == "" {
|
||||
hostIP, err := net.ChooseHostInterface()
|
||||
|
@ -208,7 +231,7 @@ func printToken(httpsPort int, advertiseIP, prefix, file, cmd string) {
|
|||
ip = hostIP.String()
|
||||
}
|
||||
|
||||
logrus.Infof("%s k3s %s -s https://%s:%d -t %s", prefix, cmd, ip, httpsPort, token)
|
||||
logrus.Infof("%s k3s %s -s https://%s:%d -t ${NODE_TOKEN}", prefix, cmd, ip, httpsPort)
|
||||
}
|
||||
|
||||
func FormatToken(token string, certs string) string {
|
||||
|
|
|
@ -15,4 +15,4 @@ else
|
|||
fi
|
||||
|
||||
echo Starting agent
|
||||
sudo env "PATH=$(pwd)/bin:$PATH" ./bin/k3s-agent agent -s https://localhost:6443 -t $(<${HOME}/.rancher/k3s/server/node-token) "$@"
|
||||
sudo env "PATH=$(pwd)/bin:$PATH" ./bin/k3s-agent --debug agent -s https://localhost:6443 -t $(<${HOME}/.rancher/k3s/server/node-token) "$@"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
mkdir -p $(dirname $0)/../bin
|
||||
cd $(dirname $0)/../bin
|
||||
|
||||
echo Running
|
||||
|
|
|
@ -9,7 +9,7 @@ cd $(dirname $0)/..
|
|||
|
||||
curl --compressed -sfL https://github.com/ibuildthecloud/k3s-root/releases/download/${ROOT_VERSION}/k3s-root-${ARCH}.tar | tar xf -
|
||||
|
||||
rm -rf bin/kubectl bin/k3s-agent bin/k3s build/data
|
||||
rm -rf bin/kubectl bin/k3s-agent bin/k3s-server bin/kubectl bin/k3s build/data
|
||||
ln -s containerd bin/k3s-agent
|
||||
ln -s containerd bin/k3s-server
|
||||
ln -s containerd bin/kubectl
|
||||
|
|
|
@ -24,4 +24,5 @@ test -z "$failed"
|
|||
echo Running: go fmt
|
||||
test -z "$(go fmt ${PACKAGES} | \
|
||||
grep -v 'pkg/data/zz_generated_bindata.go' | \
|
||||
grep -v 'pkg/deploy/zz_generated_bindata.go' | \
|
||||
tee /dev/stderr)"
|
||||
|
|
|
@ -13,5 +13,6 @@ var (
|
|||
}
|
||||
|
||||
Schemas = factory.Schemas(&APIVersion).
|
||||
MustImport(&APIVersion, ListenerConfig{})
|
||||
MustImport(&APIVersion, ListenerConfig{}).
|
||||
MustImport(&APIVersion, Addon{})
|
||||
)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"github.com/rancher/norman/pkg/dynamiclistener"
|
||||
"github.com/rancher/norman/types"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
type ListenerConfig struct {
|
||||
|
@ -14,3 +15,22 @@ type ListenerConfig struct {
|
|||
|
||||
Status dynamiclistener.ListenerStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
type Addon struct {
|
||||
types.Namespaced
|
||||
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec AddonSpec `json:"spec,omitempty"`
|
||||
Status AddonStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
type AddonSpec struct {
|
||||
Source string `json:"source,omitempty"`
|
||||
Checksum string `json:"checksum,omitempty"`
|
||||
}
|
||||
|
||||
type AddonStatus struct {
|
||||
GVKs []schema.GroupVersionKind `json:"gvks,omitempty"`
|
||||
}
|
||||
|
|
|
@ -0,0 +1,440 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/rancher/norman/controller"
|
||||
"github.com/rancher/norman/objectclient"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
AddonGroupVersionKind = schema.GroupVersionKind{
|
||||
Version: Version,
|
||||
Group: GroupName,
|
||||
Kind: "Addon",
|
||||
}
|
||||
AddonResource = metav1.APIResource{
|
||||
Name: "addons",
|
||||
SingularName: "addon",
|
||||
Namespaced: true,
|
||||
|
||||
Kind: AddonGroupVersionKind.Kind,
|
||||
}
|
||||
)
|
||||
|
||||
func NewAddon(namespace, name string, obj Addon) *Addon {
|
||||
obj.APIVersion, obj.Kind = AddonGroupVersionKind.ToAPIVersionAndKind()
|
||||
obj.Name = name
|
||||
obj.Namespace = namespace
|
||||
return &obj
|
||||
}
|
||||
|
||||
type AddonList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Addon
|
||||
}
|
||||
|
||||
type AddonHandlerFunc func(key string, obj *Addon) (runtime.Object, error)
|
||||
|
||||
type AddonChangeHandlerFunc func(obj *Addon) (runtime.Object, error)
|
||||
|
||||
type AddonLister interface {
|
||||
List(namespace string, selector labels.Selector) (ret []*Addon, err error)
|
||||
Get(namespace, name string) (*Addon, error)
|
||||
}
|
||||
|
||||
type AddonController interface {
|
||||
Generic() controller.GenericController
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() AddonLister
|
||||
AddHandler(ctx context.Context, name string, handler AddonHandlerFunc)
|
||||
AddClusterScopedHandler(ctx context.Context, name, clusterName string, handler AddonHandlerFunc)
|
||||
Enqueue(namespace, name string)
|
||||
Sync(ctx context.Context) error
|
||||
Start(ctx context.Context, threadiness int) error
|
||||
}
|
||||
|
||||
type AddonInterface interface {
|
||||
ObjectClient() *objectclient.ObjectClient
|
||||
Create(*Addon) (*Addon, error)
|
||||
GetNamespaced(namespace, name string, opts metav1.GetOptions) (*Addon, error)
|
||||
Get(name string, opts metav1.GetOptions) (*Addon, error)
|
||||
Update(*Addon) (*Addon, error)
|
||||
Delete(name string, options *metav1.DeleteOptions) error
|
||||
DeleteNamespaced(namespace, name string, options *metav1.DeleteOptions) error
|
||||
List(opts metav1.ListOptions) (*AddonList, error)
|
||||
Watch(opts metav1.ListOptions) (watch.Interface, error)
|
||||
DeleteCollection(deleteOpts *metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||
Controller() AddonController
|
||||
AddHandler(ctx context.Context, name string, sync AddonHandlerFunc)
|
||||
AddLifecycle(ctx context.Context, name string, lifecycle AddonLifecycle)
|
||||
AddClusterScopedHandler(ctx context.Context, name, clusterName string, sync AddonHandlerFunc)
|
||||
AddClusterScopedLifecycle(ctx context.Context, name, clusterName string, lifecycle AddonLifecycle)
|
||||
}
|
||||
|
||||
type addonLister struct {
|
||||
controller *addonController
|
||||
}
|
||||
|
||||
func (l *addonLister) List(namespace string, selector labels.Selector) (ret []*Addon, err error) {
|
||||
err = cache.ListAllByNamespace(l.controller.Informer().GetIndexer(), namespace, selector, func(obj interface{}) {
|
||||
ret = append(ret, obj.(*Addon))
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (l *addonLister) Get(namespace, name string) (*Addon, error) {
|
||||
var key string
|
||||
if namespace != "" {
|
||||
key = namespace + "/" + name
|
||||
} else {
|
||||
key = name
|
||||
}
|
||||
obj, exists, err := l.controller.Informer().GetIndexer().GetByKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(schema.GroupResource{
|
||||
Group: AddonGroupVersionKind.Group,
|
||||
Resource: "addon",
|
||||
}, key)
|
||||
}
|
||||
return obj.(*Addon), nil
|
||||
}
|
||||
|
||||
type addonController struct {
|
||||
controller.GenericController
|
||||
}
|
||||
|
||||
func (c *addonController) Generic() controller.GenericController {
|
||||
return c.GenericController
|
||||
}
|
||||
|
||||
func (c *addonController) Lister() AddonLister {
|
||||
return &addonLister{
|
||||
controller: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *addonController) AddHandler(ctx context.Context, name string, handler AddonHandlerFunc) {
|
||||
c.GenericController.AddHandler(ctx, name, func(key string, obj interface{}) (interface{}, error) {
|
||||
if obj == nil {
|
||||
return handler(key, nil)
|
||||
} else if v, ok := obj.(*Addon); ok {
|
||||
return handler(key, v)
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (c *addonController) AddClusterScopedHandler(ctx context.Context, name, cluster string, handler AddonHandlerFunc) {
|
||||
c.GenericController.AddHandler(ctx, name, func(key string, obj interface{}) (interface{}, error) {
|
||||
if obj == nil {
|
||||
return handler(key, nil)
|
||||
} else if v, ok := obj.(*Addon); ok && controller.ObjectInCluster(cluster, obj) {
|
||||
return handler(key, v)
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type addonFactory struct {
|
||||
}
|
||||
|
||||
func (c addonFactory) Object() runtime.Object {
|
||||
return &Addon{}
|
||||
}
|
||||
|
||||
func (c addonFactory) List() runtime.Object {
|
||||
return &AddonList{}
|
||||
}
|
||||
|
||||
func (s *addonClient) Controller() AddonController {
|
||||
s.client.Lock()
|
||||
defer s.client.Unlock()
|
||||
|
||||
c, ok := s.client.addonControllers[s.ns]
|
||||
if ok {
|
||||
return c
|
||||
}
|
||||
|
||||
genericController := controller.NewGenericController(AddonGroupVersionKind.Kind+"Controller",
|
||||
s.objectClient)
|
||||
|
||||
c = &addonController{
|
||||
GenericController: genericController,
|
||||
}
|
||||
|
||||
s.client.addonControllers[s.ns] = c
|
||||
s.client.starters = append(s.client.starters, c)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
type addonClient struct {
|
||||
client *Client
|
||||
ns string
|
||||
objectClient *objectclient.ObjectClient
|
||||
controller AddonController
|
||||
}
|
||||
|
||||
func (s *addonClient) ObjectClient() *objectclient.ObjectClient {
|
||||
return s.objectClient
|
||||
}
|
||||
|
||||
func (s *addonClient) Create(o *Addon) (*Addon, error) {
|
||||
obj, err := s.objectClient.Create(o)
|
||||
return obj.(*Addon), err
|
||||
}
|
||||
|
||||
func (s *addonClient) Get(name string, opts metav1.GetOptions) (*Addon, error) {
|
||||
obj, err := s.objectClient.Get(name, opts)
|
||||
return obj.(*Addon), err
|
||||
}
|
||||
|
||||
func (s *addonClient) GetNamespaced(namespace, name string, opts metav1.GetOptions) (*Addon, error) {
|
||||
obj, err := s.objectClient.GetNamespaced(namespace, name, opts)
|
||||
return obj.(*Addon), err
|
||||
}
|
||||
|
||||
func (s *addonClient) Update(o *Addon) (*Addon, error) {
|
||||
obj, err := s.objectClient.Update(o.Name, o)
|
||||
return obj.(*Addon), err
|
||||
}
|
||||
|
||||
func (s *addonClient) Delete(name string, options *metav1.DeleteOptions) error {
|
||||
return s.objectClient.Delete(name, options)
|
||||
}
|
||||
|
||||
func (s *addonClient) DeleteNamespaced(namespace, name string, options *metav1.DeleteOptions) error {
|
||||
return s.objectClient.DeleteNamespaced(namespace, name, options)
|
||||
}
|
||||
|
||||
func (s *addonClient) List(opts metav1.ListOptions) (*AddonList, error) {
|
||||
obj, err := s.objectClient.List(opts)
|
||||
return obj.(*AddonList), err
|
||||
}
|
||||
|
||||
func (s *addonClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
return s.objectClient.Watch(opts)
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched deployment.
|
||||
func (s *addonClient) Patch(o *Addon, patchType types.PatchType, data []byte, subresources ...string) (*Addon, error) {
|
||||
obj, err := s.objectClient.Patch(o.Name, o, patchType, data, subresources...)
|
||||
return obj.(*Addon), err
|
||||
}
|
||||
|
||||
func (s *addonClient) DeleteCollection(deleteOpts *metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
||||
return s.objectClient.DeleteCollection(deleteOpts, listOpts)
|
||||
}
|
||||
|
||||
func (s *addonClient) AddHandler(ctx context.Context, name string, sync AddonHandlerFunc) {
|
||||
s.Controller().AddHandler(ctx, name, sync)
|
||||
}
|
||||
|
||||
func (s *addonClient) AddLifecycle(ctx context.Context, name string, lifecycle AddonLifecycle) {
|
||||
sync := NewAddonLifecycleAdapter(name, false, s, lifecycle)
|
||||
s.Controller().AddHandler(ctx, name, sync)
|
||||
}
|
||||
|
||||
func (s *addonClient) AddClusterScopedHandler(ctx context.Context, name, clusterName string, sync AddonHandlerFunc) {
|
||||
s.Controller().AddClusterScopedHandler(ctx, name, clusterName, sync)
|
||||
}
|
||||
|
||||
func (s *addonClient) AddClusterScopedLifecycle(ctx context.Context, name, clusterName string, lifecycle AddonLifecycle) {
|
||||
sync := NewAddonLifecycleAdapter(name+"_"+clusterName, true, s, lifecycle)
|
||||
s.Controller().AddClusterScopedHandler(ctx, name, clusterName, sync)
|
||||
}
|
||||
|
||||
type AddonIndexer func(obj *Addon) ([]string, error)
|
||||
|
||||
type AddonClientCache interface {
|
||||
Get(namespace, name string) (*Addon, error)
|
||||
List(namespace string, selector labels.Selector) ([]*Addon, error)
|
||||
|
||||
Index(name string, indexer AddonIndexer)
|
||||
GetIndexed(name, key string) ([]*Addon, error)
|
||||
}
|
||||
|
||||
type AddonClient interface {
|
||||
Create(*Addon) (*Addon, error)
|
||||
Get(namespace, name string, opts metav1.GetOptions) (*Addon, error)
|
||||
Update(*Addon) (*Addon, error)
|
||||
Delete(namespace, name string, options *metav1.DeleteOptions) error
|
||||
List(namespace string, opts metav1.ListOptions) (*AddonList, error)
|
||||
Watch(opts metav1.ListOptions) (watch.Interface, error)
|
||||
|
||||
Cache() AddonClientCache
|
||||
|
||||
OnCreate(ctx context.Context, name string, sync AddonChangeHandlerFunc)
|
||||
OnChange(ctx context.Context, name string, sync AddonChangeHandlerFunc)
|
||||
OnRemove(ctx context.Context, name string, sync AddonChangeHandlerFunc)
|
||||
Enqueue(namespace, name string)
|
||||
|
||||
Generic() controller.GenericController
|
||||
ObjectClient() *objectclient.ObjectClient
|
||||
Interface() AddonInterface
|
||||
}
|
||||
|
||||
type addonClientCache struct {
|
||||
client *addonClient2
|
||||
}
|
||||
|
||||
type addonClient2 struct {
|
||||
iface AddonInterface
|
||||
controller AddonController
|
||||
}
|
||||
|
||||
func (n *addonClient2) Interface() AddonInterface {
|
||||
return n.iface
|
||||
}
|
||||
|
||||
func (n *addonClient2) Generic() controller.GenericController {
|
||||
return n.iface.Controller().Generic()
|
||||
}
|
||||
|
||||
func (n *addonClient2) ObjectClient() *objectclient.ObjectClient {
|
||||
return n.Interface().ObjectClient()
|
||||
}
|
||||
|
||||
func (n *addonClient2) Enqueue(namespace, name string) {
|
||||
n.iface.Controller().Enqueue(namespace, name)
|
||||
}
|
||||
|
||||
func (n *addonClient2) Create(obj *Addon) (*Addon, error) {
|
||||
return n.iface.Create(obj)
|
||||
}
|
||||
|
||||
func (n *addonClient2) Get(namespace, name string, opts metav1.GetOptions) (*Addon, error) {
|
||||
return n.iface.GetNamespaced(namespace, name, opts)
|
||||
}
|
||||
|
||||
func (n *addonClient2) Update(obj *Addon) (*Addon, error) {
|
||||
return n.iface.Update(obj)
|
||||
}
|
||||
|
||||
func (n *addonClient2) Delete(namespace, name string, options *metav1.DeleteOptions) error {
|
||||
return n.iface.DeleteNamespaced(namespace, name, options)
|
||||
}
|
||||
|
||||
func (n *addonClient2) List(namespace string, opts metav1.ListOptions) (*AddonList, error) {
|
||||
return n.iface.List(opts)
|
||||
}
|
||||
|
||||
func (n *addonClient2) Watch(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
return n.iface.Watch(opts)
|
||||
}
|
||||
|
||||
func (n *addonClientCache) Get(namespace, name string) (*Addon, error) {
|
||||
return n.client.controller.Lister().Get(namespace, name)
|
||||
}
|
||||
|
||||
func (n *addonClientCache) List(namespace string, selector labels.Selector) ([]*Addon, error) {
|
||||
return n.client.controller.Lister().List(namespace, selector)
|
||||
}
|
||||
|
||||
func (n *addonClient2) Cache() AddonClientCache {
|
||||
n.loadController()
|
||||
return &addonClientCache{
|
||||
client: n,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *addonClient2) OnCreate(ctx context.Context, name string, sync AddonChangeHandlerFunc) {
|
||||
n.loadController()
|
||||
n.iface.AddLifecycle(ctx, name+"-create", &addonLifecycleDelegate{create: sync})
|
||||
}
|
||||
|
||||
func (n *addonClient2) OnChange(ctx context.Context, name string, sync AddonChangeHandlerFunc) {
|
||||
n.loadController()
|
||||
n.iface.AddLifecycle(ctx, name+"-change", &addonLifecycleDelegate{update: sync})
|
||||
}
|
||||
|
||||
func (n *addonClient2) OnRemove(ctx context.Context, name string, sync AddonChangeHandlerFunc) {
|
||||
n.loadController()
|
||||
n.iface.AddLifecycle(ctx, name, &addonLifecycleDelegate{remove: sync})
|
||||
}
|
||||
|
||||
func (n *addonClientCache) Index(name string, indexer AddonIndexer) {
|
||||
err := n.client.controller.Informer().GetIndexer().AddIndexers(map[string]cache.IndexFunc{
|
||||
name: func(obj interface{}) ([]string, error) {
|
||||
if v, ok := obj.(*Addon); ok {
|
||||
return indexer(v)
|
||||
}
|
||||
return nil, nil
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *addonClientCache) GetIndexed(name, key string) ([]*Addon, error) {
|
||||
var result []*Addon
|
||||
objs, err := n.client.controller.Informer().GetIndexer().ByIndex(name, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, obj := range objs {
|
||||
if v, ok := obj.(*Addon); ok {
|
||||
result = append(result, v)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (n *addonClient2) loadController() {
|
||||
if n.controller == nil {
|
||||
n.controller = n.iface.Controller()
|
||||
}
|
||||
}
|
||||
|
||||
type addonLifecycleDelegate struct {
|
||||
create AddonChangeHandlerFunc
|
||||
update AddonChangeHandlerFunc
|
||||
remove AddonChangeHandlerFunc
|
||||
}
|
||||
|
||||
func (n *addonLifecycleDelegate) HasCreate() bool {
|
||||
return n.create != nil
|
||||
}
|
||||
|
||||
func (n *addonLifecycleDelegate) Create(obj *Addon) (runtime.Object, error) {
|
||||
if n.create == nil {
|
||||
return obj, nil
|
||||
}
|
||||
return n.create(obj)
|
||||
}
|
||||
|
||||
func (n *addonLifecycleDelegate) HasFinalize() bool {
|
||||
return n.remove != nil
|
||||
}
|
||||
|
||||
func (n *addonLifecycleDelegate) Remove(obj *Addon) (runtime.Object, error) {
|
||||
if n.remove == nil {
|
||||
return obj, nil
|
||||
}
|
||||
return n.remove(obj)
|
||||
}
|
||||
|
||||
func (n *addonLifecycleDelegate) Updated(obj *Addon) (runtime.Object, error) {
|
||||
if n.update == nil {
|
||||
return obj, nil
|
||||
}
|
||||
return n.update(obj)
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/lifecycle"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
type AddonLifecycle interface {
|
||||
Create(obj *Addon) (runtime.Object, error)
|
||||
Remove(obj *Addon) (runtime.Object, error)
|
||||
Updated(obj *Addon) (runtime.Object, error)
|
||||
}
|
||||
|
||||
type addonLifecycleAdapter struct {
|
||||
lifecycle AddonLifecycle
|
||||
}
|
||||
|
||||
func (w *addonLifecycleAdapter) HasCreate() bool {
|
||||
o, ok := w.lifecycle.(lifecycle.ObjectLifecycleCondition)
|
||||
return !ok || o.HasCreate()
|
||||
}
|
||||
|
||||
func (w *addonLifecycleAdapter) HasFinalize() bool {
|
||||
o, ok := w.lifecycle.(lifecycle.ObjectLifecycleCondition)
|
||||
return !ok || o.HasFinalize()
|
||||
}
|
||||
|
||||
func (w *addonLifecycleAdapter) Create(obj runtime.Object) (runtime.Object, error) {
|
||||
o, err := w.lifecycle.Create(obj.(*Addon))
|
||||
if o == nil {
|
||||
return nil, err
|
||||
}
|
||||
return o, err
|
||||
}
|
||||
|
||||
func (w *addonLifecycleAdapter) Finalize(obj runtime.Object) (runtime.Object, error) {
|
||||
o, err := w.lifecycle.Remove(obj.(*Addon))
|
||||
if o == nil {
|
||||
return nil, err
|
||||
}
|
||||
return o, err
|
||||
}
|
||||
|
||||
func (w *addonLifecycleAdapter) Updated(obj runtime.Object) (runtime.Object, error) {
|
||||
o, err := w.lifecycle.Updated(obj.(*Addon))
|
||||
if o == nil {
|
||||
return nil, err
|
||||
}
|
||||
return o, err
|
||||
}
|
||||
|
||||
func NewAddonLifecycleAdapter(name string, clusterScoped bool, client AddonInterface, l AddonLifecycle) AddonHandlerFunc {
|
||||
adapter := &addonLifecycleAdapter{lifecycle: l}
|
||||
syncFn := lifecycle.NewObjectLifecycleAdapter(name, clusterScoped, adapter, client.ObjectClient())
|
||||
return func(key string, obj *Addon) (runtime.Object, error) {
|
||||
newObj, err := syncFn(key, obj)
|
||||
if o, ok := newObj.(runtime.Object); ok {
|
||||
return o, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
}
|
|
@ -2,8 +2,108 @@ package v1
|
|||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Addon) DeepCopyInto(out *Addon) {
|
||||
*out = *in
|
||||
out.Namespaced = in.Namespaced
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
out.Spec = in.Spec
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Addon.
|
||||
func (in *Addon) DeepCopy() *Addon {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Addon)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Addon) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AddonList) DeepCopyInto(out *AddonList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Addon, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddonList.
|
||||
func (in *AddonList) DeepCopy() *AddonList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AddonList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *AddonList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AddonSpec) DeepCopyInto(out *AddonSpec) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddonSpec.
|
||||
func (in *AddonSpec) DeepCopy() *AddonSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AddonSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AddonStatus) DeepCopyInto(out *AddonStatus) {
|
||||
*out = *in
|
||||
if in.GVKs != nil {
|
||||
in, out := &in.GVKs, &out.GVKs
|
||||
*out = make([]schema.GroupVersionKind, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddonStatus.
|
||||
func (in *AddonStatus) DeepCopy() *AddonStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AddonStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ListenerConfig) DeepCopyInto(out *ListenerConfig) {
|
||||
*out = *in
|
||||
|
|
|
@ -21,12 +21,14 @@ type Interface interface {
|
|||
controller.Starter
|
||||
|
||||
ListenerConfigsGetter
|
||||
AddonsGetter
|
||||
}
|
||||
|
||||
type Clients struct {
|
||||
Interface Interface
|
||||
|
||||
ListenerConfig ListenerConfigClient
|
||||
Addon AddonClient
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
|
@ -35,6 +37,7 @@ type Client struct {
|
|||
starters []controller.Starter
|
||||
|
||||
listenerConfigControllers map[string]ListenerConfigController
|
||||
addonControllers map[string]AddonController
|
||||
}
|
||||
|
||||
func Factory(ctx context.Context, config rest.Config) (context.Context, controller.Starter, error) {
|
||||
|
@ -73,6 +76,9 @@ func NewClientsFromInterface(iface Interface) *Clients {
|
|||
ListenerConfig: &listenerConfigClient2{
|
||||
iface: iface.ListenerConfigs(""),
|
||||
},
|
||||
Addon: &addonClient2{
|
||||
iface: iface.Addons(""),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,6 +96,7 @@ func NewForConfig(config rest.Config) (Interface, error) {
|
|||
restClient: restClient,
|
||||
|
||||
listenerConfigControllers: map[string]ListenerConfigController{},
|
||||
addonControllers: map[string]AddonController{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -117,3 +124,16 @@ func (c *Client) ListenerConfigs(namespace string) ListenerConfigInterface {
|
|||
objectClient: objectClient,
|
||||
}
|
||||
}
|
||||
|
||||
type AddonsGetter interface {
|
||||
Addons(namespace string) AddonInterface
|
||||
}
|
||||
|
||||
func (c *Client) Addons(namespace string) AddonInterface {
|
||||
objectClient := objectclient.NewObjectClient(namespace, c.restClient, &AddonResource, AddonGroupVersionKind, addonFactory{})
|
||||
return &addonClient{
|
||||
ns: namespace,
|
||||
client: c,
|
||||
objectClient: objectClient,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
|||
|
||||
&ListenerConfig{},
|
||||
&ListenerConfigList{},
|
||||
&Addon{},
|
||||
&AddonList{},
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -28,6 +28,22 @@ func main() {
|
|||
if err := bindata.Translate(bc); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
bc = &bindata.Config{
|
||||
Input: []bindata.InputConfig{
|
||||
{
|
||||
Path: "manifests",
|
||||
},
|
||||
},
|
||||
Package: "deploy",
|
||||
NoMetadata: true,
|
||||
Prefix: "manifests/",
|
||||
Output: "pkg/deploy/zz_generated_bindata.go",
|
||||
}
|
||||
if err := bindata.Translate(bc); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
if err := generator.DefaultGenerate(v1.Schemas, basePackage, false, nil); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue