mirror of https://github.com/k3s-io/k3s
Darren Shepherd
6 years ago
commit
9bb7c27c62
67 changed files with 4763 additions and 0 deletions
@ -0,0 +1,10 @@
|
||||
./bin |
||||
./.vagrant |
||||
./.dapper |
||||
./data-dir |
||||
./dist |
||||
./.trash-cache |
||||
./image/root |
||||
./image/agent |
||||
./image/go_build_agent |
||||
./image/main.squashfs |
@ -0,0 +1,55 @@
|
||||
--- |
||||
pipeline: |
||||
build: |
||||
privileged: true |
||||
image: rancher/dapper:1.11.2 |
||||
volumes: |
||||
- /var/run/docker.sock:/var/run/docker.sock |
||||
commands: |
||||
- dapper ci |
||||
|
||||
stage-binaries: |
||||
image: rancher/dapper:1.11.2 |
||||
commands: |
||||
- cp -f ./bin/rio-incluster ./package/rio |
||||
when: |
||||
branch: master |
||||
event: tag |
||||
|
||||
publish-image: |
||||
image: plugins/docker |
||||
dockerfile: package/Dockerfile |
||||
repo: rancher/rio |
||||
context: package/ |
||||
tag: ${DRONE_TAG} |
||||
secrets: [docker_username, docker_password] |
||||
when: |
||||
branch: master |
||||
event: tag |
||||
|
||||
github_binary_prerelease: |
||||
image: plugins/github-release |
||||
prerelease: true |
||||
files: |
||||
- dist/artifacts/* |
||||
checksum: |
||||
- sha256 |
||||
secrets: [github_token] |
||||
when: |
||||
branch: master |
||||
event: tag |
||||
ref: |
||||
include: [ refs/tags/*rc* ] |
||||
|
||||
github_binary_release: |
||||
image: plugins/github-release |
||||
files: |
||||
- dist/artifacts/* |
||||
checksum: |
||||
- sha256 |
||||
secrets: [github_token] |
||||
when: |
||||
branch: master |
||||
event: tag |
||||
ref: |
||||
exclude: [ refs/tags/*rc* ] |
@ -0,0 +1,20 @@
|
||||
*.swp |
||||
/.dapper |
||||
/.idea |
||||
/.trash-cache |
||||
/.vagrant |
||||
/*.log |
||||
/bin |
||||
/build |
||||
/data-dir |
||||
/dist |
||||
/image/root |
||||
/image/agent |
||||
/image/go_build_agent |
||||
/image/main.squashfs |
||||
/package/rio |
||||
__pycache__ |
||||
/tests/.pytest_cache/ |
||||
/tests/.tox/ |
||||
/tests/.vscode |
||||
|
@ -0,0 +1,11 @@
|
||||
{ |
||||
"EnableAll": false, |
||||
"Enable": [ |
||||
"golint", |
||||
"goimports", |
||||
"misspell", |
||||
"ineffassign", |
||||
"errcheck" |
||||
], |
||||
"Deadline": "1m" |
||||
} |
@ -0,0 +1,29 @@
|
||||
FROM golang:1.11-alpine3.8 |
||||
|
||||
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 |
||||
RUN pip3 install 'tox==3.6.0' |
||||
RUN npm install -g 'bats@1.1.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 |
||||
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 |
||||
|
||||
ENV DAPPER_RUN_ARGS --privileged |
||||
ENV DAPPER_ENV REPO TAG DRONE_TAG |
||||
ENV DAPPER_SOURCE /go/src/github.com/rancher/rio/ |
||||
ENV DAPPER_OUTPUT ./bin ./dist |
||||
ENV DAPPER_DOCKER_SOCKET true |
||||
ENV HOME ${DAPPER_SOURCE} |
||||
ENV CROSS true |
||||
WORKDIR ${DAPPER_SOURCE} |
||||
|
||||
ENTRYPOINT ["./scripts/entry"] |
||||
CMD ["ci"] |
||||
|
@ -0,0 +1,177 @@
|
||||
|
||||
Apache License |
||||
Version 2.0, January 2004 |
||||
http://www.apache.org/licenses/ |
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
||||
|
||||
1. Definitions. |
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, |
||||
and distribution as defined by Sections 1 through 9 of this document. |
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by |
||||
the copyright owner that is granting the License. |
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all |
||||
other entities that control, are controlled by, or are under common |
||||
control with that entity. For the purposes of this definition, |
||||
"control" means (i) the power, direct or indirect, to cause the |
||||
direction or management of such entity, whether by contract or |
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
||||
outstanding shares, or (iii) beneficial ownership of such entity. |
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity |
||||
exercising permissions granted by this License. |
||||
|
||||
"Source" form shall mean the preferred form for making modifications, |
||||
including but not limited to software source code, documentation |
||||
source, and configuration files. |
||||
|
||||
"Object" form shall mean any form resulting from mechanical |
||||
transformation or translation of a Source form, including but |
||||
not limited to compiled object code, generated documentation, |
||||
and conversions to other media types. |
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or |
||||
Object form, made available under the License, as indicated by a |
||||
copyright notice that is included in or attached to the work |
||||
(an example is provided in the Appendix below). |
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object |
||||
form, that is based on (or derived from) the Work and for which the |
||||
editorial revisions, annotations, elaborations, or other modifications |
||||
represent, as a whole, an original work of authorship. For the purposes |
||||
of this License, Derivative Works shall not include works that remain |
||||
separable from, or merely link (or bind by name) to the interfaces of, |
||||
the Work and Derivative Works thereof. |
||||
|
||||
"Contribution" shall mean any work of authorship, including |
||||
the original version of the Work and any modifications or additions |
||||
to that Work or Derivative Works thereof, that is intentionally |
||||
submitted to Licensor for inclusion in the Work by the copyright owner |
||||
or by an individual or Legal Entity authorized to submit on behalf of |
||||
the copyright owner. For the purposes of this definition, "submitted" |
||||
means any form of electronic, verbal, or written communication sent |
||||
to the Licensor or its representatives, including but not limited to |
||||
communication on electronic mailing lists, source code control systems, |
||||
and issue tracking systems that are managed by, or on behalf of, the |
||||
Licensor for the purpose of discussing and improving the Work, but |
||||
excluding communication that is conspicuously marked or otherwise |
||||
designated in writing by the copyright owner as "Not a Contribution." |
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity |
||||
on behalf of whom a Contribution has been received by Licensor and |
||||
subsequently incorporated within the Work. |
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of |
||||
this License, each Contributor hereby grants to You a perpetual, |
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
copyright license to reproduce, prepare Derivative Works of, |
||||
publicly display, publicly perform, sublicense, and distribute the |
||||
Work and such Derivative Works in Source or Object form. |
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of |
||||
this License, each Contributor hereby grants to You a perpetual, |
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
(except as stated in this section) patent license to make, have made, |
||||
use, offer to sell, sell, import, and otherwise transfer the Work, |
||||
where such license applies only to those patent claims licensable |
||||
by such Contributor that are necessarily infringed by their |
||||
Contribution(s) alone or by combination of their Contribution(s) |
||||
with the Work to which such Contribution(s) was submitted. If You |
||||
institute patent litigation against any entity (including a |
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work |
||||
or a Contribution incorporated within the Work constitutes direct |
||||
or contributory patent infringement, then any patent licenses |
||||
granted to You under this License for that Work shall terminate |
||||
as of the date such litigation is filed. |
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the |
||||
Work or Derivative Works thereof in any medium, with or without |
||||
modifications, and in Source or Object form, provided that You |
||||
meet the following conditions: |
||||
|
||||
(a) You must give any other recipients of the Work or |
||||
Derivative Works a copy of this License; and |
||||
|
||||
(b) You must cause any modified files to carry prominent notices |
||||
stating that You changed the files; and |
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works |
||||
that You distribute, all copyright, patent, trademark, and |
||||
attribution notices from the Source form of the Work, |
||||
excluding those notices that do not pertain to any part of |
||||
the Derivative Works; and |
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its |
||||
distribution, then any Derivative Works that You distribute must |
||||
include a readable copy of the attribution notices contained |
||||
within such NOTICE file, excluding those notices that do not |
||||
pertain to any part of the Derivative Works, in at least one |
||||
of the following places: within a NOTICE text file distributed |
||||
as part of the Derivative Works; within the Source form or |
||||
documentation, if provided along with the Derivative Works; or, |
||||
within a display generated by the Derivative Works, if and |
||||
wherever such third-party notices normally appear. The contents |
||||
of the NOTICE file are for informational purposes only and |
||||
do not modify the License. You may add Your own attribution |
||||
notices within Derivative Works that You distribute, alongside |
||||
or as an addendum to the NOTICE text from the Work, provided |
||||
that such additional attribution notices cannot be construed |
||||
as modifying the License. |
||||
|
||||
You may add Your own copyright statement to Your modifications and |
||||
may provide additional or different license terms and conditions |
||||
for use, reproduction, or distribution of Your modifications, or |
||||
for any such Derivative Works as a whole, provided Your use, |
||||
reproduction, and distribution of the Work otherwise complies with |
||||
the conditions stated in this License. |
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, |
||||
any Contribution intentionally submitted for inclusion in the Work |
||||
by You to the Licensor shall be under the terms and conditions of |
||||
this License, without any additional terms or conditions. |
||||
Notwithstanding the above, nothing herein shall supersede or modify |
||||
the terms of any separate license agreement you may have executed |
||||
with Licensor regarding such Contributions. |
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade |
||||
names, trademarks, service marks, or product names of the Licensor, |
||||
except as required for reasonable and customary use in describing the |
||||
origin of the Work and reproducing the content of the NOTICE file. |
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or |
||||
agreed to in writing, Licensor provides the Work (and each |
||||
Contributor provides its Contributions) on an "AS IS" BASIS, |
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
||||
implied, including, without limitation, any warranties or conditions |
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
||||
PARTICULAR PURPOSE. You are solely responsible for determining the |
||||
appropriateness of using or redistributing the Work and assume any |
||||
risks associated with Your exercise of permissions under this License. |
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, |
||||
whether in tort (including negligence), contract, or otherwise, |
||||
unless required by applicable law (such as deliberate and grossly |
||||
negligent acts) or agreed to in writing, shall any Contributor be |
||||
liable to You for damages, including any direct, indirect, special, |
||||
incidental, or consequential damages of any character arising as a |
||||
result of this License or out of the use or inability to use the |
||||
Work (including but not limited to damages for loss of goodwill, |
||||
work stoppage, computer failure or malfunction, or any and all |
||||
other commercial damages or losses), even if such Contributor |
||||
has been advised of the possibility of such damages. |
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing |
||||
the Work or Derivative Works thereof, You may choose to offer, |
||||
and charge a fee for, acceptance of support, warranty, indemnity, |
||||
or other liability obligations and/or rights consistent with this |
||||
License. However, in accepting such obligations, You may act only |
||||
on Your own behalf and on Your sole responsibility, not on behalf |
||||
of any other Contributor, and only if You agree to indemnify, |
||||
defend, and hold each Contributor harmless for any liability |
||||
incurred by, or claims asserted against, such Contributor by reason |
||||
of your accepting any such warranty or additional liability. |
||||
|
||||
END OF TERMS AND CONDITIONS |
@ -0,0 +1,23 @@
|
||||
TARGETS := $(shell ls scripts)
|
||||
|
||||
.dapper: |
||||
@echo Downloading dapper
|
||||
@curl -sL https://releases.rancher.com/dapper/latest/dapper-`uname -s`-`uname -m` > .dapper.tmp
|
||||
@@chmod +x .dapper.tmp
|
||||
@./.dapper.tmp -v
|
||||
@mv .dapper.tmp .dapper
|
||||
|
||||
$(TARGETS): .dapper |
||||
./.dapper $@
|
||||
|
||||
trash: .dapper |
||||
./.dapper -m bind trash
|
||||
|
||||
trash-keep: .dapper |
||||
./.dapper -m bind trash -k
|
||||
|
||||
deps: trash |
||||
|
||||
.DEFAULT_GOAL := ci
|
||||
|
||||
.PHONY: $(TARGETS) |
@ -0,0 +1,223 @@
|
||||
package config |
||||
|
||||
import ( |
||||
"crypto/md5" |
||||
"crypto/tls" |
||||
"encoding/hex" |
||||
"encoding/pem" |
||||
"fmt" |
||||
"io/ioutil" |
||||
"net/url" |
||||
"os" |
||||
"path/filepath" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/pkg/errors" |
||||
"github.com/rancher/norman/pkg/clientaccess" |
||||
"github.com/rancher/rio/pkg/daemons/config" |
||||
"github.com/sirupsen/logrus" |
||||
"k8s.io/apimachinery/pkg/util/json" |
||||
net2 "k8s.io/apimachinery/pkg/util/net" |
||||
"k8s.io/client-go/util/cert" |
||||
) |
||||
|
||||
type envInfo struct { |
||||
ServerURL string |
||||
Token string |
||||
DataDir string |
||||
NodeIP string |
||||
NodeName string |
||||
} |
||||
|
||||
func Get() *config.Node { |
||||
for { |
||||
agentConfig, err := get() |
||||
if err != nil { |
||||
logrus.Error(err) |
||||
time.Sleep(5 * time.Second) |
||||
continue |
||||
} |
||||
return agentConfig |
||||
} |
||||
} |
||||
|
||||
func getEnvInfo() (*envInfo, error) { |
||||
u := os.Getenv("K3S_URL") |
||||
if u == "" { |
||||
return nil, fmt.Errorf("K3S_URL env var is required") |
||||
} |
||||
|
||||
_, err := url.Parse(u) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("K3S_URL [%s] is invalid: %v", u, err) |
||||
} |
||||
|
||||
t := os.Getenv("K3S_TOKEN") |
||||
if t == "" { |
||||
return nil, fmt.Errorf("K3S_TOKEN env var is required") |
||||
} |
||||
|
||||
dataDir := os.Getenv("K3S_DATA_DIR") |
||||
if dataDir == "" { |
||||
return nil, fmt.Errorf("K3S_DATA_DIR is required") |
||||
} |
||||
|
||||
return &envInfo{ |
||||
ServerURL: u, |
||||
Token: t, |
||||
DataDir: dataDir, |
||||
NodeIP: os.Getenv("K3S_NODE_IP"), |
||||
NodeName: os.Getenv("NODE_NAME"), |
||||
}, nil |
||||
} |
||||
|
||||
func getNodeCert(info *clientaccess.Info) (*tls.Certificate, error) { |
||||
nodeCert, err := clientaccess.Get("/v1-k3s/node.cert", info) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
nodeKey, err := clientaccess.Get("/v1-k3s/node.key", info) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
cert, err := tls.X509KeyPair(nodeCert, nodeKey) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return &cert, nil |
||||
} |
||||
|
||||
func writeNodeCA(dataDir string, nodeCert *tls.Certificate) (string, error) { |
||||
clientCABytes := pem.EncodeToMemory(&pem.Block{ |
||||
Type: "CERTIFICATE", |
||||
Bytes: nodeCert.Certificate[1], |
||||
}) |
||||
|
||||
clientCA := filepath.Join(dataDir, "client-ca.pem") |
||||
if err := ioutil.WriteFile(clientCA, clientCABytes, 0600); err != nil { |
||||
return "", errors.Wrapf(err, "failed to write client CA") |
||||
} |
||||
|
||||
return clientCA, nil |
||||
} |
||||
|
||||
func getHostnameAndIP(info envInfo) (string, string, error) { |
||||
ip := info.NodeIP |
||||
if ip == "" { |
||||
hostIP, err := net2.ChooseHostInterface() |
||||
if err != nil { |
||||
return "", "", err |
||||
} |
||||
ip = hostIP.String() |
||||
} |
||||
|
||||
name := info.NodeName |
||||
if name == "" { |
||||
hostname, err := os.Hostname() |
||||
if err != nil { |
||||
return "", "", err |
||||
} |
||||
hostname = strings.Split(hostname, ".")[0] |
||||
|
||||
d := md5.Sum([]byte(ip)) |
||||
name = hostname + "-" + hex.EncodeToString(d[:])[:8] |
||||
} |
||||
|
||||
return name, ip, nil |
||||
} |
||||
|
||||
func localAddress(controlConfig *config.Control) string { |
||||
return fmt.Sprintf("127.0.0.1:%d", controlConfig.AdvertisePort) |
||||
} |
||||
|
||||
func writeKubeConfig(envInfo *envInfo, info clientaccess.Info, controlConfig *config.Control, nodeCert *tls.Certificate) (string, error) { |
||||
os.MkdirAll(envInfo.DataDir, 0700) |
||||
kubeConfigPath := filepath.Join(envInfo.DataDir, "kubeconfig.yaml") |
||||
|
||||
info.URL = "https://" + localAddress(controlConfig) |
||||
info.CACerts = pem.EncodeToMemory(&pem.Block{ |
||||
Type: cert.CertificateBlockType, |
||||
Bytes: nodeCert.Certificate[1], |
||||
}) |
||||
|
||||
return kubeConfigPath, info.WriteKubeConfig(kubeConfigPath) |
||||
} |
||||
|
||||
func get() (*config.Node, error) { |
||||
envInfo, err := getEnvInfo() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
serverURLParsed, err := url.Parse(envInfo.ServerURL) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
info, err := clientaccess.ParseAndValidateToken(envInfo.ServerURL, envInfo.Token) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
controlConfig, err := getConfig(info) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
nodeCert, err := getNodeCert(info) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
clientCA, err := writeNodeCA(envInfo.DataDir, nodeCert) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
nodeName, nodeIP, err := getHostnameAndIP(*envInfo) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
kubeConfig, err := writeKubeConfig(envInfo, *info, controlConfig, nodeCert) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
nodeConfig := &controlConfig.NodeConfig |
||||
nodeConfig.LocalAddress = localAddress(controlConfig) |
||||
nodeConfig.AgentConfig.NodeIP = defString(nodeConfig.AgentConfig.NodeIP, nodeIP) |
||||
nodeConfig.AgentConfig.NodeName = defString(nodeConfig.AgentConfig.NodeName, nodeName) |
||||
nodeConfig.AgentConfig.CNIBinDir = defString(nodeConfig.AgentConfig.CNIBinDir, "/usr/share/cni") |
||||
nodeConfig.AgentConfig.CACertPath = clientCA |
||||
nodeConfig.AgentConfig.ListenAddress = defString(nodeConfig.AgentConfig.ListenAddress, "127.0.0.1") |
||||
nodeConfig.AgentConfig.KubeConfig = kubeConfig |
||||
nodeConfig.CACerts = info.CACerts |
||||
nodeConfig.ServerAddress = serverURLParsed.Host |
||||
nodeConfig.Certificate = nodeCert |
||||
if !nodeConfig.Docker { |
||||
nodeConfig.AgentConfig.RuntimeSocket = "/run/k3s/containerd.sock" |
||||
} |
||||
|
||||
return nodeConfig, nil |
||||
} |
||||
|
||||
func defString(val, newVal string) string { |
||||
if val == "" { |
||||
return newVal |
||||
} |
||||
return val |
||||
} |
||||
|
||||
func getConfig(info *clientaccess.Info) (*config.Control, error) { |
||||
data, err := clientaccess.Get("/v1-k3s/config", info) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
controlControl := &config.Control{} |
||||
return controlControl, json.Unmarshal(data, controlControl) |
||||
} |
@ -0,0 +1,89 @@
|
||||
package containerd |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"os" |
||||
"os/exec" |
||||
"strings" |
||||
"syscall" |
||||
"time" |
||||
|
||||
"github.com/rancher/rio/agent/config" |
||||
util2 "github.com/rancher/rio/agent/util" |
||||
"github.com/sirupsen/logrus" |
||||
"google.golang.org/grpc" |
||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" |
||||
"k8s.io/kubernetes/pkg/kubelet/util" |
||||
) |
||||
|
||||
const ( |
||||
address = "/run/k3s/containerd.sock" |
||||
maxMsgSize = 1024 * 1024 * 16 |
||||
configToml = `[plugins.cri] |
||||
stream_server_address = "%NODE%" |
||||
stream_server_port = "10010" |
||||
[plugins.cri.cni] |
||||
bin_dir = "/usr/share/cni/bin" |
||||
conf_dir = "/etc/cni/net.d" |
||||
` |
||||
) |
||||
|
||||
func Run(ctx context.Context, config *config.NodeConfig) error { |
||||
args := []string{ |
||||
"containerd", |
||||
"-a", address, |
||||
"--state", "/run/k3s/containerd", |
||||
} |
||||
|
||||
if err := util2.WriteFile("/etc/containerd/config.toml", |
||||
strings.Replace(configToml, "%NODE%", config.AgentConfig.NodeName, -1)); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if logrus.GetLevel() >= logrus.DebugLevel { |
||||
args = append(args, "--verbose") |
||||
} |
||||
|
||||
go func() { |
||||
cmd := exec.Command(args[0], args[1:]...) |
||||
cmd.Stdout = os.Stdout |
||||
cmd.Stderr = os.Stderr |
||||
cmd.SysProcAttr = &syscall.SysProcAttr{ |
||||
Pdeathsig: syscall.SIGKILL, |
||||
} |
||||
if err := cmd.Run(); err != nil { |
||||
fmt.Fprintf(os.Stderr, "containerd: %s\n", err) |
||||
} |
||||
os.Exit(1) |
||||
}() |
||||
|
||||
for { |
||||
addr, dailer, err := util.GetAddressAndDialer("unix://" + address) |
||||
if err != nil { |
||||
time.Sleep(1 * time.Second) |
||||
continue |
||||
} |
||||
|
||||
conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithTimeout(3*time.Second), grpc.WithDialer(dailer), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMsgSize))) |
||||
if err != nil { |
||||
time.Sleep(1 * time.Second) |
||||
continue |
||||
} |
||||
|
||||
c := runtimeapi.NewRuntimeServiceClient(conn) |
||||
|
||||
_, err = c.Version(ctx, &runtimeapi.VersionRequest{ |
||||
Version: "0.1.0", |
||||
}) |
||||
if err == nil { |
||||
conn.Close() |
||||
break |
||||
} |
||||
conn.Close() |
||||
logrus.Infof("Waiting for containerd startup") |
||||
time.Sleep(1 * time.Second) |
||||
} |
||||
|
||||
return nil |
||||
} |
@ -0,0 +1,140 @@
|
||||
// Copyright 2015 flannel authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package flannel |
||||
|
||||
import ( |
||||
"fmt" |
||||
"net" |
||||
"os" |
||||
"path/filepath" |
||||
"sync" |
||||
|
||||
"github.com/coreos/flannel/backend" |
||||
"github.com/coreos/flannel/network" |
||||
"github.com/coreos/flannel/pkg/ip" |
||||
"github.com/coreos/flannel/subnet/kube" |
||||
"golang.org/x/net/context" |
||||
log "k8s.io/klog" |
||||
|
||||
// Backends need to be imported for their init() to get executed and them to register
|
||||
_ "github.com/coreos/flannel/backend/vxlan" |
||||
) |
||||
|
||||
const ( |
||||
subnetFile = "/run/flannel/subnet.env" |
||||
) |
||||
|
||||
func flannel(ctx context.Context, kubeConfigFile string) error { |
||||
extIface, err := LookupExtIface() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
sm, err := kube.NewSubnetManager("", kubeConfigFile) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
config, err := sm.GetNetworkConfig(ctx) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
// Create a backend manager then use it to create the backend and register the network with it.
|
||||
bm := backend.NewManager(ctx, sm, extIface) |
||||
|
||||
be, err := bm.GetBackend(config.BackendType) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
bn, err := be.RegisterNetwork(ctx, sync.WaitGroup{}, config) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
go network.SetupAndEnsureIPTables(network.MasqRules(config.Network, bn.Lease()), 60) |
||||
go network.SetupAndEnsureIPTables(network.ForwardRules(config.Network.String()), 50) |
||||
|
||||
if err := WriteSubnetFile(subnetFile, config.Network, true, bn); err != nil { |
||||
// Continue, even though it failed.
|
||||
log.Warningf("Failed to write subnet file: %s", err) |
||||
} else { |
||||
log.Infof("Wrote subnet file to %s", subnetFile) |
||||
} |
||||
|
||||
// Start "Running" the backend network. This will block until the context is done so run in another goroutine.
|
||||
log.Info("Running backend.") |
||||
bn.Run(ctx) |
||||
return nil |
||||
} |
||||
|
||||
func LookupExtIface() (*backend.ExternalInterface, error) { |
||||
var iface *net.Interface |
||||
var ifaceAddr net.IP |
||||
var err error |
||||
|
||||
log.Info("Determining IP address of default interface") |
||||
if iface, err = ip.GetDefaultGatewayIface(); err != nil { |
||||
return nil, fmt.Errorf("failed to get default interface: %s", err) |
||||
} |
||||
|
||||
ifaceAddr, err = ip.GetIfaceIP4Addr(iface) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("failed to find IPv4 address for interface %s", iface.Name) |
||||
} |
||||
|
||||
log.Infof("Using interface with name %s and address %s", iface.Name, ifaceAddr) |
||||
|
||||
if iface.MTU == 0 { |
||||
return nil, fmt.Errorf("failed to determine MTU for %s interface", ifaceAddr) |
||||
} |
||||
|
||||
return &backend.ExternalInterface{ |
||||
Iface: iface, |
||||
IfaceAddr: ifaceAddr, |
||||
ExtAddr: ifaceAddr, |
||||
}, nil |
||||
} |
||||
|
||||
func WriteSubnetFile(path string, nw ip.IP4Net, ipMasq bool, bn backend.Network) error { |
||||
dir, name := filepath.Split(path) |
||||
os.MkdirAll(dir, 0755) |
||||
|
||||
tempFile := filepath.Join(dir, "."+name) |
||||
f, err := os.Create(tempFile) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
// Write out the first usable IP by incrementing
|
||||
// sn.IP by one
|
||||
sn := bn.Lease().Subnet |
||||
sn.IP += 1 |
||||
|
||||
fmt.Fprintf(f, "FLANNEL_NETWORK=%s\n", nw) |
||||
fmt.Fprintf(f, "FLANNEL_SUBNET=%s\n", sn) |
||||
fmt.Fprintf(f, "FLANNEL_MTU=%d\n", bn.MTU()) |
||||
_, err = fmt.Fprintf(f, "FLANNEL_IPMASQ=%v\n", ipMasq) |
||||
f.Close() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
// rename(2) the temporary file to the desired location so that it becomes
|
||||
// atomically visible with the contents
|
||||
return os.Rename(tempFile, path) |
||||
//TODO - is this safe? What if it's not on the same FS?
|
||||
} |
@ -0,0 +1,91 @@
|
||||
package flannel |
||||
|
||||
import ( |
||||
"context" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/rancher/rio/agent/util" |
||||
|
||||
"github.com/rancher/rio/agent/config" |
||||
"github.com/sirupsen/logrus" |
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||
"k8s.io/client-go/kubernetes" |
||||
"k8s.io/client-go/tools/clientcmd" |
||||
) |
||||
|
||||
const ( |
||||
cniConf = `{ |
||||
"name":"cbr0", |
||||
"cniVersion":"0.3.1", |
||||
"plugins":[ |
||||
{ |
||||
"type":"flannel", |
||||
"delegate":{ |
||||
"forceAddress":true, |
||||
"isDefaultGateway":true |
||||
} |
||||
}, |
||||
{ |
||||
"type":"portmap", |
||||
"capabilities":{ |
||||
"portMappings":true |
||||
} |
||||
} |
||||
] |
||||
} |
||||
` |
||||
netJson = `{ |
||||
"Network": "%CIDR%", |
||||
"Backend": { |
||||
"Type": "vxlan" |
||||
} |
||||
} |
||||
` |
||||
) |
||||
|
||||
func Run(ctx context.Context, config *config.NodeConfig) error { |
||||
nodeName := config.AgentConfig.NodeName |
||||
|
||||
restConfig, err := clientcmd.BuildConfigFromFlags("", config.AgentConfig.KubeConfig) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
client, err := kubernetes.NewForConfig(restConfig) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
for { |
||||
node, err := client.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{}) |
||||
if err == nil && node.Spec.PodCIDR != "" { |
||||
break |
||||
} |
||||
if err == nil { |
||||
logrus.Infof("waiting for node %s CIDR not assigned yet", nodeName) |
||||
} else { |
||||
logrus.Infof("waiting for node %s: %v", nodeName, err) |
||||
} |
||||
time.Sleep(2 * time.Second) |
||||
} |
||||
|
||||
if err := createCNIConf(); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := createFlannelConf(config); err != nil { |
||||
return err |
||||
} |
||||
|
||||
return flannel(ctx, config.AgentConfig.KubeConfig) |
||||
} |
||||
|
||||
func createCNIConf() error { |
||||
return util.WriteFile("/etc/cni/net.d/10-flannel.conflist", cniConf) |
||||
} |
||||
|
||||
func createFlannelConf(config *config.NodeConfig) error { |
||||
return util.WriteFile("/etc/kube-flannel/net-conf.json", |
||||
strings.Replace(netJson, "%CIDR", config.AgentConfig.ClusterCIDR.String(), -1)) |
||||
} |
@ -0,0 +1,58 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/rancher/norman/signal" |
||||
"github.com/rancher/rio/agent/config" |
||||
"github.com/rancher/rio/agent/containerd" |
||||
"github.com/rancher/rio/agent/flannel" |
||||
"github.com/rancher/rio/agent/proxy" |
||||
"github.com/rancher/rio/agent/syssetup" |
||||
"github.com/rancher/rio/agent/tunnel" |
||||
"github.com/rancher/rio/pkg/daemons/agent" |
||||
"github.com/sirupsen/logrus" |
||||
) |
||||
|
||||
func main() { |
||||
if err := run(); err != nil { |
||||
logrus.Fatal(err) |
||||
} |
||||
} |
||||
|
||||
func run() error { |
||||
ctx := signal.SigTermCancelContext(context.Background()) |
||||
|
||||
nodeConfig := config.Get() |
||||
|
||||
if nodeConfig.Docker { |
||||
nodeConfig.AgentConfig.RuntimeSocket = "" |
||||
} else { |
||||
containerd.Run(ctx, nodeConfig) |
||||
} |
||||
|
||||
if err := syssetup.Configure(); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := tunnel.Setup(nodeConfig); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := proxy.Run(nodeConfig); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := agent.Agent(&nodeConfig.AgentConfig); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if !nodeConfig.NoFlannel { |
||||
if err := flannel.Run(ctx, nodeConfig); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
|
||||
<-ctx.Done() |
||||
return ctx.Err() |
||||
} |
@ -0,0 +1,35 @@
|
||||
package proxy |
||||
|
||||
import ( |
||||
"crypto/tls" |
||||
"net/http" |
||||
|
||||
"github.com/pkg/errors" |
||||
"github.com/rancher/norman/pkg/proxy" |
||||
"github.com/rancher/rio/agent/config" |
||||
"github.com/sirupsen/logrus" |
||||
) |
||||
|
||||
func Run(config *config.NodeConfig) error { |
||||
proxy, err := proxy.NewSimpleProxy(config.ServerAddress, config.CACerts, true) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
listener, err := tls.Listen("tcp", config.LocalAddress, &tls.Config{ |
||||
Certificates: []tls.Certificate{ |
||||
*config.Certificate, |
||||
}, |
||||
}) |
||||
|
||||
if err != nil { |
||||
return errors.Wrap(err, "Failed to start tls listener") |
||||
} |
||||
|
||||
go func() { |
||||
err := http.Serve(listener, proxy) |
||||
logrus.Fatalf("TLS proxy stopped: %v", err) |
||||
}() |
||||
|
||||
return nil |
||||
} |
@ -0,0 +1,18 @@
|
||||
package syssetup |
||||
|
||||
import ( |
||||
"io/ioutil" |
||||
|
||||
"github.com/sirupsen/logrus" |
||||
) |
||||
|
||||
var ( |
||||
callIPTablesFile = "/proc/sys/net/bridge/bridge-nf-call-iptables" |
||||
) |
||||
|
||||
func Configure() error { |
||||
if err := ioutil.WriteFile(callIPTablesFile, []byte("1"), 0640); err != nil { |
||||
logrus.Warnf("failed to write value 1 at %s: %v", callIPTablesFile, err) |
||||
} |
||||
return nil |
||||
} |
@ -0,0 +1,79 @@
|
||||
package tunnel |
||||
|
||||
import ( |
||||
"context" |
||||
"crypto/tls" |
||||
"crypto/x509" |
||||
"encoding/base64" |
||||
"fmt" |
||||
"net" |
||||
"net/http" |
||||
"sync" |
||||
"time" |
||||
|
||||
"github.com/gorilla/websocket" |
||||
"github.com/rancher/norman/pkg/remotedialer" |
||||
"github.com/rancher/rio/agent/config" |
||||
"github.com/sirupsen/logrus" |
||||
"k8s.io/client-go/tools/clientcmd" |
||||
) |
||||
|
||||
var ( |
||||
ports = map[string]bool{ |
||||
"10250": true, |
||||
"10010": true, |
||||
} |
||||
) |
||||
|
||||
func Setup(config *config.NodeConfig) error { |
||||
restConfig, err := clientcmd.BuildConfigFromFlags("", config.AgentConfig.KubeConfig) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
transportConfig, err := restConfig.TransportConfig() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
wsURL := fmt.Sprintf("wss://%s/v1/connect", config.ServerAddress) |
||||
headers := map[string][]string{ |
||||
"X-K3s-NodeName": {config.AgentConfig.NodeName}, |
||||
} |
||||
ws := &websocket.Dialer{} |
||||
|
||||
if len(config.CACerts) > 0 { |
||||
pool := x509.NewCertPool() |
||||
pool.AppendCertsFromPEM(config.CACerts) |
||||
ws.TLSClientConfig = &tls.Config{ |
||||
RootCAs: pool, |
||||
} |
||||
} |
||||
|
||||
if transportConfig.Username != "" { |
||||
auth := transportConfig.Username + ":" + transportConfig.Password |
||||
auth = base64.StdEncoding.EncodeToString([]byte(auth)) |
||||
headers["Authorization"] = []string{"Basic " + auth} |
||||
} |
||||
|
||||
once := sync.Once{} |
||||
wg := sync.WaitGroup{} |
||||
wg.Add(1) |
||||
|
||||
go func() { |
||||
for { |
||||
logrus.Infof("Connecting to %s", wsURL) |
||||
remotedialer.ClientConnect(wsURL, http.Header(headers), ws, func(proto, address string) bool { |
||||
host, port, err := net.SplitHostPort(address) |
||||
return err == nil && proto == "tcp" && ports[port] && host == "127.0.0.1" |
||||
}, func(_ context.Context) error { |
||||
once.Do(wg.Done) |
||||
return nil |
||||
}) |
||||
time.Sleep(5 * time.Second) |
||||
} |
||||
}() |
||||
|
||||
wg.Wait() |
||||
return nil |
||||
} |
@ -0,0 +1,18 @@
|
||||
package util |
||||
|
||||
import ( |
||||
"io/ioutil" |
||||
"os" |
||||
"path/filepath" |
||||
|
||||
"github.com/pkg/errors" |
||||
) |
||||
|
||||
func WriteFile(name string, content string) error { |
||||
os.Mkdir(filepath.Dir(name), 0755) |
||||
err := ioutil.WriteFile(name, []byte(content), 0644) |
||||
if err != nil { |
||||
return errors.Wrapf(err, "writing %s", name) |
||||
} |
||||
return nil |
||||
} |
@ -0,0 +1,19 @@
|
||||
package agent |
||||
|
||||
import "github.com/urfave/cli" |
||||
|
||||
type Agent struct { |
||||
T_Token string `desc:"Token to use for authentication" env:"K3S_TOKEN"` |
||||
S_Server string `desc:"Server to connect to" env:"K3S_URL"` |
||||
D_DataDir string `desc:"Folder to hold state" default:"/var/lib/rancher/k3s"` |
||||
L_Log string `desc:"log to file"` |
||||
AgentShared |
||||
} |
||||
|
||||
type AgentShared struct { |
||||
I_NodeIp string `desc:"IP address to advertise for node"` |
||||
} |
||||
|
||||
func (a *Agent) Customize(command *cli.Command) { |
||||
command.Category = "CLUSTER RUNTIME" |
||||
} |
@ -0,0 +1,81 @@
|
||||
// +build k8s
|
||||
|
||||
package agent |
||||
|
||||
import ( |
||||
"fmt" |
||||
"io" |
||||
"os" |
||||
"path/filepath" |
||||
"time" |
||||
|
||||
"github.com/natefinch/lumberjack" |
||||
"github.com/rancher/norman/pkg/clientaccess" |
||||
"github.com/rancher/norman/pkg/resolvehome" |
||||
"github.com/rancher/rio/pkg/enterchroot" |
||||
"github.com/sirupsen/logrus" |
||||
"github.com/urfave/cli" |
||||
) |
||||
|
||||
func (a *Agent) Run(ctx *cli.Context) error { |
||||
if os.Getuid() != 0 { |
||||
return fmt.Errorf("agent must be ran as root") |
||||
} |
||||
|
||||
if len(a.T_Token) == 0 { |
||||
return fmt.Errorf("--token is required") |
||||
} |
||||
|
||||
if len(a.S_Server) == 0 { |
||||
return fmt.Errorf("--server is required") |
||||
} |
||||
|
||||
dataDir, err := resolvehome.Resolve(a.D_DataDir) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
return RunAgent(a.S_Server, a.T_Token, dataDir, a.L_Log, a.I_NodeIp) |
||||
} |
||||
|
||||
func RunAgent(server, token, dataDir, logFile, ipAddress string) error { |
||||
dataDir = filepath.Join(dataDir, "agent") |
||||
|
||||
for { |
||||
tmpFile, err := clientaccess.AgentAccessInfoToTempKubeConfig("", server, token) |
||||
if err != nil { |
||||
logrus.Error(err) |
||||
time.Sleep(2 * time.Second) |
||||
continue |
||||
} |
||||
os.Remove(tmpFile) |
||||
break |
||||
} |
||||
|
||||
os.Setenv("K3S_URL", server) |
||||
os.Setenv("K3S_TOKEN", token) |
||||
os.Setenv("K3S_DATA_DIR", dataDir) |
||||
os.Setenv("K3S_NODE_IP", ipAddress) |
||||
|
||||
os.MkdirAll(dataDir, 0700) |
||||
|
||||
stdout := io.Writer(os.Stdout) |
||||
stderr := io.Writer(os.Stderr) |
||||
|
||||
if logFile == "" { |
||||
stdout = os.Stdout |
||||
stderr = os.Stderr |
||||
} else { |
||||
l := &lumberjack.Logger{ |
||||
Filename: logFile, |
||||
MaxSize: 50, |
||||
MaxBackups: 3, |
||||
MaxAge: 28, |
||||
Compress: true, |
||||
} |
||||
stdout = l |
||||
stderr = l |
||||
} |
||||
|
||||
return enterchroot.Mount(filepath.Join(dataDir, "root"), stdout, stderr, os.Args[1:]) |
||||
} |
@ -0,0 +1,17 @@
|
||||
// +build !k8s
|
||||
|
||||
package agent |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"github.com/urfave/cli" |
||||
) |
||||
|
||||
func (a *Agent) Run(ctx *cli.Context) error { |
||||
return fmt.Errorf("agent support is not compiled in, add \"-tags k8s\" to \"go build\"") |
||||
} |
||||
|
||||
func RunAgent(server, token, dataDir, logFile string) error { |
||||
return fmt.Errorf("agent support is not compiled in, add \"-tags k8s\" to \"go build\"") |
||||
} |
@ -0,0 +1,24 @@
|
||||
package kubectl |
||||
|
||||
import ( |
||||
"os" |
||||
|
||||
"github.com/rancher/rio/pkg/kubectl" |
||||
"github.com/urfave/cli" |
||||
) |
||||
|
||||
func NewKubectlCommand() cli.Command { |
||||
return cli.Command{ |
||||
Name: "kubectl", |
||||
Usage: "Run kubectl", |
||||
SkipFlagParsing: true, |
||||
SkipArgReorder: true, |
||||
Action: run, |
||||
} |
||||
} |
||||
|
||||
func run(ctx *cli.Context) error { |
||||
os.Args = append([]string{"kubectl"}, ctx.Args()...) |
||||
kubectl.Main() |
||||
return nil |
||||
} |
@ -0,0 +1,128 @@
|
||||
package server |
||||
|
||||
import ( |
||||
"context" |
||||
"flag" |
||||
"fmt" |
||||
"os" |
||||
"path/filepath" |
||||
|
||||
"github.com/docker/docker/pkg/reexec" |
||||
"github.com/natefinch/lumberjack" |
||||
"github.com/rancher/norman/signal" |
||||
"github.com/rancher/rio/pkg/server" |
||||
"github.com/sirupsen/logrus" |
||||
"github.com/urfave/cli" |
||||
"k8s.io/apimachinery/pkg/util/net" |
||||
) |
||||
|
||||
var ( |
||||
appName = filepath.Base(os.Args[0]) |
||||
|
||||
config server.Config |
||||
log string |
||||
) |
||||
|
||||
var ServerCommand = cli.Command{ |
||||
Name: "server", |
||||
Usage: "Run management server", |
||||
UsageText: appName + " server [OPTIONS]", |
||||
Action: Run, |
||||
Flags: []cli.Flag{ |
||||
cli.IntFlag{ |
||||
Name: "https-listen-port", |
||||
Usage: "HTTPS listen port", |
||||
Value: 6443, |
||||
Destination: &config.TLSConfig.HTTPSPort, |
||||
}, |
||||
cli.IntFlag{ |
||||
Name: "http-listen-port", |
||||
Usage: "HTTP listen port (for /healthz, HTTPS redirect, and port for TLS terminating LB)", |
||||
Value: 0, |
||||
Destination: &config.TLSConfig.HTTPPort, |
||||
}, |
||||
cli.StringFlag{ |
||||
Name: "data-dir", |
||||
Usage: "Folder to hold state default /var/lib/rancher/k3s or ${HOME}/.rancher/k3s if not root", |
||||
Destination: &config.ControlConfig.DataDir, |
||||
}, |
||||
//cli.StringFlag{
|
||||
// Name: "advertise-address",
|
||||
// Usage: "Address of the server to put in the generated kubeconfig",
|
||||
// Destination: &config.AdvertiseIP,
|
||||
//},
|
||||
cli.BoolFlag{ |
||||
Name: "disable-agent", |
||||
Usage: "Do not run a local agent and register a local kubelet", |
||||
Destination: &config.DisableAgent, |
||||
}, |
||||
cli.StringFlag{ |
||||
Name: "log", |
||||
Usage: "Log to file", |
||||
Destination: &log, |
||||
}, |
||||
}, |
||||
} |
||||
|
||||
func setupLogging(app *cli.Context) { |
||||
if !app.GlobalBool("debug") { |
||||
flag.Set("stderrthreshold", "3") |
||||
flag.Set("alsologtostderr", "false") |
||||
flag.Set("logtostderr", "false") |
||||
} |
||||
} |
||||
|
||||
func runWithLogging(app *cli.Context) error { |
||||
l := &lumberjack.Logger{ |
||||
Filename: log, |
||||
MaxSize: 50, |
||||
MaxBackups: 3, |
||||
MaxAge: 28, |
||||
Compress: true, |
||||
} |
||||
|
||||
args := append([]string{"k3s"}, os.Args[1:]...) |
||||
cmd := reexec.Command(args...) |
||||
cmd.Env = os.Environ() |
||||
cmd.Env = append(cmd.Env, "_RIO_REEXEC_=true") |
||||
cmd.Stderr = l |
||||
cmd.Stdout = l |
||||
cmd.Stdin = os.Stdin |
||||
return cmd.Run() |
||||
} |
||||
|
||||
func Run(app *cli.Context) error { |
||||
if log != "" && os.Getenv("_RIO_REEXEC_") == "" { |
||||
return runWithLogging(app) |
||||
} |
||||
|
||||
setupLogging(app) |
||||
|
||||
if !config.DisableAgent && os.Getuid() != 0 { |
||||
return fmt.Errorf("must run as root unless --disable-agent is specified") |
||||
} |
||||
|
||||
if config.ControlConfig.NodeConfig.AgentConfig.NodeIP == "" { |
||||
ip, err := net.ChooseHostInterface() |
||||
if err == nil { |
||||
config.ControlConfig.NodeConfig.AgentConfig.NodeIP = ip.String() |
||||
} |
||||
} |
||||
|
||||
logrus.Info("Starting k3s ", app.App.Version) |
||||
ctx := signal.SigTermCancelContext(context.Background()) |
||||
if err := server.StartServer(ctx, &config); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if config.DisableAgent { |
||||
<-ctx.Done() |
||||
return nil |
||||
} |
||||
|
||||
return nil |
||||
//logFile := filepath.Join(serverConfig.DataDir, "agent/agent.log")
|
||||
//url := fmt.Sprintf("https://localhost:%d", httpsListenPort)
|
||||
//logrus.Infof("Agent starting, logging to %s", logFile)
|
||||
//return agent.RunAgent(url, server2.FormatToken(serverConfig.Runtime.NodeToken), serverConfig.DataDir, logFile, "")
|
||||
} |
@ -0,0 +1,151 @@
|
||||
package builder |
||||
|
||||
import ( |
||||
"fmt" |
||||
"reflect" |
||||
"regexp" |
||||
"strconv" |
||||
"strings" |
||||
"unsafe" |
||||
|
||||
"github.com/urfave/cli" |
||||
) |
||||
|
||||
var ( |
||||
caseRegexp = regexp.MustCompile("([a-z])([A-Z])") |
||||
) |
||||
|
||||
type clirunnable interface { |
||||
Run(app *cli.Context) error |
||||
} |
||||
|
||||
type customizer interface { |
||||
Customize(cmd *cli.Command) |
||||
} |
||||
|
||||
type fieldInfo struct { |
||||
FieldType reflect.StructField |
||||
FieldValue reflect.Value |
||||
} |
||||
|
||||
func fields(obj interface{}) []fieldInfo { |
||||
ptrValue := reflect.ValueOf(obj) |
||||
objValue := ptrValue.Elem() |
||||
|
||||
var result []fieldInfo |
||||
|
||||
for i := 0; i < objValue.NumField(); i++ { |
||||
fieldType := objValue.Type().Field(i) |
||||
if fieldType.Anonymous && fieldType.Type.Kind() == reflect.Struct { |
||||
result = append(result, fields(objValue.Field(i).Addr().Interface())...) |
||||
} else if !fieldType.Anonymous { |
||||
result = append(result, fieldInfo{ |
||||
FieldValue: objValue.Field(i), |
||||
FieldType: objValue.Type().Field(i), |
||||
}) |
||||
} |
||||
} |
||||
|
||||
return result |
||||
} |
||||
|
||||
func Command(obj interface{}, usage, usageText, description string) cli.Command { |
||||
slices := map[string]reflect.Value{} |
||||
maps := map[string]reflect.Value{} |
||||
ptrValue := reflect.ValueOf(obj) |
||||
objValue := ptrValue.Elem() |
||||
|
||||
c := cli.Command{ |
||||
Name: strings.ToLower(strings.Replace(objValue.Type().Name(), "Command", "", 1)), |
||||
Usage: usage, |
||||
UsageText: usageText, |
||||
Description: description, |
||||
UseShortOptionHandling: true, |
||||
SkipArgReorder: true, |
||||
} |
||||
|
||||
for _, info := range fields(obj) { |
||||
defMessage := "" |
||||
fieldType := info.FieldType |
||||
v := info.FieldValue |
||||
|
||||
switch fieldType.Type.Kind() { |
||||
case reflect.Int: |
||||
flag := cli.IntFlag{ |
||||
Name: name(fieldType.Name), |
||||
Usage: fieldType.Tag.Get("desc"), |
||||
EnvVar: fieldType.Tag.Get("env"), |
||||
Destination: (*int)(unsafe.Pointer(v.Addr().Pointer())), |
||||
} |
||||
defValue := fieldType.Tag.Get("default") |
||||
if defValue != "" { |
||||
n, err := strconv.Atoi(defValue) |
||||
if err != nil { |
||||
panic("bad default " + defValue + " on field " + fieldType.Name) |
||||
} |
||||
flag.Value = n |
||||
} |
||||
c.Flags = append(c.Flags, flag) |
||||
case reflect.String: |
||||
flag := cli.StringFlag{ |
||||
Name: name(fieldType.Name), |
||||
Usage: fieldType.Tag.Get("desc"), |
||||
Value: fieldType.Tag.Get("default"), |
||||
EnvVar: fieldType.Tag.Get("env"), |
||||
Destination: (*string)(unsafe.Pointer(v.Addr().Pointer())), |
||||
} |
||||
c.Flags = append(c.Flags, flag) |
||||
case reflect.Slice: |
||||
slices[name(fieldType.Name)] = v |
||||
defMessage = " " |
||||
fallthrough |
||||
case reflect.Map: |
||||
if defMessage == "" { |
||||
maps[name(fieldType.Name)] = v |
||||
defMessage = " " |
||||
} |
||||
flag := cli.StringSliceFlag{ |
||||
Name: name(fieldType.Name), |
||||
Usage: fieldType.Tag.Get("desc") + defMessage, |
||||
EnvVar: fieldType.Tag.Get("env"), |
||||
Value: &cli.StringSlice{}, |
||||
} |
||||
c.Flags = append(c.Flags, flag) |
||||
case reflect.Bool: |
||||
flag := cli.BoolFlag{ |
||||
Name: name(fieldType.Name), |
||||
Usage: fieldType.Tag.Get("desc"), |
||||
EnvVar: fieldType.Tag.Get("env"), |
||||
Destination: (*bool)(unsafe.Pointer(v.Addr().Pointer())), |
||||
} |
||||
c.Flags = append(c.Flags, flag) |
||||
default: |
||||
panic("Unknown kind on field " + fieldType.Name + " on " + objValue.Type().Name()) |
||||
} |
||||
} |
||||
|
||||
if run, ok := obj.(clirunnable); ok { |
||||
c.Action = run.Run |
||||
} else { |
||||
panic(fmt.Sprintf("failed to find Action function for %T", obj)) |
||||
} |
||||
|
||||
cust, ok := obj.(customizer) |
||||
if ok { |
||||
cust.Customize(&c) |
||||
} |
||||
|
||||
return c |
||||
} |
||||
|
||||
func name(name string) string { |
||||
parts := strings.Split(name, "_") |
||||
i := len(parts) - 1 |
||||
name = caseRegexp.ReplaceAllString(parts[i], "$1-$2") |
||||
name = strings.ToLower(name) |
||||
result := append([]string{name}, parts[0:i]...) |
||||
for i := 0; i < len(result); i++ { |
||||
result[i] = strings.ToLower(result[i]) |
||||
} |
||||
return strings.Join(result, ",") |
||||
} |
@ -0,0 +1,179 @@
|
||||
### BASE ### |
||||
FROM alpine:3.8 as base |
||||
RUN apk -U add findutils iptables ipset bash ca-certificates jq iproute2 nfs-utils coreutils libseccomp conntrack-tools |
||||
# RUN apk -U add eudev tinyssh e2fsprogs mdadm rsync nfs-utils parted |
||||
|
||||
FROM base as k3s-build |
||||
COPY --from=base /bin /usr/src/image/bin/ |
||||
COPY --from=base /lib /usr/src/image/lib/ |
||||
COPY --from=base /sbin /usr/src/image/sbin/ |
||||
COPY --from=base /etc/ssl/certs/ca-certificates.crt /usr/src/image/etc/ssl/certs/ca-certificates.crt |
||||
COPY --from=base /etc/terminfo /usr/src/image/etc/terminfo |
||||
COPY --from=base /usr /usr/src/image/usr/ |
||||
|
||||
WORKDIR /usr/src/image |
||||
|
||||
RUN rm -rf usr/bin/iconv \ |
||||
usr/bin/scanelf \ |
||||
usr/bin/ssl_client \ |
||||
usr/bin/pkgconf \ |
||||
usr/bin/getent \ |
||||
usr/bin/locate \ |
||||
usr/bin/updatedb \ |
||||
usr/bin/c_rehash \ |
||||
usr/bin/getconf \ |
||||
usr/etc \ |
||||
usr/include \ |
||||
usr/lib/bash \ |
||||
usr/lib/krb5 \ |
||||
usr/lib/pkgconfig \ |
||||
usr/lib/tc \ |
||||
usr/libexec \ |
||||
usr/local \ |
||||
usr/sbin/nfsiostat \ |
||||
usr/sbin/rpc.gssd \ |
||||
usr/sbin/nfsidmap \ |
||||
usr/sbin/blkmapd \ |
||||
usr/sbin/conntrackd \ |
||||
usr/sbin/nfct \ |
||||
usr/sbin/nfsstat \ |
||||
usr/sbin/mountstats \ |
||||
usr/sbin/setcap \ |
||||
usr/sbin/exportfs \ |
||||
usr/sbin/update-ca-certificates \ |
||||
usr/sbin/capsh \ |
||||
usr/sbin/getcap \ |
||||
usr/sbin/rpcdebug \ |
||||
usr/sbin/start-statd \ |
||||
usr/sbin/getpcaps \ |
||||
usr/sbin/sm-notify \ |
||||
usr/share/aclocal \ |
||||
usr/share/apk \ |
||||
usr/share/ca-certificates \ |
||||
usr/share/man \ |
||||
usr/share/misc && \ |
||||
find usr/share/terminfo -type f -exec rm {} \; && \ |
||||
ln -s xterm-color usr/share/terminfo/x/xterm-256color && \ |
||||
rmdir usr/share/terminfo/* || true |
||||
RUN rm -rf bin/sh \ |
||||
lib/apk \ |
||||
lib/mdev \ |
||||
sbin/ss \ |
||||
sbin/routel \ |
||||
sbin/*-compat* \ |
||||
sbin/genl \ |
||||
sbin/lnstat \ |
||||
sbin/ifstat \ |
||||
sbin/mkmntdirs \ |
||||
sbin/nfsdcltrack \ |
||||
sbin/rtacct \ |
||||
sbin/nstat \ |
||||
sbin/routef \ |
||||
sbin/apk \ |
||||
sbin/tc \ |
||||
sbin/ifcfg \ |
||||
sbin/setup-udev \ |
||||
sbin/rtpr \ |
||||
sbin/osd_login \ |
||||
sbin/bridge \ |
||||
sbin/rtmon && \ |
||||
ln -s bash bin/sh && \ |
||||
mkdir -p lib/modules |
||||
|
||||
RUN mv sbin/* bin/ && \ |
||||
rmdir sbin && \ |
||||
ln -s bin sbin |
||||
|
||||
RUN mkdir lib2 && \ |
||||
mv usr/lib/* lib2/ && \ |
||||
mv lib2/* lib/ && \ |
||||
mv usr/bin/* bin/ && \ |
||||
mv usr/sbin/* bin/ && \ |
||||
mv usr/share . && \ |
||||
rm -rf usr lib2 && \ |
||||
for i in $(ls -l bin | grep usr/bin/coreutils | awk '{print $(NF-2)}'); do \ |
||||
rm bin/$i && ln -s coreutils bin/$i \ |
||||
;done && \ |
||||
find -L bin -type l -exec rm {} \; -print |
||||
|
||||
RUN apk add upx && \ |
||||
upx $(find bin -type f -executable \! -name coreutils) || true |
||||
|
||||
RUN echo '#### LAYOUT #####' && \ |
||||
find -type d && \ |
||||
echo '#### BIN #####' && \ |
||||
find bin -type f -executable && \ |
||||
du -x -s -h |
||||
|
||||
RUN tar cf ../rootfs.tar * && \ |
||||
ls -la ../rootfs.tar |
||||
|
||||
CMD ["sh"] |
||||
|
||||
### BUILD IMAGE ### |
||||
FROM golang:1.11-alpine AS gobuild |
||||
RUN apk -U add git gcc linux-headers musl-dev make libseccomp libseccomp-dev bash |
||||
RUN rm -f /bin/sh && ln -s /bin/bash /bin/sh |
||||
|
||||
### CNI ### |
||||
FROM gobuild AS cni |
||||
RUN mkdir -p $GOPATH/src/github.com/containernetworking && \ |
||||
cd $GOPATH/src/github.com/containernetworking && \ |
||||
git clone https://github.com/ibuildthecloud/plugins.git && \ |
||||
cd plugins && \ |
||||
git checkout 9810b7d5137b171c4e07ce59bb18be9feccec557 |
||||
RUN go build -buildmode=pie -ldflags -s -o /usr/bin/cni github.com/containernetworking/plugins |
||||
|
||||
### RUNC ### |
||||
FROM gobuild AS runc |
||||
RUN go get -d github.com/opencontainers/runc && \ |
||||
git -C $GOPATH/src/github.com/opencontainers/runc checkout -b build v1.0.0-rc5 |
||||
WORKDIR $GOPATH/src/github.com/opencontainers/runc |
||||
RUN make runc && \ |
||||
cp runc /usr/bin/ |
||||
|
||||
### CONTAINERD ### |
||||
FROM gobuild AS containerd |
||||
RUN go get -d github.com/containerd/containerd && \ |
||||
git -C $GOPATH/src/github.com/containerd/containerd checkout -b build v1.1.4 |
||||
WORKDIR $GOPATH/src/github.com/containerd/containerd |
||||
RUN sed -i -e '/aufs/d' -e '/zfs/d' cmd/containerd/builtins_linux.go |
||||
RUN make BUILDTAGS="apparmor seccomp no_btrfs netgo osusergo" bin/containerd bin/containerd-shim && \ |
||||
cp bin/containerd bin/containerd-shim /usr/bin/ |
||||
|
||||
### AGENT ### |
||||
FROM gobuild AS agent |
||||
ADD /build/vendor.tar $GOPATH/src/github.com/rancher/rio/ |
||||
COPY /agent $GOPATH/src/github.com/rancher/rio/agent |
||||
WORKDIR $GOPATH/src/github.com/rancher/rio |
||||
RUN go build -buildmode=pie -tags k3s -ldflags -s -o /usr/bin/agent ./agent |
||||
|
||||
### ASSEMBLE IMAGE ### |
||||
FROM gobuild |
||||
|
||||
RUN apk add -U squashfs-tools |
||||
|
||||
COPY --from=k3s-build /usr/src/rootfs.tar /usr/src/rootfs.tar |
||||
RUN mkdir /usr/src/image && \ |
||||
tar xf /usr/src/rootfs.tar -C /usr/src/image |
||||
|
||||
COPY --from=runc /usr/bin/runc /usr/src/image/bin/runc |
||||
RUN strip --strip-unneeded /usr/src/image/bin/runc |
||||
|
||||
COPY --from=agent /usr/bin/agent /usr/src/image/bin/ |
||||
RUN strip --strip-unneeded /usr/src/image/bin/agent |
||||
|
||||
COPY --from=containerd /usr/bin/containerd-shim /usr/bin/containerd /usr/src/image/bin/ |
||||
#COPY containerd /usr/src/image/bin |
||||
RUN strip --strip-unneeded /usr/src/image/bin/containerd /usr/src/image/bin/containerd-shim |
||||
|
||||
RUN mkdir -p /usr/src/image/share/cni/bin |
||||
COPY --from=cni /usr/bin/cni /usr/src/image/share/cni/bin |
||||
RUN cd /usr/src/image/share/cni/bin && \ |
||||
for i in ./bridge ./flannel ./host-local ./loopback ./portmap; do \ |
||||
ln -s cni $i \ |
||||
;done |
||||
|
||||
COPY image/init /usr/src/image/init |
||||
|
||||
RUN mksquashfs /usr/src/image main.squashfs |
@ -0,0 +1,19 @@
|
||||
#!/bin/bash |
||||
set -e |
||||
|
||||
cd $(dirname $0) |
||||
rm -rf main.squashfs |
||||
|
||||
pushd .. |
||||
mkdir -p build |
||||
echo Copying vendor |
||||
tar chf build/vendor.tar \ |
||||
--exclude vendor/github.com/coreos/etcd/cmd \ |
||||
--exclude vendor/github.com/jteeuwen/go-bindata/testdata \ |
||||
--exclude vendor/github.com/karrick/godirwalk/testdata \ |
||||
vendor |
||||
echo Running agent docker build |
||||
docker build -t bb -f image/Dockerfile . |
||||
popd |
||||
|
||||
docker run --rm bb cat main.squashfs > main.squashfs |
@ -0,0 +1,147 @@
|
||||
#!/usr/bin/sh |
||||
set -e |
||||
|
||||
if [ "$ENTER_DEBUG" = true ]; then |
||||
set -x |
||||
fi |
||||
|
||||
layout() |
||||
{ |
||||
mount --make-rshared / |
||||
|
||||
mkdir -p /proc |
||||
mount -t proc -o nodev,nosuid,noexec,relatime none /proc |
||||
|
||||
for i in cache empty lib local local log opt spool tmp; do |
||||
mkdir -p /var/$i |
||||
done |
||||
|
||||
for i in run dev home mnt media opt root lib/modules lib/firmware var/lib/docker; do |
||||
if [ -d /.root/$i ]; then |
||||
mkdir -p /$i |
||||
mount --rbind /.root/$i /$i |
||||
fi |
||||
done |
||||
|
||||
if [ -L /.root/var/run ]; then |
||||
ln -sf /run /var/run |
||||
else |
||||
mkdir -p /var/run |
||||
mount --rbind /.root/var/run /var/run |
||||
fi |
||||
|
||||
mkdir -p $K3S_DATA_DIR |
||||
mount --rbind /.root/$K3S_DATA_DIR /$K3S_DATA_DIR |
||||
|
||||
mkdir -p /run/k3s/containerd |
||||
} |
||||
|
||||
sysfs() |
||||
{ |
||||
mkdir -p /sys |
||||
mount -t sysfs none /sys |
||||
|
||||
mount -t securityfs -o noexec,nosuid,nodev none /sys/kernel/security 2>/dev/null|| true |
||||
mount -t configfs -o noexec,nosuid,nodev none /sys/kernel/config 2>/dev/null || true |
||||
mount -t fusectl -o noexec,nosuid,nodev none /sys/fs/fuse/connections 2>/dev/null || true |
||||
mount -t binfmt_misc -o noexec,nosuid,nodev none /proc/sys/fs/binfmt_misc 2>/dev/null || true |
||||
} |
||||
|
||||
cgroups() |
||||
{ |
||||
mount -t tmpfs -o mode=755,size=10m none /sys/fs/cgroup |
||||
cat /proc/cgroups > /tmp/cgroups |
||||
|
||||
for i in $(seq 0 20); do |
||||
t="" |
||||
l="$(cat /tmp/cgroups | grep '1$' | awk '{print $1 " " $2}' | grep -w $i | awk '{print $1}')" |
||||
for j in $l; do |
||||
if [ -z "$t" ]; then |
||||
t=$j |
||||
else |
||||
t="${t},$j" |
||||
fi |
||||
done |
||||
|
||||
if [ -z "$t" ]; then |
||||
continue |
||||
fi |
||||
|
||||
mkdir -p /sys/fs/cgroup/${t} |
||||
mount -t cgroup -o ${t},noexec,nosuid,nodev none /sys/fs/cgroup/${t} |
||||
mkdir -p /sys/fs/cgroup/${t}/k3s |
||||
|
||||
for j in $l; do |
||||
if [ $j != $t ]; then |
||||
ln -s $t /sys/fs/cgroup/$j |
||||
fi |
||||
done |
||||
done |
||||
|
||||
# good ole systemd |
||||
mkdir -p /sys/fs/cgroup/systemd |
||||
mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd |
||||
mkdir -p /sys/fs/cgroup/systemd/k3s |
||||
|
||||
rm /tmp/cgroups |
||||
} |
||||
|
||||
mketc() |
||||
{ |
||||
mkdir -p /etc |
||||
cp -rf usr/etc/* /etc/ |
||||
for i in /.root/usr/lib/os-release /.root/etc/os-release; do |
||||
if [ -e $i ]; then |
||||
cp -f $i /etc/os-release |
||||
fi |
||||
done |
||||
|
||||
if [ -e /.root/etc/machine-id ]; then |
||||
cp -f /.root/etc/machine-id /etc/machine-id |
||||
fi |
||||
|
||||
hostname > /etc/hostname |
||||
|
||||
cat > /etc/hosts << EOF |
||||
127.0.0.1 localhost $NODE_NAME $(hostname) |
||||
::1 localhost ip6-localhost ip6-loopback |
||||
ff02::1 ip6-allnodes |
||||
ff02::2 ip6-allrouters |
||||
EOF |
||||
|
||||
cat > /etc/resolv.conf << EOF |
||||
nameserver 1.1.1.1 |
||||
EOF |
||||
} |
||||
|
||||
nodename() |
||||
{ |
||||
if [ ! -e $K3S_DATA_DIR/id ]; then |
||||
echo $RANDOM > $K3S_DATA_DIR/id |
||||
fi |
||||
export NODE_NAME="$(hostname | cut -f1 -d.)-$(<$K3S_DATA_DIR/id)" |
||||
} |
||||
|
||||
layout |
||||
nodename |
||||
mketc |
||||
sysfs |
||||
cgroups |
||||
|
||||
umount -l .root |
||||
rmdir .root |
||||
|
||||
if [ "$1" = "--" ]; then |
||||
shift 1 |
||||
exec "$@" |
||||
fi |
||||
|
||||
exec env -i -- \ |
||||
HOME=/root \ |
||||
NODE_NAME=$NODE_NAME \ |
||||
PATH=/sbin:/bin \ |
||||
K3S_DATA_DIR=$K3S_DATA_DIR \ |
||||
K3S_NODE_IP=$K3S_NODE_IP \ |
||||
K3S_TOKEN=$K3S_TOKEN \ |
||||
K3S_URL=$K3S_URL \ |
||||
agent |
@ -0,0 +1,71 @@
|
||||
//go:generate go run types/codegen/cleanup/main.go
|
||||
//go:generate go run types/codegen/main.go
|
||||
|
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
"os" |
||||
"path/filepath" |
||||
|
||||
"github.com/docker/docker/pkg/reexec" |
||||
"github.com/rancher/rio/cli/cmd/agent" |
||||
"github.com/rancher/rio/cli/cmd/kubectl" |
||||
"github.com/rancher/rio/cli/cmd/server" |
||||
"github.com/rancher/rio/cli/pkg/builder" |
||||
"github.com/rancher/rio/version" |
||||
"github.com/sirupsen/logrus" |
||||
"github.com/urfave/cli" |
||||
|
||||
_ "github.com/rancher/rio/pkg/kubectl" |
||||
) |
||||
|
||||
var ( |
||||
appName = filepath.Base(os.Args[0]) |
||||
debug bool |
||||
) |
||||
|
||||
func main() { |
||||
old := os.Args[0] |
||||
os.Args[0] = filepath.Base(os.Args[0]) |
||||
if reexec.Init() { |
||||
return |
||||
} |
||||
os.Args[0] = old |
||||
|
||||
app := cli.NewApp() |
||||
app.Name = appName |
||||
app.Usage = "Kubernetes, but small and simple" |
||||
app.Version = version.Version |
||||
cli.VersionPrinter = func(c *cli.Context) { |
||||
fmt.Printf("%s version %s\n", app.Name, app.Version) |
||||
} |
||||
app.Flags = []cli.Flag{ |
||||
cli.BoolFlag{ |
||||
Name: "debug", |
||||
Usage: "Turn on debug logs", |
||||
Destination: &debug, |
||||
}, |
||||
} |
||||
|
||||
app.Commands = []cli.Command{ |
||||
server.ServerCommand, |
||||
builder.Command(&agent.Agent{}, |
||||
"Run node agent", |
||||
appName+" agent [OPTIONS]", |
||||
""), |
||||
|
||||
kubectl.NewKubectlCommand(), |
||||
} |
||||
app.Before = func(ctx *cli.Context) error { |
||||
if debug { |
||||
logrus.SetLevel(logrus.DebugLevel) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
err := app.Run(os.Args) |
||||
if err != nil { |
||||
logrus.Fatal(err) |
||||
} |
||||
} |
@ -0,0 +1,5 @@
|
||||
FROM alpine:3.8 |
||||
RUN apk -U --no-cache add ca-certificates |
||||
|
||||
COPY rio / |
||||
WORKDIR /var/lib/rancher/rio |
@ -0,0 +1,12 @@
|
||||
package tls |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
v1 "github.com/rancher/rio/types/apis/k3s.cattle.io/v1" |
||||
) |
||||
|
||||
func Register(ctx context.Context) error { |
||||
clients := v1.ClientsFrom(ctx) |
||||
clients.ListenerConfig.OnChange(ctx) |
||||
} |
@ -0,0 +1,98 @@
|
||||
package agent |
||||
|
||||
import ( |
||||
"context" |
||||
"math/rand" |
||||
"time" |
||||
|
||||
"github.com/rancher/rio/pkg/daemons/config" |
||||
|
||||
"github.com/sirupsen/logrus" |
||||
"k8s.io/apiserver/pkg/util/logs" |
||||
app2 "k8s.io/kubernetes/cmd/kube-proxy/app" |
||||
"k8s.io/kubernetes/cmd/kubelet/app" |
||||
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
|
||||
_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
|
||||
) |
||||
|
||||
func Agent(config *config.Agent) error { |
||||
rand.Seed(time.Now().UTC().UnixNano()) |
||||
|
||||
prepare(config) |
||||
|
||||
kubelet(config) |
||||
kubeProxy(config) |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func prepare(config *config.Agent) { |
||||
if config.CNIBinDir == "" { |
||||
config.CNIBinDir = "/opt/cni/bin" |
||||
} |
||||
if config.CNIConfDir == "" { |
||||
config.CNIConfDir = "/etc/cni/net.d" |
||||
} |
||||
} |
||||
|
||||
func kubeProxy(config *config.Agent) { |
||||
args := []string{ |
||||
"--proxy-mode", "iptables", |
||||
"--healthz-bind-address", "127.0.0.1", |
||||
"--kubeconfig", config.KubeConfig, |
||||
"--cluster-cidr", config.ClusterCIDR.String(), |
||||
} |
||||
args = append(args, config.ExtraKubeletArgs...) |
||||
|
||||
command := app2.NewProxyCommand() |
||||
command.SetArgs(args) |
||||
go func() { |
||||
err := command.Execute() |
||||
logrus.Fatalf("kube-proxy exited: %v", err) |
||||
}() |
||||
} |
||||
|
||||
func kubelet(config *config.Agent) { |
||||
command := app.NewKubeletCommand(context.Background().Done()) |
||||
logs.InitLogs() |
||||
defer logs.FlushLogs() |
||||
|
||||
args := []string{ |
||||
"--healthz-bind-address", "127.0.0.1", |
||||
"--read-only-port", "0", |
||||
"--allow-privileged=true", |
||||
"--cluster-domain", "cluster.local", |
||||
"--kubeconfig", config.KubeConfig, |
||||
"--eviction-hard", "imagefs.available<5%,nodefs.available<5%", |
||||
"--eviction-minimum-reclaim", "imagefs.available=10%,nodefs.available=10%", |
||||
"--feature-gates=MountPropagation=true", |
||||
"--node-ip", config.NodeIP, |
||||
"--fail-swap-on=false", |
||||
"--cgroup-root", "/k3s", |
||||
"--cgroup-driver", "cgroupfs", |
||||
"--cni-conf-dir", config.CNIConfDir, |
||||
"--cni-bin-dir", config.CNIBinDir, |
||||
} |
||||
if len(config.ClusterDNS) > 0 { |
||||
args = append(args, "--cluster-dns", config.ClusterDNS.String()) |
||||
} |
||||
if config.RuntimeSocket != "" { |
||||
args = append(args, "--container-runtime-endpoint", config.RuntimeSocket) |
||||
} |
||||
if config.ListenAddress != "" { |
||||
args = append(args, "--address", config.ListenAddress) |
||||
} |
||||
if config.CACertPath != "" { |
||||
args = append(args, "--anonymous-auth=false", "--client-ca-file", config.CACertPath) |
||||
} |
||||
if config.NodeName != "" { |
||||
args = append(args, "--hostname-override", config.NodeName) |
||||
} |
||||
args = append(args, config.ExtraKubeletArgs...) |
||||
|
||||
command.SetArgs(args) |
||||
|
||||
go func() { |
||||
logrus.Fatalf("kubelet exited: %v", command.Execute()) |
||||
}() |
||||
} |
@ -0,0 +1,74 @@
|
||||
package config |
||||
|
||||
import ( |
||||
"crypto/tls" |
||||
"net" |
||||
"net/http" |
||||
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator" |
||||
) |
||||
|
||||
type Node struct { |
||||
Docker bool |
||||
NoFlannel bool |
||||
NoCoreDNS bool |
||||
LocalAddress string |
||||
AgentConfig Agent |
||||
CACerts []byte |
||||
ServerAddress string |
||||
Certificate *tls.Certificate |
||||
} |
||||
|
||||
type Agent struct { |
||||
NodeName string |
||||
ClusterCIDR net.IPNet |
||||
ClusterDNS net.IP |
||||
KubeConfig string |
||||
NodeIP string |
||||
RuntimeSocket string |
||||
ListenAddress string |
||||
CACertPath string |
||||
CNIBinDir string |
||||
CNIConfDir string |
||||
ExtraKubeletArgs []string |
||||
ExtraKubeProxyArgs []string |
||||
} |
||||
|
||||
type Control struct { |
||||
AdvertisePort int |
||||
ListenPort int |
||||
ClusterIPRange *net.IPNet |
||||
ServiceIPRange *net.IPNet |
||||
DataDir string |
||||
ETCDEndpoints []string |
||||
ETCDKeyFile string |
||||
ETCDCertFile string |
||||
ETCDCAFile string |
||||
NoScheduler bool |
||||
ExtraAPIArgs []string |
||||
ExtraControllerArgs []string |
||||
ExtraSchedulerAPIArgs []string |
||||
NodeConfig Node |
||||
|
||||
Runtime *ControlRuntime `json:"-"` |
||||
} |
||||
|
||||
type ControlRuntime struct { |
||||
TLSCert string |
||||
TLSKey string |
||||
TLSCA string |
||||
TLSCAKey string |
||||
TokenCA string |
||||
TokenCAKey string |
||||
ServiceKey string |
||||
PasswdFile string |
||||
KubeConfigSystem string |
||||
|
||||
NodeCert string |
||||
NodeKey string |
||||
ClientToken string |
||||
NodeToken string |
||||
Handler http.Handler |
||||
Tunnel http.Handler |
||||
Authenticator authenticator.Request |
||||
} |
@ -0,0 +1,560 @@
|
||||
package control |
||||
|
||||
import ( |
||||
"context" |
||||
cryptorand "crypto/rand" |
||||
"crypto/rsa" |
||||
"crypto/x509" |
||||
"encoding/base64" |
||||
"encoding/csv" |
||||
"encoding/hex" |
||||
"fmt" |
||||
"html/template" |
||||
"io" |
||||
"io/ioutil" |
||||
"math/rand" |
||||
"net" |
||||
"net/http" |
||||
"os" |
||||
"path" |
||||
"path/filepath" |
||||
"strconv" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/rancher/rio/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" |
||||
"k8s.io/kubernetes/cmd/kube-apiserver/app" |
||||
cmapp "k8s.io/kubernetes/cmd/kube-controller-manager/app" |
||||
sapp "k8s.io/kubernetes/cmd/kube-scheduler/app" |
||||
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
|
||||
"k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes" |
||||
"k8s.io/kubernetes/pkg/master" |
||||
_ "k8s.io/kubernetes/pkg/util/reflector/prometheus" // for reflector metric registration
|
||||
_ "k8s.io/kubernetes/pkg/util/workqueue/prometheus" // for workqueue metric registration
|
||||
_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
|
||||
) |
||||
|
||||
var ( |
||||
localhostIP = net.ParseIP("127.0.0.1") |
||||
kubeconfigTemplate = template.Must(template.New("kubeconfig").Parse(`apiVersion: v1 |
||||
clusters: |
||||
- cluster: |
||||
server: {{.URL}} |
||||
certificate-authority-data: {{.CACert}} |
||||
name: local |
||||
contexts: |
||||
- context: |
||||
cluster: local |
||||
namespace: default |
||||
user: user |
||||
name: Default |
||||
current-context: Default |
||||
kind: Config |
||||
preferences: {} |
||||
users: |
||||
- name: user |
||||
user: |
||||
username: {{.User}} |
||||
password: {{.Password}} |
||||
`)) |
||||
) |
||||
|
||||
func Server(ctx context.Context, cfg *config.Control) error { |
||||
rand.Seed(time.Now().UTC().UnixNano()) |
||||
|
||||
runtime := &config.ControlRuntime{} |
||||
cfg.Runtime = runtime |
||||
|
||||
if err := prepare(cfg, runtime); err != nil { |
||||
return err |
||||
} |
||||
|
||||
cfg.Runtime.Tunnel = setupTunnel() |
||||
|
||||
auth, handler, err := apiServer(ctx, cfg, runtime) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
runtime.Handler = handler |
||||
runtime.Authenticator = auth |
||||
|
||||
if !cfg.NoScheduler { |
||||
scheduler(cfg, runtime) |
||||
} |
||||
|
||||
controllerManager(cfg, runtime) |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func controllerManager(config *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", config.ClusterIPRange.String(), |
||||
"--root-ca-file", runtime.TokenCA, |
||||
"--port", "0", |
||||
"--secure-port", "0", |
||||
} |
||||
args = append(args, config.ExtraControllerArgs...) |
||||
command := cmapp.NewControllerManagerCommand() |
||||
command.SetArgs(args) |
||||
|
||||
go func() { |
||||
logrus.Infof("Running kube-controller-manager %s", argString(args)) |
||||
logrus.Fatalf("controller-manager exited: %v", command.Execute()) |
||||
}() |
||||
} |
||||
|
||||
type argString []string |
||||
|
||||
func (a argString) String() string { |
||||
b := strings.Builder{} |
||||
for _, s := range a { |
||||
if b.Len() > 0 { |
||||
b.WriteString(" ") |
||||
} |
||||
b.WriteString(s) |
||||
} |
||||
return b.String() |
||||
} |
||||
|
||||
func scheduler(config *config.Control, runtime *config.ControlRuntime) { |
||||
args := []string{ |
||||
"--kubeconfig", runtime.KubeConfigSystem, |
||||
"--port", "0", |
||||
"--secure-port", "0", |
||||
} |
||||
args = append(args, config.ExtraSchedulerAPIArgs...) |
||||
command := sapp.NewSchedulerCommand() |
||||
command.SetArgs(args) |
||||
|
||||
go func() { |
||||
logrus.Infof("Running kube-scheduler %s", argString(args)) |
||||
logrus.Fatalf("scheduler exited: %v", command.Execute()) |
||||
}() |
||||
} |
||||
|
||||
func apiServer(ctx context.Context, config *config.Control, runtime *config.ControlRuntime) (authenticator.Request, http.Handler, error) { |
||||
var args []string |
||||
|
||||
if len(config.ETCDEndpoints) > 0 { |
||||
args = append(args, "--storage-backend", "etcd3") |
||||
args = append(args, "--etcd-servers", strings.Join(config.ETCDEndpoints, ",")) |
||||
if config.ETCDKeyFile != "" { |
||||
args = append(args, "--etcd-keyfile", config.ETCDKeyFile) |
||||
} |
||||
if config.ETCDCAFile != "" { |
||||
args = append(args, "--etcd-cafile", config.ETCDCAFile) |
||||
} |
||||
if config.ETCDCertFile != "" { |
||||
args = append(args, "--etcd-certfile", config.ETCDCertFile) |
||||
} |
||||
} |
||||
|
||||
args = append(args, "--allow-privileged=true") |
||||
args = append(args, "--authorization-mode", strings.Join([]string{modes.ModeNode, modes.ModeRBAC}, ",")) |
||||
args = append(args, "--service-account-signing-key-file", runtime.ServiceKey) |
||||
args = append(args, "--service-cluster-ip-range", config.ServiceIPRange.String()) |
||||
args = append(args, "--advertise-port", strconv.Itoa(config.AdvertisePort)) |
||||
args = append(args, "--advertise-address", localhostIP.String()) |
||||
args = append(args, "--insecure-port", "0") |
||||
args = append(args, "--secure-port", strconv.Itoa(config.ListenPort)) |
||||
args = append(args, "--bind-address", localhostIP.String()) |
||||
args = append(args, "--tls-cert-file", runtime.TLSCert) |
||||
args = append(args, "--tls-private-key-file", runtime.TLSKey) |
||||
args = append(args, "--service-account-key-file", runtime.ServiceKey) |
||||
args = append(args, "--service-account-issuer", "k3s") |
||||
args = append(args, "--api-audiences", "unknown") |
||||
args = append(args, "--basic-auth-file", runtime.PasswdFile) |
||||
//args = append(args, "--kubelet-client-certificate", runtime.NodeCert)
|
||||
//args = append(args, "--kubelet-client-key", runtime.NodeKey)
|
||||
|
||||
args = append(args, config.ExtraAPIArgs...) |
||||
command := app.NewAPIServerCommand(ctx.Done()) |
||||
command.SetArgs(args) |
||||
|
||||
go func() { |
||||
logrus.Infof("Running kube-apiserver %s", argString(args)) |
||||
logrus.Fatalf("apiserver exited: %v", command.Execute()) |
||||
}() |
||||
|
||||
startupConfig := <-app.StartupConfig |
||||
|
||||
return startupConfig.Authenticator, startupConfig.Handler, nil |
||||
} |
||||
|
||||
func defaults(config *config.Control) { |
||||
if config.ClusterIPRange == nil { |
||||
_, clusterIPNet, _ := net.ParseCIDR("10.42.0.0/16") |
||||
config.ClusterIPRange = clusterIPNet |
||||
} |
||||
|
||||
if config.ServiceIPRange == nil { |
||||
_, serviceIPNet, _ := net.ParseCIDR("10.43.0.0/16") |
||||
config.ServiceIPRange = serviceIPNet |
||||
} |
||||
|
||||
if config.AdvertisePort == 0 { |
||||
config.AdvertisePort = 6445 |
||||
} |
||||
|
||||
if config.ListenPort == 0 { |
||||
config.ListenPort = 6444 |
||||
} |
||||
|
||||
if config.DataDir == "" { |
||||
config.DataDir = "./management-state" |
||||
} |
||||
} |
||||
|
||||
func prepare(config *config.Control, runtime *config.ControlRuntime) error { |
||||
var err error |
||||
|
||||
defaults(config) |
||||
|
||||
if _, err := os.Stat(config.DataDir); os.IsNotExist(err) { |
||||
if err := os.MkdirAll(config.DataDir, 0700); err != nil { |
||||
return err |
||||
} |
||||
} else if err != nil { |
||||
return err |
||||
} |
||||
|
||||
config.DataDir, err = filepath.Abs(config.DataDir) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
os.MkdirAll(path.Join(config.DataDir, "tls"), 0700) |
||||
os.MkdirAll(path.Join(config.DataDir, "cred"), 0700) |
||||
|
||||
name := "localhost" |
||||
runtime.TLSCert = path.Join(config.DataDir, "tls", name+".crt") |
||||
runtime.TLSKey = path.Join(config.DataDir, "tls", name+".key") |
||||
runtime.TLSCA = path.Join(config.DataDir, "tls", "ca.crt") |
||||
runtime.TLSCAKey = path.Join(config.DataDir, "tls", "ca.key") |
||||
runtime.TokenCA = path.Join(config.DataDir, "tls", "token-ca.crt") |
||||
runtime.TokenCAKey = path.Join(config.DataDir, "tls", "token-ca.key") |
||||
runtime.ServiceKey = path.Join(config.DataDir, "tls", "service.key") |
||||
runtime.PasswdFile = path.Join(config.DataDir, "cred", "passwd") |
||||
runtime.KubeConfigSystem = path.Join(config.DataDir, "cred", "kubeconfig-system.yaml") |
||||
runtime.NodeKey = path.Join(config.DataDir, "tls", "token-node.key") |
||||
runtime.NodeCert = path.Join(config.DataDir, "tls", "token-node.crt") |
||||
|
||||
regen := false |
||||
if _, err := os.Stat(runtime.TLSCA); err != nil { |
||||
regen = true |
||||
if err := genCA(runtime); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
|
||||
if err := genServiceAccount(runtime); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := genTLS(regen, config, runtime); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := genTokenTLS(config, runtime); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := genUsers(config, runtime); err != nil { |
||||
return err |
||||
} |
||||
|
||||
return readTokens(runtime) |
||||
} |
||||
|
||||
func readTokens(runtime *config.ControlRuntime) error { |
||||
f, err := os.Open(runtime.PasswdFile) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
reader := csv.NewReader(f) |
||||
reader.FieldsPerRecord = -1 |
||||
|
||||
for { |
||||
record, err := reader.Read() |
||||
if err == io.EOF { |
||||
break |
||||
} |
||||
if err != nil { |
||||
return err |
||||
} |
||||
if len(record) < 2 { |
||||
continue |
||||
} |
||||
|
||||
switch record[1] { |
||||
case "node": |
||||
runtime.NodeToken = "node:" + record[0] |
||||
case "admin": |
||||
runtime.ClientToken = "admin:" + record[0] |
||||
} |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func genUsers(config *config.Control, runtime *config.ControlRuntime) error { |
||||
if s, err := os.Stat(runtime.PasswdFile); err == nil && s.Size() > 0 { |
||||
return nil |
||||
} |
||||
|
||||
adminToken, err := getToken() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
systemToken, err := getToken() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
nodeToken, err := getToken() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
passwd := fmt.Sprintf(`%s,admin,admin,system:masters |
||||
%s,system,system,system:masters |
||||
%s,node,node,system:masters |
||||
`, adminToken, systemToken, nodeToken) |
||||
|
||||
caCertBytes, err := ioutil.ReadFile(runtime.TLSCA) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
caCert := base64.StdEncoding.EncodeToString(caCertBytes) |
||||
|
||||
if err := kubeConfig(runtime.KubeConfigSystem, fmt.Sprintf("https://localhost:%d", config.ListenPort), caCert, |
||||
"system", systemToken); err != nil { |
||||
return err |
||||
} |
||||
|
||||
return ioutil.WriteFile(runtime.PasswdFile, []byte(passwd), 0600) |
||||
} |
||||
|
||||
func getToken() (string, error) { |
||||
token := make([]byte, 16, 16) |
||||
_, err := cryptorand.Read(token) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
return hex.EncodeToString(token), err |
||||
} |
||||
|
||||
func genTokenTLS(config *config.Control, runtime *config.ControlRuntime) error { |
||||
regen := false |
||||
if _, err := os.Stat(runtime.TokenCA); err != nil { |
||||
regen = true |
||||
if err := genTokenCA(runtime); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
|
||||
_, apiServerServiceIP, err := master.DefaultServiceIPRange(*config.ServiceIPRange) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
cfg := certutil.Config{ |
||||
CommonName: "kubernetes", |
||||
AltNames: certutil.AltNames{ |
||||
DNSNames: []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes", "localhost"}, |
||||
IPs: []net.IP{net.ParseIP("127.0.0.1"), apiServerServiceIP}, |
||||
}, |
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, |
||||
} |
||||
|
||||
if _, err := os.Stat(runtime.NodeCert); err == nil && !regen { |
||||
return nil |
||||
} |
||||
|
||||
caKeyBytes, err := ioutil.ReadFile(runtime.TokenCAKey) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
caBytes, err := ioutil.ReadFile(runtime.TokenCA) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
caKey, err := certutil.ParsePrivateKeyPEM(caKeyBytes) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
caCert, err := certutil.ParseCertsPEM(caBytes) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
key, err := certutil.NewPrivateKey() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
cert, err := certutil.NewSignedCert(cfg, key, caCert[0], caKey.(*rsa.PrivateKey)) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := certutil.WriteKey(runtime.NodeKey, certutil.EncodePrivateKeyPEM(key)); err != nil { |
||||
return err |
||||
} |
||||
|
||||
return certutil.WriteCert(runtime.NodeCert, append(certutil.EncodeCertPEM(cert), certutil.EncodeCertPEM(caCert[0])...)) |
||||
} |
||||
|
||||
func genTLS(regen bool, config *config.Control, runtime *config.ControlRuntime) error { |
||||
if !regen { |
||||
_, certErr := os.Stat(runtime.TLSCert) |
||||
_, keyErr := os.Stat(runtime.TLSKey) |
||||
if certErr == nil && keyErr == nil { |
||||
return nil |
||||
} |
||||
} |
||||
|
||||
_, apiServerServiceIP, err := master.DefaultServiceIPRange(*config.ServiceIPRange) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
cfg := certutil.Config{ |
||||
CommonName: "localhost", |
||||
AltNames: certutil.AltNames{ |
||||
DNSNames: []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes", "localhost"}, |
||||
IPs: []net.IP{apiServerServiceIP, localhostIP}, |
||||
}, |
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, |
||||
} |
||||
|
||||
caKeyBytes, err := ioutil.ReadFile(runtime.TLSCAKey) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
caBytes, err := ioutil.ReadFile(runtime.TLSCA) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
caKey, err := certutil.ParsePrivateKeyPEM(caKeyBytes) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
caCert, err := certutil.ParseCertsPEM(caBytes) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
key, err := certutil.NewPrivateKey() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
cert, err := certutil.NewSignedCert(cfg, key, caCert[0], caKey.(*rsa.PrivateKey)) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := certutil.WriteKey(runtime.TLSKey, certutil.EncodePrivateKeyPEM(key)); err != nil { |
||||
return err |
||||
} |
||||
|
||||
return certutil.WriteCert(runtime.TLSCert, append(certutil.EncodeCertPEM(cert), certutil.EncodeCertPEM(caCert[0])...)) |
||||
} |
||||
|
||||
func genServiceAccount(runtime *config.ControlRuntime) error { |
||||
_, keyErr := os.Stat(runtime.ServiceKey) |
||||
if keyErr == nil { |
||||
return nil |
||||
} |
||||
|
||||
key, err := certutil.NewPrivateKey() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
return certutil.WriteKey(runtime.ServiceKey, certutil.EncodePrivateKeyPEM(key)) |
||||
} |
||||
|
||||
func genTokenCA(runtime *config.ControlRuntime) error { |
||||
caKey, err := certutil.NewPrivateKey() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
cfg := certutil.Config{ |
||||
CommonName: fmt.Sprintf("%s-ca@%d", "k3s-token", time.Now().Unix()), |
||||
} |
||||
|
||||
cert, err := certutil.NewSelfSignedCACert(cfg, caKey) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := certutil.WriteKey(runtime.TokenCAKey, certutil.EncodePrivateKeyPEM(caKey)); err != nil { |
||||
return err |
||||
} |
||||
|
||||
return certutil.WriteCert(runtime.TokenCA, certutil.EncodeCertPEM(cert)) |
||||
} |
||||
|
||||
func genCA(runtime *config.ControlRuntime) error { |
||||
caKey, err := certutil.NewPrivateKey() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
cfg := certutil.Config{ |
||||
CommonName: fmt.Sprintf("%s-ca@%d", "k3s", time.Now().Unix()), |
||||
} |
||||
|
||||
cert, err := certutil.NewSelfSignedCACert(cfg, caKey) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := certutil.WriteKey(runtime.TLSCAKey, certutil.EncodePrivateKeyPEM(caKey)); err != nil { |
||||
return err |
||||
} |
||||
|
||||
return certutil.WriteCert(runtime.TLSCA, certutil.EncodeCertPEM(cert)) |
||||
} |
||||
|
||||
func kubeConfig(dest, url, cert, user, password string) error { |
||||
data := struct { |
||||
URL string |
||||
CACert string |
||||
User string |
||||
Password string |
||||
}{ |
||||
URL: url, |
||||
CACert: cert, |
||||
User: user, |
||||
Password: password, |
||||
} |
||||
|
||||
output, err := os.Create(dest) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer output.Close() |
||||
|
||||
return kubeconfigTemplate.Execute(output, &data) |
||||
} |
@ -0,0 +1,50 @@
|
||||
package control |
||||
|
||||
import ( |
||||
"context" |
||||
"net" |
||||
"net/http" |
||||
"time" |
||||
|
||||
"github.com/rancher/norman/pkg/kv" |
||||
"github.com/rancher/norman/pkg/remotedialer" |
||||
utilnet "k8s.io/apimachinery/pkg/util/net" |
||||
"k8s.io/apiserver/pkg/endpoints/request" |
||||
"k8s.io/kubernetes/cmd/kube-apiserver/app" |
||||
) |
||||
|
||||
func setupTunnel() http.Handler { |
||||
tunnelServer := remotedialer.New(authorizer, remotedialer.DefaultErrorWriter) |
||||
setupProxyDialer(tunnelServer) |
||||
return tunnelServer |
||||
} |
||||
|
||||
func setupProxyDialer(tunnelServer *remotedialer.Server) { |
||||
app.DefaultProxyDialerFn = utilnet.DialFunc(func(_ context.Context, network, address string) (net.Conn, error) { |
||||
_, port, _ := net.SplitHostPort(address) |
||||
addr := "127.0.0.1" |
||||
if port != "" { |
||||
addr += ":" + port |
||||
} |
||||
nodeName, _ := kv.Split(address, ":") |
||||
return tunnelServer.Dial(nodeName, 15*time.Second, "tcp", addr) |
||||
}) |
||||
} |
||||
|
||||
func authorizer(req *http.Request) (clientKey string, authed bool, err error) { |
||||
user, ok := request.UserFrom(req.Context()) |
||||
if !ok { |
||||
return "", false, nil |
||||
} |
||||
|
||||
if user.GetName() != "node" { |
||||
return "", false, nil |
||||
} |
||||
|
||||
nodeName := req.Header.Get("X-K3s-NodeName") |
||||
if nodeName == "" { |
||||
return "", false, nil |
||||
} |
||||
|
||||
return nodeName, true, nil |
||||
} |
@ -0,0 +1,254 @@
|
||||
package enterchroot |
||||
|
||||
import ( |
||||
"fmt" |
||||
"io" |
||||
"io/ioutil" |
||||
"os" |
||||
"os/exec" |
||||
"path/filepath" |
||||
"strings" |
||||
"syscall" |
||||
"time" |
||||
|
||||
"github.com/docker/docker/pkg/mount" |
||||
"github.com/docker/docker/pkg/reexec" |
||||
"github.com/pkg/errors" |
||||
"github.com/sirupsen/logrus" |
||||
losetup "gopkg.in/freddierice/go-losetup.v1" |
||||
) |
||||
|
||||
const ( |
||||
magic = "_SQMAGIC_" |
||||
) |
||||
|
||||
var ( |
||||
symlinks = []string{"lib", "bin", "sbin", "lib64"} |
||||
) |
||||
|
||||
func init() { |
||||
reexec.Register("enter-root", enter) |
||||
} |
||||
|
||||
func enter() { |
||||
if os.Getenv("ENTER_DEBUG") == "true" { |
||||
logrus.SetLevel(logrus.DebugLevel) |
||||
} |
||||
|
||||
logrus.Debug("Running bootstrap") |
||||
err := run(os.Getenv("ENTER_DATA")) |
||||
if err != nil { |
||||
logrus.Fatal(err) |
||||
} |
||||
} |
||||
|
||||
func Mount(dataDir string, stdout, stderr io.Writer, args []string) error { |
||||
if logrus.GetLevel() >= logrus.DebugLevel { |
||||
os.Setenv("ENTER_DEBUG", "true") |
||||
} |
||||
|
||||
root, offset, err := findRoot() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
os.Setenv("ENTER_DATA", dataDir) |
||||
os.Setenv("ENTER_ROOT", root) |
||||
|
||||
logrus.Debugf("Using data [%s] root [%s]", dataDir, root) |
||||
|
||||
stat, err := os.Stat(root) |
||||
if err != nil { |
||||
return fmt.Errorf("failed to find %s: %v", root, err) |
||||
} |
||||
|
||||
if !stat.IsDir() { |
||||
logrus.Debugf("Attaching file [%s] offset [%d]", root, offset) |
||||
dev, err := losetup.Attach(root, offset, true) |
||||
if err != nil { |
||||
return errors.Wrap(err, "creating loopback device") |
||||
} |
||||
defer dev.Detach() |
||||
os.Setenv("ENTER_DEVICE", dev.Path()) |
||||
|
||||
go func() { |
||||
// Assume that after 3 seconds loop back device has been mounted
|
||||
time.Sleep(3 * time.Second) |
||||
info, err := dev.GetInfo() |
||||
if err != nil { |
||||
return |
||||
} |
||||
|
||||
info.Flags |= losetup.FlagsAutoClear |
||||
err = dev.SetInfo(info) |
||||
if err != nil { |
||||
return |
||||
} |
||||
}() |
||||
} |
||||
|
||||
logrus.Debugf("Running enter-root %v", args) |
||||
cmd := &exec.Cmd{ |
||||
Path: reexec.Self(), |
||||
Args: append([]string{"enter-root"}, args...), |
||||
SysProcAttr: &syscall.SysProcAttr{ |
||||
//Cloneflags: syscall.CLONE_NEWPID | syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC,
|
||||
Unshareflags: syscall.CLONE_NEWNS, |
||||
Pdeathsig: syscall.SIGKILL, |
||||
}, |
||||
Stdout: stdout, |
||||
Stdin: os.Stdin, |
||||
Stderr: stderr, |
||||
Env: os.Environ(), |
||||
} |
||||
return cmd.Run() |
||||
} |
||||
|
||||
func findRoot() (string, uint64, error) { |
||||
root := os.Getenv("ENTER_ROOT") |
||||
if root != "" { |
||||
return root, 0, nil |
||||
} |
||||
|
||||
for _, suffix := range []string{".root", ".squashfs"} { |
||||
test := os.Args[0] + suffix |
||||
if _, err := os.Stat(test); err == nil { |
||||
return test, 0, nil |
||||
} |
||||
} |
||||
|
||||
return inFile() |
||||
} |
||||
|
||||
func inFile() (string, uint64, error) { |
||||
f, err := os.Open(reexec.Self()) |
||||
if err != nil { |
||||
return "", 0, err |
||||
} |
||||
defer f.Close() |
||||
|
||||
buf := make([]byte, 8192) |
||||
test := []byte(strings.ToLower(magic)) |
||||
testLength := len(test) |
||||
offset := uint64(0) |
||||
found := 0 |
||||
|
||||
for { |
||||
n, err := f.Read(buf) |
||||
if err == io.EOF && n == 0 { |
||||
break |
||||
} else if err != nil { |
||||
return "", 0, err |
||||
} |
||||
|
||||
for _, b := range buf[:n] { |
||||
if b == test[found] { |
||||
found++ |
||||
if found == testLength { |
||||
return reexec.Self(), offset + 1, nil |
||||
} |
||||
} else { |
||||
found = 0 |
||||
} |
||||
offset++ |
||||
} |
||||
} |
||||
|
||||
return "", 0, fmt.Errorf("failed to find image in file %s", os.Args[0]) |
||||
} |
||||
|
||||
func run(data string) error { |
||||
os.MkdirAll(data, 0755) |
||||
|
||||
if err := mount.Mount("tmpfs", data, "tmpfs", ""); err != nil { |
||||
return errors.Wrapf(err, "remounting data %s", data) |
||||
} |
||||
|
||||
root := os.Getenv("ENTER_ROOT") |
||||
device := os.Getenv("ENTER_DEVICE") |
||||
|
||||
logrus.Debugf("Using root %s %s", root, device) |
||||
|
||||
usr := filepath.Join(data, "usr") |
||||
dotRoot := filepath.Join(data, ".root") |
||||
|
||||
for _, d := range []string{usr, dotRoot} { |
||||
if err := os.MkdirAll(d, 0755); err != nil { |
||||
return fmt.Errorf("failed to make dir %s: %v", data, err) |
||||
} |
||||
} |
||||
|
||||
if device == "" { |
||||
logrus.Debugf("Bind mounting %s to %s", root, usr) |
||||
if err := mount.Mount(root, usr, "none", "bind"); err != nil { |
||||
return fmt.Errorf("failed to bind mount") |
||||
} |
||||
} else { |
||||
logrus.Debugf("Mounting squashfs %s to %s", device, usr) |
||||
squashErr := checkSquashfs() |
||||
if err := mount.Mount(device, usr, "squashfs", "ro"); err != nil { |
||||
err = errors.Wrap(err, "mounting squashfs") |
||||
if squashErr != nil { |
||||
err = errors.Wrap(err, squashErr.Error()) |
||||
} |
||||
return err |
||||
} |
||||
} |
||||
|
||||
if err := os.Chdir(data); err != nil { |
||||
return err |
||||
} |
||||
|
||||
for _, p := range symlinks { |
||||
if _, err := os.Lstat(p); os.IsNotExist(err) { |
||||
if err := os.Symlink(filepath.Join("usr", p), p); err != nil { |
||||
return errors.Wrapf(err, "failed to symlink %s", p) |
||||
} |
||||
} |
||||
} |
||||
|
||||
logrus.Debugf("pivoting to . .root") |
||||
if err := syscall.PivotRoot(".", ".root"); err != nil { |
||||
return errors.Wrap(err, "pivot_root failed") |
||||
} |
||||
|
||||
if err := mount.ForceMount("", ".", "none", "rprivate"); err != nil { |
||||
return errors.Wrapf(err, "making . private %s", data) |
||||
} |
||||
|
||||
if err := syscall.Chroot("/"); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := os.Chdir("/"); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if _, err := os.Stat("/usr/init"); err != nil { |
||||
return errors.Wrap(err, "failed to find /usr/init") |
||||
} |
||||
|
||||
return syscall.Exec("/usr/init", os.Args, os.Environ()) |
||||
} |
||||
|
||||
func checkSquashfs() error { |
||||
if !inProcFS() { |
||||
exec.Command("modprobe", "squashfs").Run() |
||||
} |
||||
|
||||
if !inProcFS() { |
||||
return errors.New("This kernel does not support squashfs, please enable. " + |
||||
"On Fedora you may need to run \"dnf install kernel-modules-$(uname -r)\"") |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func inProcFS() bool { |
||||
bytes, err := ioutil.ReadFile("/proc/filesystems") |
||||
if err != nil { |
||||
logrus.Errorf("Failed to read /proc/filesystems: %v", err) |
||||
return false |
||||
} |
||||
return strings.Contains(string(bytes), "squashfs") |
||||
} |
@ -0,0 +1,52 @@
|
||||
package kubectl |
||||
|
||||
import ( |
||||
goflag "flag" |
||||
"fmt" |
||||
"math/rand" |
||||
"os" |
||||
"time" |
||||
|
||||
"github.com/docker/docker/pkg/reexec" |
||||
"github.com/rancher/rio/pkg/server" |
||||
"github.com/spf13/pflag" |
||||
utilflag "k8s.io/apiserver/pkg/util/flag" |
||||
"k8s.io/apiserver/pkg/util/logs" |
||||
"k8s.io/kubernetes/pkg/kubectl/cmd" |
||||
) |
||||
|
||||
func init() { |
||||
reexec.Register("kubectl", Main) |
||||
} |
||||
|
||||
func Main() { |
||||
kubenv := os.Getenv("KUBECONFIG") |
||||
if kubenv == "" { |
||||
config, err := server.HomeKubeConfig() |
||||
if _, serr := os.Stat(config); err == nil && serr == nil { |
||||
os.Setenv("KUBECONFIG", config) |
||||
} |
||||
} |
||||
|
||||
main() |
||||
} |
||||
|
||||
func main() { |
||||
rand.Seed(time.Now().UnixNano()) |
||||
|
||||
command := cmd.NewDefaultKubectlCommand() |
||||
|
||||
// TODO: once we switch everything over to Cobra commands, we can go back to calling
|
||||
// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
|
||||
// normalize func and add the go flag set by hand.
|
||||
pflag.CommandLine.SetNormalizeFunc(utilflag.WordSepNormalizeFunc) |
||||
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine) |
||||
// utilflag.InitFlags()
|
||||
logs.InitLogs() |
||||
defer logs.FlushLogs() |
||||
|
||||
if err := command.Execute(); err != nil { |
||||
fmt.Fprintf(os.Stderr, "%v\n", err) |
||||
os.Exit(1) |
||||
} |
||||
} |
@ -0,0 +1,41 @@
|
||||
package server |
||||
|
||||
import ( |
||||
"net/http" |
||||
|
||||
"github.com/gorilla/mux" |
||||
"github.com/rancher/rio/pkg/daemons/config" |
||||
"github.com/sirupsen/logrus" |
||||
"k8s.io/apiserver/pkg/endpoints/request" |
||||
) |
||||
|
||||
func doAuth(serverConfig *config.Control, next http.Handler, rw http.ResponseWriter, req *http.Request) { |
||||
if serverConfig == nil || serverConfig.Runtime.Authenticator == nil { |
||||
next.ServeHTTP(rw, req) |
||||
return |
||||
} |
||||
|
||||
resp, ok, err := serverConfig.Runtime.Authenticator.AuthenticateRequest(req) |
||||
if err != nil { |
||||
logrus.Errorf("failed to authenticate request: %v", err) |
||||
rw.WriteHeader(http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
if !ok || resp.User.GetName() != "node" { |
||||
rw.WriteHeader(http.StatusUnauthorized) |
||||
return |
||||
} |
||||
|
||||
ctx := request.WithUser(req.Context(), resp.User) |
||||
req = req.WithContext(ctx) |
||||
next.ServeHTTP(rw, req) |
||||
} |
||||
|
||||
func authMiddleware(serverConfig *config.Control) mux.MiddlewareFunc { |
||||
return func(next http.Handler) http.Handler { |
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { |
||||
doAuth(serverConfig, next, rw, req) |
||||
}) |
||||
} |
||||
} |
@ -0,0 +1,72 @@
|
||||
package server |
||||
|
||||
import ( |
||||
"net/http" |
||||
|
||||
"github.com/rancher/rio/pkg/daemons/config" |
||||
|
||||
"k8s.io/apimachinery/pkg/util/json" |
||||
|
||||
"github.com/gorilla/mux" |
||||
) |
||||
|
||||
type CACertsGetter func() (string, error) |
||||
|
||||
func router(serverConfig *config.Control, tunnel http.Handler, cacertsGetter CACertsGetter) http.Handler { |
||||
authed := mux.NewRouter() |
||||
authed.Use(authMiddleware(serverConfig)) |
||||
authed.NotFoundHandler = serverConfig.Runtime.Handler |
||||
authed.Path("/v1-k3s/connect").Handler(tunnel) |
||||
authed.Path("/v1-k3s/node.crt").Handler(nodeCrt(serverConfig)) |
||||
authed.Path("/v1-k3s/node.key").Handler(nodeKey(serverConfig)) |
||||
authed.Path("/v1-k3s/config").Handler(configHandler(serverConfig)) |
||||
|
||||
router := mux.NewRouter() |
||||
router.NotFoundHandler = authed |
||||
router.Path("/cacerts").Handler(cacerts(cacertsGetter)) |
||||
|
||||
return router |
||||
} |
||||
|
||||
func cacerts(getter CACertsGetter) http.Handler { |
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { |
||||
content, err := getter() |
||||
if err != nil { |
||||
resp.WriteHeader(http.StatusInternalServerError) |
||||
resp.Write([]byte(err.Error())) |
||||
} |
||||
resp.Header().Set("content-type", "text/plain") |
||||
resp.Write([]byte(content)) |
||||
}) |
||||
} |
||||
|
||||
func nodeCrt(server *config.Control) http.Handler { |
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { |
||||
if req.TLS == nil { |
||||
resp.WriteHeader(http.StatusNotFound) |
||||
return |
||||
} |
||||
http.ServeFile(resp, req, server.Runtime.NodeCert) |
||||
}) |
||||
} |
||||
|
||||
func nodeKey(server *config.Control) http.Handler { |
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { |
||||
if req.TLS == nil { |
||||
resp.WriteHeader(http.StatusNotFound) |
||||
return |
||||
} |
||||
http.ServeFile(resp, req, server.Runtime.NodeKey) |
||||
}) |
||||
} |
||||
|
||||
func configHandler(server *config.Control) http.Handler { |
||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { |
||||
if req.TLS == nil { |
||||
resp.WriteHeader(http.StatusNotFound) |
||||
return |
||||
} |
||||
resp.Header().Set("content-type", "application/json") |
||||
json.NewEncoder(resp).Encode(server) |
||||
}) |
||||
} |
@ -0,0 +1,230 @@
|
||||
package server |
||||
|
||||
import ( |
||||
"context" |
||||
"crypto/sha256" |
||||
"encoding/hex" |
||||
"fmt" |
||||
"io/ioutil" |
||||
"os" |
||||
"path/filepath" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/pkg/errors" |
||||
"github.com/rancher/norman" |
||||
"github.com/rancher/norman/pkg/clientaccess" |
||||
"github.com/rancher/norman/pkg/dynamiclistener" |
||||
"github.com/rancher/norman/pkg/resolvehome" |
||||
"github.com/rancher/norman/types" |
||||
"github.com/rancher/rio/pkg/daemons/config" |
||||
"github.com/rancher/rio/pkg/daemons/control" |
||||
"github.com/rancher/rio/pkg/tls" |
||||
v1 "github.com/rancher/rio/types/apis/k3s.cattle.io/v1" |
||||
"github.com/sirupsen/logrus" |
||||
"k8s.io/apimachinery/pkg/util/net" |
||||
) |
||||
|
||||
func resolveDataDir(dataDir string) (string, error) { |
||||
if dataDir == "" { |
||||
if os.Getuid() == 0 { |
||||
dataDir = "/var/lib/rancher/k3s" |
||||
} else { |
||||
dataDir = "${HOME}/.rancher/k3s" |
||||
} |
||||
} |
||||
|
||||
dataDir = filepath.Join(dataDir, "server") |
||||
return resolvehome.Resolve(dataDir) |
||||
} |
||||
|
||||
func StartServer(ctx context.Context, config *Config) error { |
||||
if err := setupDataDirAndChdir(&config.ControlConfig); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := control.Server(ctx, &config.ControlConfig); err != nil { |
||||
return errors.Wrap(err, "starting kubernetes") |
||||
} |
||||
|
||||
certs, err := startNorman(ctx, &config.TLSConfig, &config.ControlConfig) |
||||
if err != nil { |
||||
return errors.Wrap(err, "starting tls server") |
||||
} |
||||
|
||||
printTokens(certs, config.ControlConfig.NodeConfig.AgentConfig.NodeIP, &config.TLSConfig, &config.ControlConfig) |
||||
|
||||
writeKubeConfig(certs, &config.TLSConfig, &config.ControlConfig) |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func startNorman(ctx context.Context, tlsConfig *dynamiclistener.UserConfig, config *config.Control) (string, error) { |
||||
var ( |
||||
err error |
||||
tlsServer dynamiclistener.ServerInterface |
||||
) |
||||
|
||||
tlsConfig.Handler = router(config, config.Runtime.Tunnel, func() (string, error) { |
||||
if tlsServer == nil { |
||||
return "", nil |
||||
} |
||||
return tlsServer.CACert() |
||||
}) |
||||
|
||||
normanConfig := &norman.Config{ |
||||
Name: "k3s", |
||||
KubeConfig: config.Runtime.KubeConfigSystem, |
||||
Clients: []norman.ClientFactory{ |
||||
v1.Factory, |
||||
}, |
||||
Schemas: []*types.Schemas{ |
||||
v1.Schemas, |
||||
}, |
||||
CRDs: map[*types.APIVersion][]string{ |
||||
&v1.APIVersion: { |
||||
v1.ListenerConfigGroupVersionKind.Kind, |
||||
}, |
||||
}, |
||||
IgnoredKubeConfigEnv: true, |
||||
GlobalSetup: func(ctx context.Context) (context.Context, error) { |
||||
tlsServer, err = tls.NewServer(ctx, v1.ClientsFrom(ctx).ListenerConfig, *tlsConfig) |
||||
return ctx, err |
||||
}, |
||||
} |
||||
|
||||
ctx, _, err = normanConfig.Build(ctx, nil) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
for { |
||||
certs, err := tlsServer.CACert() |
||||
if err != nil { |
||||
logrus.Infof("waiting to generate CA certs") |
||||
time.Sleep(time.Second) |
||||
continue |
||||
} |
||||
return certs, nil |
||||
} |
||||
} |
||||
|
||||
func HomeKubeConfig() (string, error) { |
||||
return resolvehome.Resolve("${HOME}/.kube/k3s.yaml") |
||||
} |
||||
|
||||
func printTokens(certs, advertiseIP string, tlsConfig *dynamiclistener.UserConfig, config *config.Control) { |
||||
var ( |
||||
nodeFile string |
||||
) |
||||
|
||||
if advertiseIP == "" { |
||||
advertiseIP = "localhost" |
||||
} |
||||
|
||||
if len(config.Runtime.NodeToken) > 0 { |
||||
p := filepath.Join(config.DataDir, "node-token") |
||||
if err := writeToken(config.Runtime.NodeToken, p, certs); err == nil { |
||||
logrus.Infof("Node token is available at %s", p) |
||||
nodeFile = p |
||||
} |
||||
} |
||||
|
||||
if len(nodeFile) > 0 { |
||||
printToken(tlsConfig.HTTPSPort, advertiseIP, "To join node to cluster:", nodeFile, "agent") |
||||
} |
||||
|
||||
} |
||||
|
||||
func writeKubeConfig(certs string, tlsConfig *dynamiclistener.UserConfig, config *config.Control) { |
||||
clientToken := FormatToken(config.Runtime.ClientToken, certs) |
||||
url := fmt.Sprintf("https://localhost:%d", tlsConfig.HTTPSPort) |
||||
kubeConfig, err := HomeKubeConfig() |
||||
def := true |
||||
if err != nil { |
||||
kubeConfig = filepath.Join(config.DataDir, "kubeconfig-k3s.yaml") |
||||
def = false |
||||
} |
||||
|
||||
if err = clientaccess.AgentAccessInfoToKubeConfig(kubeConfig, url, clientToken); err != nil { |
||||
logrus.Errorf("Failed to generate kubeconfig: %v", err) |
||||
} |
||||
|
||||
logrus.Infof("Wrote kubeconfig %s", kubeConfig) |
||||
if def { |
||||
logrus.Infof("Run: %s kubectl", filepath.Base(os.Args[0])) |
||||
} |
||||
} |
||||
|
||||
func setupDataDirAndChdir(config *config.Control) error { |
||||
var ( |
||||
err error |
||||
) |
||||
|
||||
config.DataDir, err = resolveDataDir(config.DataDir) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
dataDir := config.DataDir |
||||
|
||||
if err := os.MkdirAll(dataDir, 0700); err != nil { |
||||
return errors.Wrapf(err, "can not mkdir %s", dataDir) |
||||
} |
||||
|
||||
if err := os.Chdir(dataDir); err != nil { |
||||
return errors.Wrapf(err, "can not chdir %s", dataDir) |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func readTokenFile(file string) (string, error) { |
||||
content, err := ioutil.ReadFile(file) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
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) |
||||
} |
||||
|
||||
ip := advertiseIP |
||||
if ip == "" { |
||||
hostIP, err := net.ChooseHostInterface() |
||||
if err != nil { |
||||
logrus.Error(err) |
||||
} |
||||
ip = hostIP.String() |
||||
} |
||||
|
||||
logrus.Infof("%s rio %s -s https://%s:%d -t %s", prefix, cmd, ip, httpsPort, token) |
||||
} |
||||
|
||||
func FormatToken(token string, certs string) string { |
||||
if len(token) == 0 { |
||||
return token |
||||
} |
||||
|
||||
prefix := "K10" |
||||
if len(certs) > 0 { |
||||
digest := sha256.Sum256([]byte(certs)) |
||||
prefix = "K10" + hex.EncodeToString(digest[:]) + "::" |
||||
} |
||||
|
||||
return prefix + token |
||||
} |
||||
|
||||
func writeToken(token, file, certs string) error { |
||||
if len(token) == 0 { |
||||
return nil |
||||
} |
||||
|
||||
token = FormatToken(token, certs) |
||||
return ioutil.WriteFile(file, []byte(token+"\n"), 0600) |
||||
} |
@ -0,0 +1,12 @@
|
||||
package server |
||||
|
||||
import ( |
||||
"github.com/rancher/norman/pkg/dynamiclistener" |
||||
"github.com/rancher/rio/pkg/daemons/config" |
||||
) |
||||
|
||||
type Config struct { |
||||
DisableAgent bool |
||||
TLSConfig dynamiclistener.UserConfig |
||||
ControlConfig config.Control |
||||
} |
@ -0,0 +1,79 @@
|
||||
package tls |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/rancher/norman/pkg/dynamiclistener" |
||||
v1 "github.com/rancher/rio/types/apis/k3s.cattle.io/v1" |
||||
"k8s.io/apimachinery/pkg/api/errors" |
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||
"k8s.io/apimachinery/pkg/runtime" |
||||
) |
||||
|
||||
const ( |
||||
ns = "kube-system" |
||||
name = "tls-config" |
||||
) |
||||
|
||||
func NewServer(ctx context.Context, listenerClient v1.ListenerConfigClient, config dynamiclistener.UserConfig) (dynamiclistener.ServerInterface, error) { |
||||
storage := &listenerConfigStorage{ |
||||
client: listenerClient, |
||||
cache: listenerClient.Cache(), |
||||
} |
||||
|
||||
server, err := dynamiclistener.NewServer(storage, config) |
||||
listenerClient.OnChange(ctx, "listen-config", func(obj *v1.ListenerConfig) (runtime.Object, error) { |
||||
return obj, server.Update(fromStorage(obj)) |
||||
}) |
||||
|
||||
return server, err |
||||
} |
||||
|
||||
type listenerConfigStorage struct { |
||||
cache v1.ListenerConfigClientCache |
||||
client v1.ListenerConfigClient |
||||
} |
||||
|
||||
func (l *listenerConfigStorage) Set(config *dynamiclistener.ListenerStatus) (*dynamiclistener.ListenerStatus, error) { |
||||
if config == nil { |
||||
return nil, nil |
||||
} |
||||
|
||||
obj, err := l.cache.Get(ns, name) |
||||
if errors.IsNotFound(err) { |
||||
ls := v1.NewListenerConfig(ns, name, v1.ListenerConfig{ |
||||
Status: *config, |
||||
}) |
||||
|
||||
ls, err := l.client.Create(ls) |
||||
return fromStorage(ls), err |
||||
} else if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
obj = obj.DeepCopy() |
||||
obj.ResourceVersion = config.Revision |
||||
obj.Status = *config |
||||
obj.Status.Revision = "" |
||||
|
||||
obj, err = l.client.Update(obj) |
||||
return fromStorage(obj), err |
||||
} |
||||
|
||||
func (l *listenerConfigStorage) Get() (*dynamiclistener.ListenerStatus, error) { |
||||
obj, err := l.cache.Get(ns, name) |
||||
if errors.IsNotFound(err) { |
||||
obj, err = l.client.Get(ns, name, metav1.GetOptions{}) |
||||
} |
||||
return fromStorage(obj), err |
||||
} |
||||
|
||||
func fromStorage(obj *v1.ListenerConfig) *dynamiclistener.ListenerStatus { |
||||
if obj == nil { |
||||
return nil |
||||
} |
||||
|
||||
copy := obj.DeepCopy() |
||||
copy.Status.Revision = obj.ResourceVersion |
||||
return ©.Status |
||||
} |
@ -0,0 +1,31 @@
|
||||
#!/bin/bash |
||||
set -e |
||||
|
||||
source $(dirname $0)/version |
||||
|
||||
cd $(dirname $0)/.. |
||||
|
||||
LDFLAGS="-X github.com/rancher/rio/version.Version=$VERSION -w -s" |
||||
STATIC="-extldflags -static" |
||||
STATIC_SQLITE="-extldflags '-static -lm -ldl -lz -lpthread'" |
||||
|
||||
cross() |
||||
{ |
||||
echo Building windows CLI |
||||
GOOS=windows GOARCH=amd64 go build -ldflags "$LDFLAGS" -o bin/rio-windows ./cli/main.go |
||||
echo Building mac CLI |
||||
GOOS=darwin GOARCH=amd64 go build -ldflags "$LDFLAGS" -o bin/rio-darwin ./cli/main.go |
||||
} |
||||
|
||||
mkdir -p bin |
||||
|
||||
if [ -n "$CROSS" ]; then |
||||
cross |
||||
fi |
||||
|
||||
echo Building incluster |
||||
GOOS=linux GOARCH=amd64 |
||||
CGO_ENABLED=0 go build -ldflags "$LDFLAGS $STATIC" -o bin/rio-incluster |
||||
|
||||
echo Building cli full |
||||
CGO_ENABLED=1 go build -tags "static_build libsqlite3 k8s ctr no_etcd netgo osusergo" -ldflags "$LDFLAGS $STATIC_SQLITE" -o bin/rio-full ./cli/main.go |
@ -0,0 +1,9 @@
|
||||
#!/bin/bash |
||||
set -e |
||||
|
||||
cd $(dirname $0) |
||||
|
||||
./validate |
||||
./build |
||||
./package |
||||
./test |
@ -0,0 +1,14 @@
|
||||
#!/bin/bash |
||||
set -e |
||||
|
||||
cd $(dirname $0)/../bin |
||||
|
||||
# Prime sudo |
||||
sudo echo Compiling CLI |
||||
go build -tags "k8s no_etcd" -o rio-agent ../cli/main.go |
||||
|
||||
echo Building image and agent |
||||
../image/build |
||||
|
||||
echo Running |
||||
exec sudo ENTER_ROOT=../image/main.squashfs ./rio-agent --debug agent -s https://localhost:7443 -t $(<${HOME}/.rancher/rio/server/node-token) |
@ -0,0 +1,7 @@
|
||||
#!/bin/bash |
||||
set -e |
||||
|
||||
cd $(dirname $0)/../bin |
||||
|
||||
echo Running |
||||
go run -tags "k8s no_etcd" ../cli/main.go --debug server --disable-controllers --disable-agent |
@ -0,0 +1,6 @@
|
||||
#!/bin/bash |
||||
set -e |
||||
|
||||
cd $(dirname $0)/../bin |
||||
|
||||
rio login -s https://localhost:5443 -t $(<${HOME}/.rancher/rio/server/client-token) |
@ -0,0 +1,7 @@
|
||||
#!/bin/bash |
||||
set -e |
||||
|
||||
cd $(dirname $0)/../bin |
||||
|
||||
echo Running |
||||
go run -tags k3s ../cli/main.go --debug server --disable-agent |
@ -0,0 +1,11 @@
|
||||
#!/bin/bash |
||||
set -e |
||||
|
||||
mkdir -p bin dist |
||||
if [ -e ./scripts/$1 ]; then |
||||
./scripts/"$@" |
||||
else |
||||
exec "$@" |
||||
fi |
||||
|
||||
chown -R $DAPPER_UID:$DAPPER_GID . |
@ -0,0 +1,8 @@
|
||||
#!/bin/bash |
||||
set -e |
||||
|
||||
cd $(dirname $0) |
||||
|
||||
./package-cli |
||||
./package-image |
||||
./package-tar |
@ -0,0 +1,11 @@
|
||||
#!/bin/bash |
||||
set -e |
||||
|
||||
source $(dirname $0)/version |
||||
|
||||
cd $(dirname $0)/../image |
||||
./build |
||||
|
||||
cp ../bin/rio-full ../bin/rio |
||||
echo -n "_sqmagic_" >> ../bin/rio |
||||
cat main.squashfs >> ../bin/rio |
@ -0,0 +1,17 @@
|
||||
#!/bin/bash |
||||
set -e |
||||
|
||||
source $(dirname $0)/version |
||||
|
||||
cd $(dirname $0)/../package |
||||
|
||||
TAG=${TAG:-${VERSION}${SUFFIX}} |
||||
REPO=${REPO:-rancher} |
||||
|
||||
cp ../bin/rio ./rio |
||||
|
||||
IMAGE=${REPO}/rio:${TAG} |
||||
docker build -t ${IMAGE} . |
||||
mkdir -p ../dist |
||||
echo ${IMAGE} > ../dist/images |
||||
echo Built ${IMAGE} |
@ -0,0 +1,17 @@
|
||||
#!/bin/bash |
||||
|
||||
cd $(dirname $0)/.. |
||||
|
||||
. ./scripts/version |
||||
|
||||
mkdir -p dist/artifacts |
||||
|
||||
tar cvzf dist/artifacts/rio-${VERSION}-linux-amd64.tar.gz -h bin/rio --xform='s!^bin!rio-'${VERSION}'-linux-amd64!' |
||||
tar cvzf dist/artifacts/rio-${VERSION}-darwin.tar.gz bin/rio-darwin --xform='s!.*!rio-'${VERSION}'-darwin/rio!' |
||||
|
||||
W=rio-${VERSION}-windows |
||||
mkdir -p $W |
||||
trap "rm -rf $W" EXIT |
||||
|
||||
cp -f bin/rio-windows $W/rio.exe |
||||
zip dist/artifacts/rio-${VERSION}-windows.zip $W/rio.exe |
@ -0,0 +1,16 @@
|
||||
#!/bin/bash |
||||
|
||||
if [ ! -d $1/staging/src/k8s.io ]; then |
||||
echo Kubernetes source not found at $1 |
||||
exit 1 |
||||
fi |
||||
|
||||
cd $(dirname $0)/../vendor/k8s.io |
||||
for i in $1/staging/src/k8s.io/*; do |
||||
rm -rf $(basename $i) |
||||
ln -s $i . |
||||
done |
||||
rm -rf kubernetes |
||||
mkdir -p kubernetes |
||||
cd kubernetes |
||||
ln -s $1/{cmd,pkg,plugin,third_party} . |
@ -0,0 +1,50 @@
|
||||
#!/bin/bash |
||||
set -e |
||||
|
||||
cd $(dirname $0)/.. |
||||
|
||||
echo Running tests |
||||
|
||||
mkdir -p ./build |
||||
|
||||
mkdir -p /var/lib/rancher/rio/agent |
||||
mount -t tmpfs none /var/lib/rancher/rio/agent |
||||
|
||||
./bin/rio server --disable-agent | grep -v level=info > /var/lib/rancher/rio/agent/agent.log 2>&1 & |
||||
|
||||
for i in {1..120}; do |
||||
if [ ! -e /var/lib/rancher/rio/server/node-token ]; then |
||||
sleep .5 |
||||
continue |
||||
fi |
||||
|
||||
curl -sf http://localhost:7080/healthz >/dev/null && break |
||||
sleep .5 |
||||
done |
||||
curl -sf http://localhost:7080/healthz >/dev/null |
||||
|
||||
rm -rf ./image/root |
||||
unsquashfs -d ./image/root ./image/main.squashfs |
||||
ENTER_ROOT=$(pwd)/image/root ./bin/rio --debug agent -s https://localhost:7443 -t $(</var/lib/rancher/rio/server/node-token) >>/var/lib/rancher/rio/agent/agent.log 2>&1 & |
||||
|
||||
export PATH=$(pwd)/bin:$PATH |
||||
|
||||
rio login -s https://localhost:7443 -t /var/lib/rancher/rio/server/client-token |
||||
|
||||
echo Waiting for istio/istio-gateway |
||||
rio --project=rio-system wait istio/istio-gateway |
||||
rio --project=rio-system ps |
||||
rio --project=rio-system ps -c |
||||
|
||||
chmod +x ./tests/init-nfs.bash |
||||
./tests/init-nfs.bash |
||||
export RUN_NFS_TEST=true |
||||
|
||||
cd ./tests |
||||
tox -- -n $(nproc) |
||||
cd .. |
||||
|
||||
bats -r ./tests || { |
||||
tail -n 100 /var/lib/rancher/rio/agent/agent.log |
||||
exit 1 |
||||
} |
@ -0,0 +1,29 @@
|
||||
#!/bin/bash |
||||
set -e |
||||
|
||||
cd $(dirname $0)/.. |
||||
|
||||
echo Running validation |
||||
|
||||
if grep -r '^[[:space:]]*\[\[.*]][[:space:]]*$' tests; then |
||||
echo "Add \"|| false\" to bats tests in any place you use [[ ... ]]" |
||||
exit 1 |
||||
fi |
||||
|
||||
PACKAGES="$(go list ./...)" |
||||
|
||||
echo Running: go vet |
||||
go vet ${PACKAGES} |
||||
echo Running: gometalinter |
||||
for i in ${PACKAGES}; do |
||||
if [ -n "$(gometalinter $i | \ |
||||
grep -v 'should have comment.*or be unexported' | \ |
||||
grep -v 'cli/cmd.*don.t use underscores in Go name' | \ |
||||
grep -v 'cli/cmd.*should be DNS' | \ |
||||
tee /dev/stderr)" ]; then |
||||
failed=true |
||||
fi |
||||
done |
||||
test -z "$failed" |
||||
echo Running: go fmt |
||||
test -z "$(go fmt ${PACKAGES} | tee /dev/stderr)" |
@ -0,0 +1,18 @@
|
||||
#!/bin/bash |
||||
|
||||
if [ -n "$(git status --porcelain --untracked-files=no)" ]; then |
||||
DIRTY="-dirty" |
||||
fi |
||||
|
||||
COMMIT=$(git rev-parse --short HEAD) |
||||
GIT_TAG=${DRONE_TAG:-$(git tag -l --contains HEAD | head -n 1)} |
||||
|
||||
if [[ -z "$DIRTY" && -n "$GIT_TAG" ]]; then |
||||
VERSION=$GIT_TAG |
||||
else |
||||
VERSION="${COMMIT}${DIRTY}" |
||||
fi |
||||
|
||||
if [ -z "$ARCH" ]; then |
||||
ARCH=amd64 |
||||
fi |
@ -0,0 +1,246 @@
|
||||
package: package=github.com/rancher/rio |
||||
import: |
||||
- package: github.com/coreos/flannel |
||||
version: 39af3d7e46f2efa156644e247bdcf3b5bc5f1394 |
||||
- package: github.com/gorilla/mux |
||||
version: v1.6.2 |
||||
- package: github.com/gorilla/websocket |
||||
version: v1.2.0 |
||||
- package: github.com/mattn/go-sqlite3 |
||||
version: v1.9.0 |
||||
- package: github.com/natefinch/lumberjack |
||||
version: aee4629129445bbdfb69aa565537dcfa16544311 |
||||
- package: github.com/rancher/norman |
||||
version: 5726ebfba191eef161af9638e85bf4fcaa58e008 |
||||
repo: https://github.com/ibuildthecloud/norman.git |
||||
- package: github.com/urfave/cli |
||||
version: 8e01ec4cd3e2d84ab2fe90d8210528ffbb06d8ff |
||||
- package: golang.org/x/crypto |
||||
version: a49355c7e3f8fe157a85be2f77e6e269a0f89602 |
||||
- package: golang.org/x/sync |
||||
version: 450f422ab23cf9881c94e2db30cac0eb1b7cf80c |
||||
- package: gopkg.in/freddierice/go-losetup.v1 |
||||
version: fc9adea44124401d8bfef3a97eaf61b5d44cc2c6 |
||||
- package: k8s.io/kubernetes |
||||
version: a1d7d1b140f43b6503311ffc1dd80017c553bf8e |
||||
repo: file:///home/darren/src/kuberlite/.git |
||||
transitive: true |
||||
staging: true |
||||
- package: github.com/pborman/uuid |
||||
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4 |
||||
- package: github.com/prometheus/client_model |
||||
version: model-0.0.2-12-gfa8ad6fec33561 |
||||
- package: github.com/prometheus/common |
||||
version: 13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207 |
||||
- package: github.com/golang/protobuf |
||||
version: v1.1.0 |
||||
- package: golang.org/x/sys |
||||
version: 95c6576299259db960f6c5b9b69ea52422860fce |
||||
- package: github.com/ugorji/go |
||||
version: bdcc60b419d136a85cdf2e7cbcac34b3f1cd6e57 |
||||
- package: github.com/vishvananda/netns |
||||
version: be1fbeda19366dea804f00efff2dd73a1642fdcc |
||||
- package: gopkg.in/natefinch/lumberjack.v2 |
||||
version: v1.0-16-g20b71e5b60d756 |
||||
- package: vbom.ml/util |
||||
version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394 |
||||
- package: github.com/exponent-io/jsonpath |
||||
version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5 |
||||
- package: github.com/google/certificate-transparency-go |
||||
version: v1.0.21 |
||||
- package: github.com/coreos/go-semver |
||||
version: v0.2.0-9-ge214231b295a8e |
||||
- package: github.com/docker/spdystream |
||||
version: 449fdfce4d962303d702fec724ef0ad181c92528 |
||||
- package: github.com/renstrom/dedent |
||||
version: v1.0.0-3-g020d11c3b9c0c7 |
||||
- package: golang.org/x/text |
||||
version: b19bf474d317b857955b12035d2c5acb57ce8b01 |
||||
- package: github.com/container-storage-interface/spec |
||||
version: v1.0.0 |
||||
- package: github.com/evanphx/json-patch |
||||
version: v4.0.0-3-g36442dbdb58521 |
||||
- package: github.com/sigma/go-inotify |
||||
version: c87b6cf5033d2c6486046f045eeebdc3d910fd38 |
||||
- package: github.com/blang/semver |
||||
version: v3.5.0 |
||||
- package: github.com/docker/libnetwork |
||||
version: v0.8.0-dev.2-1265-ga9cd636e378982 |
||||
- package: github.com/fatih/camelcase |
||||
version: f6a740d52f961c60348ebb109adde9f4635d7540 |
||||
- package: github.com/prometheus/client_golang |
||||
version: v0.8.0-83-ge7e903064f5e9e |
||||
- package: github.com/shurcooL/sanitized_anchor_name |
||||
version: 10ef21a441db47d8b13ebcc5fd2310f636973c77 |
||||
- package: github.com/spf13/cobra |
||||
version: v0.0.1-34-gc439c4fa093711 |
||||
- package: github.com/docker/docker |
||||
version: docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8dd8794 |
||||
- package: golang.org/x/net |
||||
version: 0ed95abb35c445290478a5348a7b38bb154135fd |
||||
- package: github.com/json-iterator/go |
||||
version: 1.1.4 |
||||
- package: github.com/opencontainers/runc |
||||
version: v1.0.0-rc5-46-g871ba2e58e2431 |
||||
- package: gopkg.in/inf.v0 |
||||
version: v0.9.0 |
||||
- package: github.com/containerd/containerd |
||||
version: v1.0.2 |
||||
- package: github.com/ghodss/yaml |
||||
version: v1.0.0-4-gc7ce16629ff4cd |
||||
- package: github.com/ibuildthecloud/kvsql |
||||
version: 6bb3d252056655760ed8ca6557d6d5e607b361d2 |
||||
- package: google.golang.org/genproto |
||||
version: 09f6ed296fc66555a25fe4ce95173148778dfa85 |
||||
- package: github.com/Microsoft/hcsshim |
||||
version: v0.6.11 |
||||
- package: google.golang.org/grpc |
||||
version: v1.13.0 |
||||
- package: github.com/gregjones/httpcache |
||||
version: 787624de3eb7bd915c329cba748687a3b22666a6 |
||||
- package: github.com/golang/groupcache |
||||
version: 02826c3e79038b59d737d3b1c0a1d937f71a4433 |
||||
- package: github.com/karrick/godirwalk |
||||
version: v1.7.5 |
||||
- package: github.com/mattn/go-shellwords |
||||
version: v1.0.3-20-gf8471b0a71ded0 |
||||
- package: github.com/google/gofuzz |
||||
version: 44d81051d367757e1c7c6a5a86423ece9afcf63c |
||||
- package: github.com/modern-go/concurrent |
||||
version: 1.0.3 |
||||
- package: github.com/google/cadvisor |
||||
version: 25bec0e2ace4846e5caaaf69991046c6f44c4bac |
||||
repo: https://github.com/ibuildthecloud/cadvisor.git |
||||
- package: sigs.k8s.io/yaml |
||||
version: v1.1.0 |
||||
- package: bitbucket.org/ww/goautoneg |
||||
version: a547fc61f48d567d5b4ec6f8aee5573d8efce11d |
||||
repo: https://github.com/rancher/goautoneg.git |
||||
- package: github.com/beorn7/perks |
||||
version: 3ac7bf7a47d159a033b107610db8a1b6575507a4 |
||||
- package: github.com/sirupsen/logrus |
||||
version: v1.0.3-11-g89742aefa4b206 |
||||
- package: gopkg.in/square/go-jose.v2 |
||||
version: v2.1.6-4-g89060dee6a84df |
||||
- package: k8s.io/utils |
||||
version: 66066c83e385e385ccc3c964b44fd7dcd413d0ed |
||||
- package: github.com/daviddengcn/go-colortext |
||||
version: 511bcaf42ccd42c38aba7427b6673277bf19e2a1 |
||||
- package: github.com/prometheus/procfs |
||||
version: 65c1f6f8f0fc1e2185eb9863a3bc751496404259 |
||||
- package: golang.org/x/tools |
||||
version: 2382e3994d48b1d22acc2c86bcad0a2aff028e32 |
||||
- package: github.com/jteeuwen/go-bindata |
||||
version: v3.0.7-72-ga0ff2567cfb709 |
||||
- package: github.com/modern-go/reflect2 |
||||
version: v1.0.1 |
||||
- package: golang.org/x/time |
||||
version: f51c12702a4d776e4c1fa9b0fabab841babae631 |
||||
- package: k8s.io/gengo |
||||
version: 51747d6e00da1fc578d5a333a93bb2abcbce7a95 |
||||
- package: github.com/euank/go-kmsg-parser |
||||
version: v2.0.0 |
||||
- package: github.com/chai2010/gettext-go |
||||
version: c6fed771bfd517099caf0f7a961671fa8ed08723 |
||||
- package: github.com/davecgh/go-spew |
||||
version: v1.1.0-1-g782f4967f2dc45 |
||||
- package: github.com/docker/distribution |
||||
version: v2.6.0-rc.1-209-gedc3ab29cdff86 |
||||
- package: github.com/docker/go-units |
||||
version: v0.3.1-11-g9e638d38cf6977 |
||||
- package: github.com/mindprince/gonvml |
||||
version: fee913ce8fb235edf54739d259ca0ecc226c7b8a |
||||
- package: github.com/MakeNowJust/heredoc |
||||
version: bb23615498cded5e105af4ce27de75b089cbe851 |
||||
- package: github.com/syndtr/gocapability |
||||
version: e7cb7fa329f456b3855136a2642b197bad7366ba |
||||
- package: k8s.io/klog |
||||
version: 8139d8cb77af419532b33dfa7dd09fbc5f1d344f |
||||
- package: github.com/emicklei/go-restful |
||||
version: 2.2.0-4-gff4f55a206334e |
||||
- package: github.com/google/btree |
||||
version: 7d79101e329e5a3adf994758c578dab82b90c017 |
||||
- package: github.com/Azure/go-ansiterm |
||||
version: d6e3b3328b783f23731bc4d058875b0371ff8109 |
||||
- package: github.com/containerd/console |
||||
version: 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e |
||||
- package: github.com/pkg/errors |
||||
version: v0.8.0 |
||||
- package: github.com/googleapis/gnostic |
||||
version: 0c5108395e2debce0d731cf0287ddf7242066aba |
||||
- package: github.com/imdario/mergo |
||||
version: v0.3.5 |
||||
- package: github.com/robfig/cron |
||||
version: v1-53-gdf38d32658d878 |
||||
- package: github.com/JeffAshton/win_pdh |
||||
version: 76bb4ee9f0ab50f77826f2a2ee7fb9d3880d6ec2 |
||||
- package: github.com/armon/circbuf |
||||
version: bbbad097214e2918d8543d5201d12bfd7bca254d |
||||
- package: k8s.io/heapster |
||||
version: v1.2.0-beta.1 |
||||
- package: github.com/matttproud/golang_protobuf_extensions |
||||
version: v1.0.1 |
||||
- package: github.com/mrunalp/fileutils |
||||
version: 4ee1cc9a80582a0c75febdd5cfa779ee4361cbca |
||||
- package: github.com/opencontainers/runtime-spec |
||||
version: v1.0.0 |
||||
- package: github.com/fsnotify/fsnotify |
||||
version: v1.3.1-1-gf12c6236fe7b5c |
||||
- package: github.com/mistifyio/go-zfs |
||||
version: v2.1.1-5-g1b4ae6fb4e77b0 |
||||
- package: github.com/russross/blackfriday |
||||
version: v1.4-2-g300106c228d52c |
||||
- package: github.com/inconshreveable/mousetrap |
||||
version: v1.0 |
||||
- package: github.com/vishvananda/netlink |
||||
version: b2de5d10e38ecce8607e6b438b6d174f389a004e |
||||
- package: github.com/mitchellh/go-wordwrap |
||||
version: ad45545899c7b13c020ea92b2072220eefad42b8 |
||||
- package: github.com/peterbourgon/diskv |
||||
version: v2.0.1 |
||||
- package: github.com/Microsoft/go-winio |
||||
version: v0.4.5 |
||||
- package: github.com/cyphar/filepath-securejoin |
||||
version: v0.2.1-1-gae69057f2299fb |
||||
- package: github.com/Nvveen/Gotty |
||||
version: cd527374f1e5bff4938207604a14f2e38a9cf512 |
||||
- package: github.com/containernetworking/cni |
||||
version: v0.6.0 |
||||
- package: github.com/hashicorp/golang-lru |
||||
version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4 |
||||
- package: github.com/jonboulle/clockwork |
||||
version: 72f9bd7c4e0c2a40055ab3d0f09654f730cce982 |
||||
- package: github.com/seccomp/libseccomp-golang |
||||
version: 1b506fc7c24eec5a3693cdcbed40d9c226cfc6a1 |
||||
- package: github.com/coreos/pkg |
||||
version: v4 |
||||
- package: github.com/opencontainers/image-spec |
||||
version: v1.0.0-rc6-12-g372ad780f63454 |
||||
- package: github.com/opencontainers/selinux |
||||
version: v1.0.0-rc1-5-g4a2974bf1ee960 |
||||
- package: github.com/cloudflare/cfssl |
||||
version: 1.3.2-21-g56268a613adfed |
||||
- package: github.com/grpc-ecosystem/go-grpc-prometheus |
||||
version: v1.1-4-g2500245aa6110c |
||||
- package: github.com/miekg/dns |
||||
version: 5d001d020961ae1c184f9f8152fdc73810481677 |
||||
- package: github.com/godbus/dbus |
||||
version: v3 |
||||
- package: github.com/spf13/pflag |
||||
version: v1.0.1 |
||||
- package: github.com/docker/go-connections |
||||
version: v0.3.0 |
||||
- package: golang.org/x/oauth2 |
||||
version: a6bd8cefa1811bd24b86f8902872e4e8225f74c4 |
||||
- package: github.com/gogo/protobuf |
||||
version: v0.5 |
||||
- package: github.com/mxk/go-flowrate |
||||
version: cca7078d478f8520f85629ad7c68962d31ed7682 |
||||
- package: github.com/coreos/go-systemd |
||||
version: v17 |
||||
- package: github.com/opencontainers/go-digest |
||||
version: a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb |
||||
- package: gopkg.in/yaml.v2 |
||||
version: v2.2.1 |
||||
- package: github.com/coreos/etcd |
||||
version: v3.3.10 |
@ -0,0 +1,17 @@
|
||||
package v1 |
||||
|
||||
import ( |
||||
"github.com/rancher/norman/types" |
||||
"github.com/rancher/norman/types/factory" |
||||
) |
||||
|
||||
var ( |
||||
APIVersion = types.APIVersion{ |
||||
Version: "v1", |
||||
Group: "k3s.cattle.io", |
||||
Path: "/v1-k3s", |
||||
} |
||||
|
||||
Schemas = factory.Schemas(&APIVersion). |
||||
MustImport(&APIVersion, ListenerConfig{}) |
||||
) |
@ -0,0 +1,16 @@
|
||||
package v1 |
||||
|
||||
import ( |
||||
"github.com/rancher/norman/pkg/dynamiclistener" |
||||
"github.com/rancher/norman/types" |
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||
) |
||||
|
||||
type ListenerConfig struct { |
||||
types.Namespaced |
||||
|
||||
metav1.TypeMeta `json:",inline"` |
||||
metav1.ObjectMeta `json:"metadata,omitempty"` |
||||
|
||||
Status dynamiclistener.ListenerStatus `json:"status,omitempty"` |
||||
} |
@ -0,0 +1,66 @@
|
||||
package v1 |
||||
|
||||
import ( |
||||
runtime "k8s.io/apimachinery/pkg/runtime" |
||||
) |
||||
|
||||
// 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 |
||||
out.Namespaced = in.Namespaced |
||||
out.TypeMeta = in.TypeMeta |
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) |
||||
in.Status.DeepCopyInto(&out.Status) |
||||
return |
||||
} |
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ListenerConfig.
|
||||
func (in *ListenerConfig) DeepCopy() *ListenerConfig { |
||||
if in == nil { |
||||
return nil |
||||
} |
||||
out := new(ListenerConfig) |
||||
in.DeepCopyInto(out) |
||||
return out |
||||
} |
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ListenerConfig) 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 *ListenerConfigList) DeepCopyInto(out *ListenerConfigList) { |
||||
*out = *in |
||||
out.TypeMeta = in.TypeMeta |
||||
out.ListMeta = in.ListMeta |
||||
if in.Items != nil { |
||||
in, out := &in.Items, &out.Items |
||||
*out = make([]ListenerConfig, len(*in)) |
||||
for i := range *in { |
||||
(*in)[i].DeepCopyInto(&(*out)[i]) |
||||
} |
||||
} |
||||
return |
||||
} |
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ListenerConfigList.
|
||||
func (in *ListenerConfigList) DeepCopy() *ListenerConfigList { |
||||
if in == nil { |
||||
return nil |
||||
} |
||||
out := new(ListenerConfigList) |
||||
in.DeepCopyInto(out) |
||||
return out |
||||
} |
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ListenerConfigList) DeepCopyObject() runtime.Object { |
||||
if c := in.DeepCopy(); c != nil { |
||||
return c |
||||
} |
||||
return nil |
||||
} |
@ -0,0 +1,119 @@
|
||||
package v1 |
||||
|
||||
import ( |
||||
"context" |
||||
"sync" |
||||
|
||||
"github.com/rancher/norman/controller" |
||||
"github.com/rancher/norman/objectclient" |
||||
"github.com/rancher/norman/objectclient/dynamic" |
||||
"github.com/rancher/norman/restwatch" |
||||
"k8s.io/client-go/rest" |
||||
) |
||||
|
||||
type ( |
||||
contextKeyType struct{} |
||||
contextClientsKeyType struct{} |
||||
) |
||||
|
||||
type Interface interface { |
||||
RESTClient() rest.Interface |
||||
controller.Starter |
||||
|
||||
ListenerConfigsGetter |
||||
} |
||||
|
||||
type Clients struct { |
||||
Interface Interface |
||||
|
||||
ListenerConfig ListenerConfigClient |
||||
} |
||||
|
||||
type Client struct { |
||||
sync.Mutex |
||||
restClient rest.Interface |
||||
starters []controller.Starter |
||||
|
||||
listenerConfigControllers map[string]ListenerConfigController |
||||
} |
||||
|
||||
func Factory(ctx context.Context, config rest.Config) (context.Context, controller.Starter, error) { |
||||
c, err := NewForConfig(config) |
||||
if err != nil { |
||||
return ctx, nil, err |
||||
} |
||||
|
||||
cs := NewClientsFromInterface(c) |
||||
|
||||
ctx = context.WithValue(ctx, contextKeyType{}, c) |
||||
ctx = context.WithValue(ctx, contextClientsKeyType{}, cs) |
||||
return ctx, c, nil |
||||
} |
||||
|
||||
func ClientsFrom(ctx context.Context) *Clients { |
||||
return ctx.Value(contextClientsKeyType{}).(*Clients) |
||||
} |
||||
|
||||
func From(ctx context.Context) Interface { |
||||
return ctx.Value(contextKeyType{}).(Interface) |
||||
} |
||||
|
||||
func NewClients(config rest.Config) (*Clients, error) { |
||||
iface, err := NewForConfig(config) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return NewClientsFromInterface(iface), nil |
||||
} |
||||
|
||||
func NewClientsFromInterface(iface Interface) *Clients { |
||||
return &Clients{ |
||||
Interface: iface, |
||||
|
||||
ListenerConfig: &listenerConfigClient2{ |
||||
iface: iface.ListenerConfigs(""), |
||||
}, |
||||
} |
||||
} |
||||
|
||||
func NewForConfig(config rest.Config) (Interface, error) { |
||||
if config.NegotiatedSerializer == nil { |
||||
config.NegotiatedSerializer = dynamic.NegotiatedSerializer |
||||
} |
||||
|
||||
restClient, err := restwatch.UnversionedRESTClientFor(&config) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return &Client{ |
||||
restClient: restClient, |
||||
|
||||
listenerConfigControllers: map[string]ListenerConfigController{}, |
||||
}, nil |
||||
} |
||||
|
||||
func (c *Client) RESTClient() rest.Interface { |
||||
return c.restClient |
||||
} |
||||
|
||||
func (c *Client) Sync(ctx context.Context) error { |
||||
return controller.Sync(ctx, c.starters...) |
||||
} |
||||
|
||||
func (c *Client) Start(ctx context.Context, threadiness int) error { |
||||
return controller.Start(ctx, threadiness, c.starters...) |
||||
} |
||||
|
||||
type ListenerConfigsGetter interface { |
||||
ListenerConfigs(namespace string) ListenerConfigInterface |
||||
} |
||||
|
||||
func (c *Client) ListenerConfigs(namespace string) ListenerConfigInterface { |
||||
objectClient := objectclient.NewObjectClient(namespace, c.restClient, &ListenerConfigResource, ListenerConfigGroupVersionKind, listenerConfigFactory{}) |
||||
return &listenerConfigClient{ |
||||
ns: namespace, |
||||
client: c, |
||||
objectClient: objectClient, |
||||
} |
||||
} |
@ -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 ( |
||||
ListenerConfigGroupVersionKind = schema.GroupVersionKind{ |
||||
Version: Version, |
||||
Group: GroupName, |
||||
Kind: "ListenerConfig", |
||||
} |
||||
ListenerConfigResource = metav1.APIResource{ |
||||
Name: "listenerconfigs", |
||||
SingularName: "listenerconfig", |
||||
Namespaced: true, |
||||
|
||||
Kind: ListenerConfigGroupVersionKind.Kind, |
||||
} |
||||
) |
||||
|
||||
func NewListenerConfig(namespace, name string, obj ListenerConfig) *ListenerConfig { |
||||
obj.APIVersion, obj.Kind = ListenerConfigGroupVersionKind.ToAPIVersionAndKind() |
||||
obj.Name = name |
||||
obj.Namespace = namespace |
||||
return &obj |
||||
} |
||||
|
||||
type ListenerConfigList struct { |
||||
metav1.TypeMeta `json:",inline"` |
||||
metav1.ListMeta `json:"metadata,omitempty"` |
||||
Items []ListenerConfig |
||||
} |
||||
|
||||
type ListenerConfigHandlerFunc func(key string, obj *ListenerConfig) (runtime.Object, error) |
||||
|
||||
type ListenerConfigChangeHandlerFunc func(obj *ListenerConfig) (runtime.Object, error) |
||||
|
||||
type ListenerConfigLister interface { |
||||
List(namespace string, selector labels.Selector) (ret []*ListenerConfig, err error) |
||||
Get(namespace, name string) (*ListenerConfig, error) |
||||
} |
||||
|
||||
type ListenerConfigController interface { |
||||
Generic() controller.GenericController |
||||
Informer() cache.SharedIndexInformer |
||||
Lister() ListenerConfigLister |
||||
AddHandler(ctx context.Context, name string, handler ListenerConfigHandlerFunc) |
||||
AddClusterScopedHandler(ctx context.Context, name, clusterName string, handler ListenerConfigHandlerFunc) |
||||
Enqueue(namespace, name string) |
||||
Sync(ctx context.Context) error |
||||
Start(ctx context.Context, threadiness int) error |
||||
} |
||||
|
||||
type ListenerConfigInterface interface { |
||||
ObjectClient() *objectclient.ObjectClient |
||||
Create(*ListenerConfig) (*ListenerConfig, error) |
||||
GetNamespaced(namespace, name string, opts metav1.GetOptions) (*ListenerConfig, error) |
||||
Get(name string, opts metav1.GetOptions) (*ListenerConfig, error) |
||||
Update(*ListenerConfig) (*ListenerConfig, error) |
||||
Delete(name string, options *metav1.DeleteOptions) error |
||||
DeleteNamespaced(namespace, name string, options *metav1.DeleteOptions) error |
||||
List(opts metav1.ListOptions) (*ListenerConfigList, error) |
||||
Watch(opts metav1.ListOptions) (watch.Interface, error) |
||||
DeleteCollection(deleteOpts *metav1.DeleteOptions, listOpts metav1.ListOptions) error |
||||
Controller() ListenerConfigController |
||||
AddHandler(ctx context.Context, name string, sync ListenerConfigHandlerFunc) |
||||
AddLifecycle(ctx context.Context, name string, lifecycle ListenerConfigLifecycle) |
||||
AddClusterScopedHandler(ctx context.Context, name, clusterName string, sync ListenerConfigHandlerFunc) |
||||
AddClusterScopedLifecycle(ctx context.Context, name, clusterName string, lifecycle ListenerConfigLifecycle) |
||||
} |
||||
|
||||
type listenerConfigLister struct { |
||||
controller *listenerConfigController |
||||
} |
||||
|
||||
func (l *listenerConfigLister) List(namespace string, selector labels.Selector) (ret []*ListenerConfig, err error) { |
||||
err = cache.ListAllByNamespace(l.controller.Informer().GetIndexer(), namespace, selector, func(obj interface{}) { |
||||
ret = append(ret, obj.(*ListenerConfig)) |
||||
}) |
||||
return |
||||
} |
||||
|
||||
func (l *listenerConfigLister) Get(namespace, name string) (*ListenerConfig, 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: ListenerConfigGroupVersionKind.Group, |
||||
Resource: "listenerConfig", |
||||
}, key) |
||||
} |
||||
return obj.(*ListenerConfig), nil |
||||
} |
||||
|
||||
type listenerConfigController struct { |
||||
controller.GenericController |
||||
} |
||||
|
||||
func (c *listenerConfigController) Generic() controller.GenericController { |
||||
return c.GenericController |
||||
} |
||||
|
||||
func (c *listenerConfigController) Lister() ListenerConfigLister { |
||||
return &listenerConfigLister{ |
||||
controller: c, |
||||
} |
||||
} |
||||
|
||||
func (c *listenerConfigController) AddHandler(ctx context.Context, name string, handler ListenerConfigHandlerFunc) { |
||||
c.GenericController.AddHandler(ctx, name, func(key string, obj interface{}) (interface{}, error) { |
||||
if obj == nil { |
||||
return handler(key, nil) |
||||
} else if v, ok := obj.(*ListenerConfig); ok { |
||||
return handler(key, v) |
||||
} else { |
||||
return nil, nil |
||||
} |
||||
}) |
||||
} |
||||
|
||||
func (c *listenerConfigController) AddClusterScopedHandler(ctx context.Context, name, cluster string, handler ListenerConfigHandlerFunc) { |
||||
c.GenericController.AddHandler(ctx, name, func(key string, obj interface{}) (interface{}, error) { |
||||
if obj == nil { |
||||
return handler(key, nil) |
||||
} else if v, ok := obj.(*ListenerConfig); ok && controller.ObjectInCluster(cluster, obj) { |
||||
return handler(key, v) |
||||
} else { |
||||
return nil, nil |
||||
} |
||||
}) |
||||
} |
||||
|
||||
type listenerConfigFactory struct { |
||||
} |
||||
|
||||
func (c listenerConfigFactory) Object() runtime.Object { |
||||
return &ListenerConfig{} |
||||
} |
||||
|
||||
func (c listenerConfigFactory) List() runtime.Object { |
||||
return &ListenerConfigList{} |
||||
} |
||||
|
||||
func (s *listenerConfigClient) Controller() ListenerConfigController { |
||||
s.client.Lock() |
||||
defer s.client.Unlock() |
||||
|
||||
c, ok := s.client.listenerConfigControllers[s.ns] |
||||
if ok { |
||||
return c |
||||
} |
||||
|
||||
genericController := controller.NewGenericController(ListenerConfigGroupVersionKind.Kind+"Controller", |
||||
s.objectClient) |
||||
|
||||
c = &listenerConfigController{ |
||||
GenericController: genericController, |
||||
} |
||||
|
||||
s.client.listenerConfigControllers[s.ns] = c |
||||
s.client.starters = append(s.client.starters, c) |
||||
|
||||
return c |
||||
} |
||||
|
||||
type listenerConfigClient struct { |
||||
client *Client |
||||
ns string |
||||
objectClient *objectclient.ObjectClient |
||||
controller ListenerConfigController |
||||
} |
||||
|
||||
func (s *listenerConfigClient) ObjectClient() *objectclient.ObjectClient { |
||||
return s.objectClient |
||||
} |
||||
|
||||
func (s *listenerConfigClient) Create(o *ListenerConfig) (*ListenerConfig, error) { |
||||
obj, err := s.objectClient.Create(o) |
||||
return obj.(*ListenerConfig), err |
||||
} |
||||
|
||||
func (s *listenerConfigClient) Get(name string, opts metav1.GetOptions) (*ListenerConfig, error) { |
||||
obj, err := s.objectClient.Get(name, opts) |
||||
return obj.(*ListenerConfig), err |
||||
} |
||||
|
||||
func (s *listenerConfigClient) GetNamespaced(namespace, name string, opts metav1.GetOptions) (*ListenerConfig, error) { |
||||
obj, err := s.objectClient.GetNamespaced(namespace, name, opts) |
||||
return obj.(*ListenerConfig), err |
||||
} |
||||
|
||||
func (s *listenerConfigClient) Update(o *ListenerConfig) (*ListenerConfig, error) { |
||||
obj, err := s.objectClient.Update(o.Name, o) |
||||
return obj.(*ListenerConfig), err |
||||
} |
||||
|
||||
func (s *listenerConfigClient) Delete(name string, options *metav1.DeleteOptions) error { |
||||
return s.objectClient.Delete(name, options) |
||||
} |
||||
|
||||
func (s *listenerConfigClient) DeleteNamespaced(namespace, name string, options *metav1.DeleteOptions) error { |
||||
return s.objectClient.DeleteNamespaced(namespace, name, options) |
||||
} |
||||
|
||||
func (s *listenerConfigClient) List(opts metav1.ListOptions) (*ListenerConfigList, error) { |
||||
obj, err := s.objectClient.List(opts) |
||||
return obj.(*ListenerConfigList), err |
||||
} |
||||
|
||||
func (s *listenerConfigClient) Watch(opts metav1.ListOptions) (watch.Interface, error) { |
||||
return s.objectClient.Watch(opts) |
||||
} |
||||
|
||||
// Patch applies the patch and returns the patched deployment.
|
||||
func (s *listenerConfigClient) Patch(o *ListenerConfig, patchType types.PatchType, data []byte, subresources ...string) (*ListenerConfig, error) { |
||||
obj, err := s.objectClient.Patch(o.Name, o, patchType, data, subresources...) |
||||
return obj.(*ListenerConfig), err |
||||
} |
||||
|
||||
func (s *listenerConfigClient) DeleteCollection(deleteOpts *metav1.DeleteOptions, listOpts metav1.ListOptions) error { |
||||
return s.objectClient.DeleteCollection(deleteOpts, listOpts) |
||||
} |
||||
|
||||
func (s *listenerConfigClient) AddHandler(ctx context.Context, name string, sync ListenerConfigHandlerFunc) { |
||||
s.Controller().AddHandler(ctx, name, sync) |
||||
} |
||||
|
||||
func (s *listenerConfigClient) AddLifecycle(ctx context.Context, name string, lifecycle ListenerConfigLifecycle) { |
||||
sync := NewListenerConfigLifecycleAdapter(name, false, s, lifecycle) |
||||
s.Controller().AddHandler(ctx, name, sync) |
||||
} |
||||
|
||||
func (s *listenerConfigClient) AddClusterScopedHandler(ctx context.Context, name, clusterName string, sync ListenerConfigHandlerFunc) { |
||||
s.Controller().AddClusterScopedHandler(ctx, name, clusterName, sync) |
||||
} |
||||
|
||||
func (s *listenerConfigClient) AddClusterScopedLifecycle(ctx context.Context, name, clusterName string, lifecycle ListenerConfigLifecycle) { |
||||
sync := NewListenerConfigLifecycleAdapter(name+"_"+clusterName, true, s, lifecycle) |
||||
s.Controller().AddClusterScopedHandler(ctx, name, clusterName, sync) |
||||
} |
||||
|
||||
type ListenerConfigIndexer func(obj *ListenerConfig) ([]string, error) |
||||
|
||||
type ListenerConfigClientCache interface { |
||||
Get(namespace, name string) (*ListenerConfig, error) |
||||
List(namespace string, selector labels.Selector) ([]*ListenerConfig, error) |
||||
|
||||
Index(name string, indexer ListenerConfigIndexer) |
||||
GetIndexed(name, key string) ([]*ListenerConfig, error) |
||||
} |
||||
|
||||
type ListenerConfigClient interface { |
||||
Create(*ListenerConfig) (*ListenerConfig, error) |
||||
Get(namespace, name string, opts metav1.GetOptions) (*ListenerConfig, error) |
||||
Update(*ListenerConfig) (*ListenerConfig, error) |
||||
Delete(namespace, name string, options *metav1.DeleteOptions) error |
||||
List(namespace string, opts metav1.ListOptions) (*ListenerConfigList, error) |
||||
Watch(opts metav1.ListOptions) (watch.Interface, error) |
||||
|
||||
Cache() ListenerConfigClientCache |
||||
|
||||
OnCreate(ctx context.Context, name string, sync ListenerConfigChangeHandlerFunc) |
||||
OnChange(ctx context.Context, name string, sync ListenerConfigChangeHandlerFunc) |
||||
OnRemove(ctx context.Context, name string, sync ListenerConfigChangeHandlerFunc) |
||||
Enqueue(namespace, name string) |
||||
|
||||
Generic() controller.GenericController |
||||
ObjectClient() *objectclient.ObjectClient |
||||
Interface() ListenerConfigInterface |
||||
} |
||||
|
||||
type listenerConfigClientCache struct { |
||||
client *listenerConfigClient2 |
||||
} |
||||
|
||||
type listenerConfigClient2 struct { |
||||
iface ListenerConfigInterface |
||||
controller ListenerConfigController |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) Interface() ListenerConfigInterface { |
||||
return n.iface |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) Generic() controller.GenericController { |
||||
return n.iface.Controller().Generic() |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) ObjectClient() *objectclient.ObjectClient { |
||||
return n.Interface().ObjectClient() |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) Enqueue(namespace, name string) { |
||||
n.iface.Controller().Enqueue(namespace, name) |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) Create(obj *ListenerConfig) (*ListenerConfig, error) { |
||||
return n.iface.Create(obj) |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) Get(namespace, name string, opts metav1.GetOptions) (*ListenerConfig, error) { |
||||
return n.iface.GetNamespaced(namespace, name, opts) |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) Update(obj *ListenerConfig) (*ListenerConfig, error) { |
||||
return n.iface.Update(obj) |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) Delete(namespace, name string, options *metav1.DeleteOptions) error { |
||||
return n.iface.DeleteNamespaced(namespace, name, options) |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) List(namespace string, opts metav1.ListOptions) (*ListenerConfigList, error) { |
||||
return n.iface.List(opts) |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) Watch(opts metav1.ListOptions) (watch.Interface, error) { |
||||
return n.iface.Watch(opts) |
||||
} |
||||
|
||||
func (n *listenerConfigClientCache) Get(namespace, name string) (*ListenerConfig, error) { |
||||
return n.client.controller.Lister().Get(namespace, name) |
||||
} |
||||
|
||||
func (n *listenerConfigClientCache) List(namespace string, selector labels.Selector) ([]*ListenerConfig, error) { |
||||
return n.client.controller.Lister().List(namespace, selector) |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) Cache() ListenerConfigClientCache { |
||||
n.loadController() |
||||
return &listenerConfigClientCache{ |
||||
client: n, |
||||
} |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) OnCreate(ctx context.Context, name string, sync ListenerConfigChangeHandlerFunc) { |
||||
n.loadController() |
||||
n.iface.AddLifecycle(ctx, name+"-create", &listenerConfigLifecycleDelegate{create: sync}) |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) OnChange(ctx context.Context, name string, sync ListenerConfigChangeHandlerFunc) { |
||||
n.loadController() |
||||
n.iface.AddLifecycle(ctx, name+"-change", &listenerConfigLifecycleDelegate{update: sync}) |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) OnRemove(ctx context.Context, name string, sync ListenerConfigChangeHandlerFunc) { |
||||
n.loadController() |
||||
n.iface.AddLifecycle(ctx, name, &listenerConfigLifecycleDelegate{remove: sync}) |
||||
} |
||||
|
||||
func (n *listenerConfigClientCache) Index(name string, indexer ListenerConfigIndexer) { |
||||
err := n.client.controller.Informer().GetIndexer().AddIndexers(map[string]cache.IndexFunc{ |
||||
name: func(obj interface{}) ([]string, error) { |
||||
if v, ok := obj.(*ListenerConfig); ok { |
||||
return indexer(v) |
||||
} |
||||
return nil, nil |
||||
}, |
||||
}) |
||||
|
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
} |
||||
|
||||
func (n *listenerConfigClientCache) GetIndexed(name, key string) ([]*ListenerConfig, error) { |
||||
var result []*ListenerConfig |
||||
objs, err := n.client.controller.Informer().GetIndexer().ByIndex(name, key) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
for _, obj := range objs { |
||||
if v, ok := obj.(*ListenerConfig); ok { |
||||
result = append(result, v) |
||||
} |
||||
} |
||||
|
||||
return result, nil |
||||
} |
||||
|
||||
func (n *listenerConfigClient2) loadController() { |
||||
if n.controller == nil { |
||||
n.controller = n.iface.Controller() |
||||
} |
||||
} |
||||
|
||||
type listenerConfigLifecycleDelegate struct { |
||||
create ListenerConfigChangeHandlerFunc |
||||
update ListenerConfigChangeHandlerFunc |
||||
remove ListenerConfigChangeHandlerFunc |
||||
} |
||||
|
||||
func (n *listenerConfigLifecycleDelegate) HasCreate() bool { |
||||
return n.create != nil |
||||
} |
||||
|
||||
func (n *listenerConfigLifecycleDelegate) Create(obj *ListenerConfig) (runtime.Object, error) { |
||||
if n.create == nil { |
||||
return obj, nil |
||||
} |
||||
return n.create(obj) |
||||
} |
||||
|
||||
func (n *listenerConfigLifecycleDelegate) HasFinalize() bool { |
||||
return n.remove != nil |
||||
} |
||||
|
||||
func (n *listenerConfigLifecycleDelegate) Remove(obj *ListenerConfig) (runtime.Object, error) { |
||||
if n.remove == nil { |
||||
return obj, nil |
||||
} |
||||
return n.remove(obj) |
||||
} |
||||
|
||||
func (n *listenerConfigLifecycleDelegate) Updated(obj *ListenerConfig) (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 ListenerConfigLifecycle interface { |
||||
Create(obj *ListenerConfig) (runtime.Object, error) |
||||
Remove(obj *ListenerConfig) (runtime.Object, error) |
||||
Updated(obj *ListenerConfig) (runtime.Object, error) |
||||
} |
||||
|
||||
type listenerConfigLifecycleAdapter struct { |
||||
lifecycle ListenerConfigLifecycle |
||||
} |
||||
|
||||
func (w *listenerConfigLifecycleAdapter) HasCreate() bool { |
||||
o, ok := w.lifecycle.(lifecycle.ObjectLifecycleCondition) |
||||
return !ok || o.HasCreate() |
||||
} |
||||
|
||||
func (w *listenerConfigLifecycleAdapter) HasFinalize() bool { |
||||
o, ok := w.lifecycle.(lifecycle.ObjectLifecycleCondition) |
||||
return !ok || o.HasFinalize() |
||||
} |
||||
|
||||
func (w *listenerConfigLifecycleAdapter) Create(obj runtime.Object) (runtime.Object, error) { |
||||
o, err := w.lifecycle.Create(obj.(*ListenerConfig)) |
||||
if o == nil { |
||||
return nil, err |
||||
} |
||||
return o, err |
||||
} |
||||
|
||||
func (w *listenerConfigLifecycleAdapter) Finalize(obj runtime.Object) (runtime.Object, error) { |
||||
o, err := w.lifecycle.Remove(obj.(*ListenerConfig)) |
||||
if o == nil { |
||||
return nil, err |
||||
} |
||||
return o, err |
||||
} |
||||
|
||||
func (w *listenerConfigLifecycleAdapter) Updated(obj runtime.Object) (runtime.Object, error) { |
||||
o, err := w.lifecycle.Updated(obj.(*ListenerConfig)) |
||||
if o == nil { |
||||
return nil, err |
||||
} |
||||
return o, err |
||||
} |
||||
|
||||
func NewListenerConfigLifecycleAdapter(name string, clusterScoped bool, client ListenerConfigInterface, l ListenerConfigLifecycle) ListenerConfigHandlerFunc { |
||||
adapter := &listenerConfigLifecycleAdapter{lifecycle: l} |
||||
syncFn := lifecycle.NewObjectLifecycleAdapter(name, clusterScoped, adapter, client.ObjectClient()) |
||||
return func(key string, obj *ListenerConfig) (runtime.Object, error) { |
||||
newObj, err := syncFn(key, obj) |
||||
if o, ok := newObj.(runtime.Object); ok { |
||||
return o, err |
||||
} |
||||
return nil, err |
||||
} |
||||
} |
@ -0,0 +1,40 @@
|
||||
package v1 |
||||
|
||||
import ( |
||||
"k8s.io/apimachinery/pkg/runtime" |
||||
"k8s.io/apimachinery/pkg/runtime/schema" |
||||
) |
||||
|
||||
const ( |
||||
GroupName = "k3s.cattle.io" |
||||
Version = "v1" |
||||
) |
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: Version} |
||||
|
||||
// Kind takes an unqualified kind and returns a Group qualified GroupKind
|
||||
func Kind(kind string) schema.GroupKind { |
||||
return SchemeGroupVersion.WithKind(kind).GroupKind() |
||||
} |
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource { |
||||
return SchemeGroupVersion.WithResource(resource).GroupResource() |
||||
} |
||||
|
||||
var ( |
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) |
||||
AddToScheme = SchemeBuilder.AddToScheme |
||||
) |
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error { |
||||
// TODO this gets cleaned up when the types are fixed
|
||||
scheme.AddKnownTypes(SchemeGroupVersion, |
||||
|
||||
&ListenerConfig{}, |
||||
&ListenerConfigList{}, |
||||
) |
||||
return nil |
||||
} |
@ -0,0 +1,12 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"github.com/rancher/norman/generator/cleanup" |
||||
"github.com/sirupsen/logrus" |
||||
) |
||||
|
||||
func main() { |
||||
if err := cleanup.Cleanup("./types"); err != nil { |
||||
logrus.Fatal(err) |
||||
} |
||||
} |
@ -0,0 +1,17 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"github.com/rancher/norman/generator" |
||||
v1 "github.com/rancher/rio/types/apis/k3s.cattle.io/v1" |
||||
"github.com/sirupsen/logrus" |
||||
) |
||||
|
||||
var ( |
||||
basePackage = "github.com/rancher/rio/types" |
||||
) |
||||
|
||||
func main() { |
||||
if err := generator.DefaultGenerate(v1.Schemas, basePackage, false, nil); err != nil { |
||||
logrus.Fatal(err) |
||||
} |
||||
} |
@ -0,0 +1,17 @@
|
||||
package=github.com/rancher/rio |
||||
package=github.com/jteeuwen/go-bindata |
||||
package=github.com/jteeuwen/go-bindata/go-bindata |
||||
|
||||
k8s.io/kubernetes a1d7d1b140f43b6503311ffc1dd80017c553bf8e file:///home/darren/src/kuberlite/.git transitive=true,staging=true |
||||
|
||||
github.com/rancher/norman 5726ebfba191eef161af9638e85bf4fcaa58e008 https://github.com/ibuildthecloud/norman.git |
||||
github.com/coreos/flannel 39af3d7e46f2efa156644e247bdcf3b5bc5f1394 |
||||
github.com/natefinch/lumberjack aee4629129445bbdfb69aa565537dcfa16544311 |
||||
github.com/gorilla/mux v1.6.2 |
||||
github.com/gorilla/websocket v1.2.0 |
||||
github.com/mattn/go-sqlite3 v1.9.0 |
||||
github.com/patrickmn/go-cache v2.1.0 |
||||
golang.org/x/crypto a49355c7e3f8fe157a85be2f77e6e269a0f89602 |
||||
gopkg.in/freddierice/go-losetup.v1 fc9adea44124401d8bfef3a97eaf61b5d44cc2c6 |
||||
github.com/urfave/cli 8e01ec4cd3e2d84ab2fe90d8210528ffbb06d8ff |
||||
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c |
Loading…
Reference in new issue