Prepare for initial release

pull/13/head v0.1.0-rc1
Darren Shepherd 2019-01-22 14:14:58 -07:00
parent 2e250c308b
commit 287e0f44c9
31 changed files with 1619 additions and 51 deletions

View File

@ -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

1
.gitignore vendored
View File

@ -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/

View File

@ -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/

View File

@ -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 {

28
docker-compose.yml Normal file
View File

@ -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: {}

175
manifests/coredns.yaml Normal file
View File

@ -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

View File

@ -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 {

View File

@ -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 {

View File

@ -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")
}

View File

@ -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,
},

View File

@ -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,
},

View File

@ -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

View File

@ -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
}

View File

@ -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:"-"`
}

View File

@ -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

281
pkg/deploy/controller.go Normal file
View File

@ -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, &copy)
}
return result, nil
}
return []runtime.Object{obj}, nil
}

29
pkg/deploy/stage.go Normal file
View File

@ -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
}

View File

@ -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, "/")...)...)
}

View File

@ -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 {

View File

@ -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) "$@"

View File

@ -1,6 +1,7 @@
#!/bin/bash
set -e
mkdir -p $(dirname $0)/../bin
cd $(dirname $0)/../bin
echo Running

View File

@ -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

View File

@ -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)"

View File

@ -13,5 +13,6 @@ var (
}
Schemas = factory.Schemas(&APIVersion).
MustImport(&APIVersion, ListenerConfig{})
MustImport(&APIVersion, ListenerConfig{}).
MustImport(&APIVersion, Addon{})
)

View File

@ -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"`
}

View File

@ -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)
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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,
}
}

View File

@ -35,6 +35,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&ListenerConfig{},
&ListenerConfigList{},
&Addon{},
&AddonList{},
)
return nil
}

View File

@ -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)
}