refactor(*): address linter errors and warnings (#69)
This commit is contained in:
parent
f6686bcc7b
commit
1115c86456
@ -2,29 +2,51 @@ metadata:
|
||||
repository: dianemo/initramfs
|
||||
pipeline:
|
||||
stages:
|
||||
- proto
|
||||
- cli
|
||||
- generate
|
||||
- build
|
||||
stages:
|
||||
proto:
|
||||
build:
|
||||
artifacts:
|
||||
- source: /tmp/cli
|
||||
destination: ../build/osctl
|
||||
tasks:
|
||||
- test
|
||||
- cli
|
||||
- init
|
||||
generate:
|
||||
artifacts:
|
||||
- source: /go/src/github.com/autonomy/dianemo/proto
|
||||
destination: ./src/init
|
||||
tasks:
|
||||
- proto
|
||||
cli:
|
||||
artifacts:
|
||||
- source: /cli
|
||||
destination: ../build/osctl
|
||||
tasks:
|
||||
- cli
|
||||
build:
|
||||
tasks:
|
||||
- build
|
||||
test:
|
||||
tasks:
|
||||
- test
|
||||
- proto
|
||||
tasks:
|
||||
cli:
|
||||
template: |
|
||||
FROM dianemo/tools:{{ .Docker.Image.Tag }} AS {{ .Docker.CurrentStage }}
|
||||
RUN ln -s /tools/lib64 /lib64
|
||||
RUN mkdir /tmp
|
||||
WORKDIR $GOPATH/src/github.com/autonomy/dianemo/initramfs/src/init
|
||||
COPY src/init ./
|
||||
WORKDIR $GOPATH/src/github.com/autonomy/dianemo/initramfs/src/init/cli
|
||||
RUN GOOS=darwin go build -o /cli
|
||||
RUN chmod +x /cli
|
||||
init:
|
||||
template: |
|
||||
FROM dianemo/tools:{{ .Docker.Image.Tag }} AS {{ .Docker.CurrentStage }}
|
||||
RUN ln -s /tools/lib64 /lib64
|
||||
RUN mkdir /tmp
|
||||
WORKDIR $GOPATH/src/github.com/autonomy/dianemo/initramfs/src/init
|
||||
COPY src/init ./
|
||||
RUN go build -ldflags '-s -w -linkmode external -extldflags "-static -L/usr/lib -lblkid -luuid"' -o /initramfs/init
|
||||
RUN chmod +x /initramfs/init
|
||||
WORKDIR /initramfs
|
||||
RUN find . 2>/dev/null | cpio -H newc -o | xz -v -C crc32 -9 -e -T 0 -z >/initramfs/initramfs.xz
|
||||
FROM scratch
|
||||
WORKDIR /tmp
|
||||
COPY --from=init /initramfs/init init
|
||||
COPY --from=init /initramfs/initramfs.xz initramfs.xz
|
||||
COPY --from=cli /cli cli
|
||||
CMD false
|
||||
proto:
|
||||
template: |
|
||||
FROM golang:1.10.0 AS {{ .Docker.CurrentStage }}
|
||||
@ -38,26 +60,13 @@ tasks:
|
||||
&& chmod +x /bin/protoc
|
||||
COPY ./src/init/proto ./proto
|
||||
RUN protoc -I/usr/local/include -I./proto --go_out=plugins=grpc:proto proto/api.proto
|
||||
cli:
|
||||
test:
|
||||
template: |
|
||||
FROM golang:1.10.0-alpine3.7 AS {{ .Docker.CurrentStage }}
|
||||
RUN apk --update add gcc musl-dev util-linux-dev xz
|
||||
FROM dianemo/tools:{{ .Docker.Image.Tag }} AS {{ .Docker.CurrentStage }}
|
||||
RUN ln -s /tools/lib64 /lib64
|
||||
RUN mkdir /tmp
|
||||
RUN curl -L https://github.com/alecthomas/gometalinter/releases/download/v2.0.5/gometalinter-2.0.5-linux-amd64.tar.gz | tar -xz --strip-components=1 -C /tools/bin
|
||||
WORKDIR $GOPATH/src/github.com/autonomy/dianemo/initramfs/src/init
|
||||
COPY src/init ./
|
||||
WORKDIR $GOPATH/src/github.com/autonomy/dianemo/initramfs/src/init/cli
|
||||
RUN GOOS=darwin /usr/local/go/bin/go build -o /cli
|
||||
RUN chmod +x /cli
|
||||
build:
|
||||
template: |
|
||||
FROM golang:1.10.0-alpine3.7 AS {{ .Docker.CurrentStage }}
|
||||
RUN apk --update add gcc musl-dev util-linux-dev xz
|
||||
WORKDIR $GOPATH/src/github.com/autonomy/dianemo/initramfs/src/init
|
||||
COPY src/init ./
|
||||
RUN /usr/local/go/bin/go build -ldflags '-s -w -linkmode external -extldflags "-static -L/usr/lib -lblkid -luuid"' -o /initramfs/init
|
||||
RUN chmod +x /initramfs/init
|
||||
WORKDIR /initramfs
|
||||
RUN find . 2>/dev/null | cpio -H newc -o | xz -v -C crc32 -9 -e -T 0 -z >/initramfs/initramfs.xz
|
||||
FROM scratch
|
||||
WORKDIR /tmp
|
||||
COPY --from={{ .Docker.CurrentStage }} /initramfs/init init
|
||||
COPY --from={{ .Docker.CurrentStage }} /initramfs/initramfs.xz initramfs.xz
|
||||
COPY --from=autonomy/golang:1.10 /bin/test.sh /bin/test.sh
|
||||
RUN test.sh
|
||||
|
@ -15,7 +15,10 @@ var dmesgCmd = &cobra.Command{
|
||||
Long: ``,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 0 {
|
||||
cmd.Usage()
|
||||
if err := cmd.Usage(); err != nil {
|
||||
// TODO: How should we handle this?
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
creds, err := client.NewDefaultClientCredentials()
|
||||
|
@ -24,6 +24,8 @@ var injectOSCmd = &cobra.Command{
|
||||
Short: "Populates fields in the user data that are generated for the OS",
|
||||
Long: ``,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var err error
|
||||
|
||||
if len(args) != 1 {
|
||||
os.Exit(1)
|
||||
}
|
||||
@ -33,16 +35,16 @@ var injectOSCmd = &cobra.Command{
|
||||
os.Exit(1)
|
||||
}
|
||||
data := &userdata.UserData{}
|
||||
if err := yaml.Unmarshal(fileBytes, data); err != nil {
|
||||
if err = yaml.Unmarshal(fileBytes, data); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
if data.OS.Security == nil {
|
||||
data.OS.Security = &userdata.Security{}
|
||||
data.OS.Security.Identity = &userdata.KeyPair{}
|
||||
data.OS.Security.CA = &userdata.KeyPair{}
|
||||
data.OS.Security.Identity = &userdata.CertificateAndKeyPaths{}
|
||||
data.OS.Security.CA = &userdata.CertificateAndKeyPaths{}
|
||||
}
|
||||
if identity != "" {
|
||||
fileBytes, err := ioutil.ReadFile(identity + ".crt")
|
||||
fileBytes, err = ioutil.ReadFile(identity + ".crt")
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
@ -54,7 +56,7 @@ var injectOSCmd = &cobra.Command{
|
||||
data.OS.Security.Identity.Key = base64.StdEncoding.EncodeToString(fileBytes)
|
||||
}
|
||||
if ca != "" {
|
||||
fileBytes, err := ioutil.ReadFile(ca + ".crt")
|
||||
fileBytes, err = ioutil.ReadFile(ca + ".crt")
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
@ -65,7 +67,9 @@ var injectOSCmd = &cobra.Command{
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
ioutil.WriteFile(filename, dataBytes, 0700)
|
||||
if err := ioutil.WriteFile(filename, dataBytes, 0700); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@ -85,15 +89,15 @@ var injectKubernetesCmd = &cobra.Command{
|
||||
os.Exit(1)
|
||||
}
|
||||
data := &userdata.UserData{}
|
||||
if err := yaml.Unmarshal(fileBytes, data); err != nil {
|
||||
if err = yaml.Unmarshal(fileBytes, data); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if data.Kubernetes.CA == nil {
|
||||
data.Kubernetes.CA = &userdata.KeyPair{}
|
||||
data.Kubernetes.CA = &userdata.CertificateAndKeyPaths{}
|
||||
}
|
||||
if ca != "" {
|
||||
fileBytes, err := ioutil.ReadFile(ca + ".crt")
|
||||
fileBytes, err = ioutil.ReadFile(ca + ".crt")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
@ -107,7 +111,7 @@ var injectKubernetesCmd = &cobra.Command{
|
||||
data.Kubernetes.CA.Key = base64.StdEncoding.EncodeToString(fileBytes)
|
||||
}
|
||||
if hash != "" {
|
||||
fileBytes, err := ioutil.ReadFile(hash + ".sha256")
|
||||
fileBytes, err = ioutil.ReadFile(hash + ".sha256")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
@ -119,7 +123,9 @@ var injectKubernetesCmd = &cobra.Command{
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
ioutil.WriteFile(filename, dataBytes, 0700)
|
||||
if err := ioutil.WriteFile(filename, dataBytes, 0700); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,9 @@ var kubeconfigCmd = &cobra.Command{
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
c.Kubeconfig()
|
||||
if err := c.Kubeconfig(); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,9 @@ var logsCmd = &cobra.Command{
|
||||
Long: ``,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 1 {
|
||||
cmd.Usage()
|
||||
if err := cmd.Usage(); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
process := args[0]
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
var (
|
||||
address string
|
||||
ca string
|
||||
crt string
|
||||
key string
|
||||
isContainer bool
|
||||
organization string
|
||||
|
@ -35,42 +35,45 @@ func hang() {
|
||||
|
||||
func init() {
|
||||
log.SetFlags(log.Lshortfile | log.Ldate | log.Lmicroseconds | log.Ltime)
|
||||
os.Setenv("PATH", constants.PATH)
|
||||
if err := os.Setenv("PATH", constants.PATH); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
switchRoot = flag.Bool("switch-root", false, "perform a switch_root")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer hang()
|
||||
if !*switchRoot {
|
||||
// Read the block devices and populate the mount point definitions.
|
||||
if err := mount.Init(constants.NewRoot); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Download the user data.
|
||||
data, err := userdata.Download()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Prepare the necessary files in the rootfs.
|
||||
if err := rootfs.Prepare(constants.NewRoot, data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Unmount the ROOT and DATA block devices
|
||||
if err := mount.Unmount(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Perform the equivalent of switch_root.
|
||||
if err := switchroot.Switch(constants.NewRoot); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
func initram() (err error) {
|
||||
// Read the block devices and populate the mount point definitions.
|
||||
if err = mount.Init(constants.NewRoot); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Download the user data.
|
||||
data, err := userdata.Download()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return
|
||||
}
|
||||
// Prepare the necessary files in the rootfs.
|
||||
if err = rootfs.Prepare(constants.NewRoot, data); err != nil {
|
||||
return
|
||||
}
|
||||
// Unmount the ROOT and DATA block devices
|
||||
if err = mount.Unmount(); err != nil {
|
||||
return
|
||||
}
|
||||
// Perform the equivalent of switch_root.
|
||||
if err = switchroot.Switch(constants.NewRoot); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func root() (err error) {
|
||||
// Download the user data.
|
||||
data, err := userdata.Download()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Start the services essential to running Kubernetes.
|
||||
@ -89,9 +92,19 @@ func main() {
|
||||
services.Start(&service.Kubelet{})
|
||||
services.Start(&service.Kubeadm{})
|
||||
|
||||
s, err := server.NewServer(data.OS.Security)
|
||||
if err != nil {
|
||||
return server.NewServer(data.OS.Security).Listen()
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer hang()
|
||||
|
||||
if !*switchRoot {
|
||||
if err := initram(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := root(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s.Listen()
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
// +build linux
|
||||
|
||||
// Package blkid provides bindings to libblkid.
|
||||
package blkid
|
||||
|
||||
@ -14,6 +16,7 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// NewProbeFromFilename executes lblkid blkid_new_probe_from_filename.
|
||||
func NewProbeFromFilename(s string) (C.blkid_probe, error) {
|
||||
cs := C.CString(s)
|
||||
defer C.free(unsafe.Pointer(cs))
|
||||
@ -25,12 +28,13 @@ func NewProbeFromFilename(s string) (C.blkid_probe, error) {
|
||||
return pr, nil
|
||||
}
|
||||
|
||||
// DoProbe executes lblkid blkid_do_probe.
|
||||
func DoProbe(pr C.blkid_probe) {
|
||||
C.blkid_do_probe(pr)
|
||||
}
|
||||
|
||||
// ProbeLookupValue implements:
|
||||
// int blkid_probe_lookup_value (blkid_probe pr, const char *name, const char **data, size_t *len);
|
||||
// int blkid_probe_lookup_value (blkid_probe pr, const char *name, const char **data, size_t *len);
|
||||
func ProbeLookupValue(pr C.blkid_probe, name string, size *int) (string, error) {
|
||||
cs := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cs))
|
||||
@ -51,19 +55,19 @@ func ProbeLookupValue(pr C.blkid_probe, name string, size *int) (string, error)
|
||||
}
|
||||
|
||||
// ProbeGetPartitions implements:
|
||||
// blkid_partlist blkid_probe_get_partitions (blkid_probe pr);
|
||||
// blkid_partlist blkid_probe_get_partitions (blkid_probe pr);
|
||||
func ProbeGetPartitions(pr C.blkid_probe) C.blkid_partlist {
|
||||
return C.blkid_probe_get_partitions(pr)
|
||||
}
|
||||
|
||||
// ProbeGetPartitionsPartlistNumOfPartitions implements:
|
||||
// int blkid_partlist_numof_partitions (blkid_partlist ls);
|
||||
// int blkid_partlist_numof_partitions (blkid_partlist ls);
|
||||
func ProbeGetPartitionsPartlistNumOfPartitions(ls C.blkid_partlist) int {
|
||||
return int(C.blkid_partlist_numof_partitions(ls))
|
||||
}
|
||||
|
||||
// FreeProbe implements:
|
||||
// int blkid_partlist_numof_partitions (blkid_partlist ls);
|
||||
// int blkid_partlist_numof_partitions (blkid_partlist ls);
|
||||
func FreeProbe(pr C.blkid_probe) {
|
||||
C.blkid_free_probe(pr)
|
||||
}
|
||||
|
@ -7,31 +7,24 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Size int
|
||||
}
|
||||
|
||||
type Option func(*Options)
|
||||
|
||||
// Chunker is an interface for embedding all chunking interfaces under one name.
|
||||
type Chunker interface {
|
||||
ChunkReader
|
||||
}
|
||||
|
||||
// ChunkReader is an interface describing a reader that streams data in []byte
|
||||
// chunks.
|
||||
type ChunkReader interface {
|
||||
Read(context.Context) <-chan []byte
|
||||
}
|
||||
|
||||
// DefaultChunker is a conecrete type that implements the Chunker interface.
|
||||
type DefaultChunker struct {
|
||||
path string
|
||||
options *Options
|
||||
}
|
||||
|
||||
func Size(s int) Option {
|
||||
return func(args *Options) {
|
||||
args.Size = s
|
||||
}
|
||||
}
|
||||
|
||||
// NewDefaultChunker initializes a DefaultChunker with default values.
|
||||
func NewDefaultChunker(path string, setters ...Option) Chunker {
|
||||
opts := &Options{
|
||||
Size: 1024,
|
||||
@ -46,6 +39,22 @@ func NewDefaultChunker(path string, setters ...Option) Chunker {
|
||||
}
|
||||
}
|
||||
|
||||
// Options is the functional options struct.
|
||||
type Options struct {
|
||||
Size int
|
||||
}
|
||||
|
||||
// Option is the functional option func.
|
||||
type Option func(*Options)
|
||||
|
||||
// Size sets the chunk size of the Chunker.
|
||||
func Size(s int) Option {
|
||||
return func(args *Options) {
|
||||
args.Size = s
|
||||
}
|
||||
}
|
||||
|
||||
// Read implements ChunkReader.
|
||||
func (c *DefaultChunker) Read(ctx context.Context) <-chan []byte {
|
||||
// Create a buffered channel of length 1.
|
||||
ch := make(chan []byte, 1)
|
||||
@ -56,13 +65,14 @@ func (c *DefaultChunker) Read(ctx context.Context) <-chan []byte {
|
||||
|
||||
go func(ch chan []byte, f *os.File) {
|
||||
defer close(ch)
|
||||
// nolint: errcheck
|
||||
defer f.Close()
|
||||
|
||||
offset, err := f.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
buf := make([]byte, c.options.Size, c.options.Size)
|
||||
buf := make([]byte, c.options.Size)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
|
@ -16,25 +16,30 @@ import (
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
type ClientCredentials struct {
|
||||
// Credentials represents the set of values required to initialize a vaild
|
||||
// Client.
|
||||
type Credentials struct {
|
||||
ca string
|
||||
crt string
|
||||
key string
|
||||
}
|
||||
|
||||
// Client implements the proto.DianemoClient interface. It serves as the
|
||||
// concrete type with the required methods.
|
||||
type Client struct {
|
||||
conn *grpc.ClientConn
|
||||
client proto.DianemoClient
|
||||
credentials *ClientCredentials
|
||||
conn *grpc.ClientConn
|
||||
client proto.DianemoClient
|
||||
}
|
||||
|
||||
func NewDefaultClientCredentials() (creds *ClientCredentials, err error) {
|
||||
// NewDefaultClientCredentials initializes ClientCredentials using default paths
|
||||
// to the required CA, certificate, and key.
|
||||
func NewDefaultClientCredentials() (creds *Credentials, err error) {
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
creds = &ClientCredentials{
|
||||
creds = &Credentials{
|
||||
ca: path.Join(u.HomeDir, ".dianemo/ca.pem"),
|
||||
crt: path.Join(u.HomeDir, ".dianemo/crt.pem"),
|
||||
key: path.Join(u.HomeDir, ".dianemo/key.pem"),
|
||||
@ -43,7 +48,8 @@ func NewDefaultClientCredentials() (creds *ClientCredentials, err error) {
|
||||
return creds, nil
|
||||
}
|
||||
|
||||
func NewClient(address string, port int, clientcreds *ClientCredentials) (c *Client, err error) {
|
||||
// NewClient initializes a Client.
|
||||
func NewClient(address string, port int, clientcreds *Credentials) (c *Client, err error) {
|
||||
grpcOpts := []grpc.DialOption{}
|
||||
|
||||
caBytes, err := ioutil.ReadFile(clientcreds.ca)
|
||||
@ -81,6 +87,7 @@ func NewClient(address string, port int, clientcreds *ClientCredentials) (c *Cli
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Kubeconfig implements the proto.DianemoClient interface.
|
||||
func (c *Client) Kubeconfig() (err error) {
|
||||
ctx := context.Background()
|
||||
r, err := c.client.Kubeconfig(ctx, &empty.Empty{})
|
||||
@ -92,6 +99,7 @@ func (c *Client) Kubeconfig() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dmesg implements the proto.DianemoClient interface.
|
||||
func (c *Client) Dmesg() (err error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
@ -104,6 +112,7 @@ func (c *Client) Dmesg() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Logs implements the proto.DianemoClient interface.
|
||||
func (c *Client) Logs(r *proto.LogsRequest) (err error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
@ -1,19 +1,57 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
KernelRootFlag = "dianemo.autonomy.io/root"
|
||||
UserDataURLFlag = "dianemo.autonomy.io/userdata"
|
||||
NewRoot = "/root"
|
||||
DATALabel = "DATA"
|
||||
ROOTLabel = "ROOT"
|
||||
PATH = "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/opt/cni/bin"
|
||||
ContainerRuntimeDocker = "docker"
|
||||
// KernelParamRoot is the kernel parameter name for specifying the root
|
||||
// disk.
|
||||
KernelParamRoot = "dianemo.autonomy.io/root"
|
||||
|
||||
// KernelParamUserData is the kernel parameter name for specifying the URL
|
||||
// to the user data.
|
||||
KernelParamUserData = "dianemo.autonomy.io/userdata"
|
||||
|
||||
// NewRoot is the path where the switchroot target is mounted.
|
||||
NewRoot = "/root"
|
||||
|
||||
// DataPartitionLabel is the label of the partition to use for mounting at
|
||||
// the data path.
|
||||
DataPartitionLabel = "DATA"
|
||||
|
||||
// RootPartitionLabel is the label of the partition to use for mounting at
|
||||
// the root path.
|
||||
RootPartitionLabel = "ROOT"
|
||||
|
||||
// PATH defines all locations where executables are stored.
|
||||
PATH = "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/opt/cni/bin"
|
||||
|
||||
// ContainerRuntimeDocker is the name of the Docker container runtime.
|
||||
ContainerRuntimeDocker = "docker"
|
||||
|
||||
// ContainerRuntimeDockerSocket is the path to the Docker daemon socket.
|
||||
ContainerRuntimeDockerSocket = "/var/run/docker.sock"
|
||||
ContainerRuntimeCRIO = "crio"
|
||||
ContainerRuntimeCRIOSocket = "/var/run/crio/crio.sock"
|
||||
KubeadmConfig = "/etc/kubernetes/kubeadm.yaml"
|
||||
KubeadmCACert = "/etc/kubernetes/pki/ca.crt"
|
||||
KubeadmCAKey = "/etc/kubernetes/pki/ca.key"
|
||||
SYSLOG_ACTION_SIZE_BUFFER = 10
|
||||
SYSLOG_ACTION_READ_ALL = 3
|
||||
|
||||
// ContainerRuntimeCRIO is the name of the CRI-O container runtime.
|
||||
ContainerRuntimeCRIO = "crio"
|
||||
|
||||
// ContainerRuntimeCRIOSocket is the path to the CRI-O daemon socket.
|
||||
ContainerRuntimeCRIOSocket = "/var/run/crio/crio.sock"
|
||||
|
||||
// KubeadmConfig is the path to the kubeadm manifest file.
|
||||
KubeadmConfig = "/etc/kubernetes/kubeadm.yaml"
|
||||
|
||||
// KubeadmCACert is the path to the root CA certificate.
|
||||
KubeadmCACert = "/etc/kubernetes/pki/ca.crt"
|
||||
|
||||
// KubeadmCAKey is the path to the root CA private key.
|
||||
KubeadmCAKey = "/etc/kubernetes/pki/ca.key"
|
||||
)
|
||||
|
||||
// See https://linux.die.net/man/3/klogctl
|
||||
const (
|
||||
// SYSLOG_ACTION_SIZE_BUFFER is a named type argument to klogctl.
|
||||
// nolint: golint
|
||||
SYSLOG_ACTION_SIZE_BUFFER = 10
|
||||
|
||||
// SYSLOG_ACTION_READ_ALL is a named type argument to klogctl.
|
||||
// nolint: golint
|
||||
SYSLOG_ACTION_READ_ALL = 3
|
||||
)
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// CertificateAuthority represents a CA.
|
||||
type CertificateAuthority struct {
|
||||
Crt *x509.Certificate
|
||||
CrtPEM []byte
|
||||
@ -24,25 +25,30 @@ type CertificateAuthority struct {
|
||||
KeyPEM []byte
|
||||
}
|
||||
|
||||
// Key represents an ECDSA private key.
|
||||
type Key struct {
|
||||
keyEC *ecdsa.PrivateKey
|
||||
KeyPEM []byte
|
||||
}
|
||||
|
||||
// Certificate represents an X.509 certificate.
|
||||
type Certificate struct {
|
||||
X509Certificate *x509.Certificate
|
||||
X509CertificatePEM []byte
|
||||
}
|
||||
|
||||
// CertificateSigningRequest represents a CSR.
|
||||
type CertificateSigningRequest struct {
|
||||
X509CertificateRequest *x509.CertificateRequest
|
||||
X509CertificateRequestPEM []byte
|
||||
}
|
||||
|
||||
// KeyPair represents a certificate and key pair.
|
||||
type KeyPair struct {
|
||||
*tls.Certificate
|
||||
}
|
||||
|
||||
// Options is the functional options struct.
|
||||
type Options struct {
|
||||
Organization string
|
||||
SignatureAlgorithm x509.SignatureAlgorithm
|
||||
@ -52,44 +58,54 @@ type Options struct {
|
||||
NotAfter time.Time
|
||||
}
|
||||
|
||||
// Option is the functional option func.
|
||||
type Option func(*Options)
|
||||
|
||||
// Organization sets the subject organization of the certificate.
|
||||
func Organization(o string) Option {
|
||||
return func(opts *Options) {
|
||||
opts.Organization = o
|
||||
}
|
||||
}
|
||||
|
||||
// SignatureAlgorithm sets the hash algorithm used to sign the SSL certificate.
|
||||
func SignatureAlgorithm(o x509.SignatureAlgorithm) Option {
|
||||
return func(opts *Options) {
|
||||
opts.SignatureAlgorithm = o
|
||||
}
|
||||
}
|
||||
|
||||
// IPAddresses sets the value for the IP addresses in Subject Alternate Name of
|
||||
// the certificate.
|
||||
func IPAddresses(o []net.IP) Option {
|
||||
return func(opts *Options) {
|
||||
opts.IPAddresses = o
|
||||
}
|
||||
}
|
||||
|
||||
// Bits sets the bit size of the RSA key pair.
|
||||
func Bits(o int) Option {
|
||||
return func(opts *Options) {
|
||||
opts.Bits = o
|
||||
}
|
||||
}
|
||||
|
||||
// RSA sets a flag for indicating that the requested operation should be
|
||||
// performed under the context of RSA instead of the default ECDSA.
|
||||
func RSA(o bool) Option {
|
||||
return func(opts *Options) {
|
||||
opts.RSA = o
|
||||
}
|
||||
}
|
||||
|
||||
// NotAfter sets the validity bound describing when a certificate expires.
|
||||
func NotAfter(o time.Time) Option {
|
||||
return func(opts *Options) {
|
||||
opts.NotAfter = o
|
||||
}
|
||||
}
|
||||
|
||||
// NewDefaultOptions initializes the Options struct with default values.
|
||||
func NewDefaultOptions(setters ...Option) *Options {
|
||||
opts := &Options{
|
||||
SignatureAlgorithm: x509.ECDSAWithSHA512,
|
||||
@ -106,6 +122,7 @@ func NewDefaultOptions(setters ...Option) *Options {
|
||||
return opts
|
||||
}
|
||||
|
||||
// NewSerialNumber generates a random serial number for an X.509 certificate.
|
||||
func NewSerialNumber() (sn *big.Int, err error) {
|
||||
snLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
sn, err = rand.Int(rand.Reader, snLimit)
|
||||
@ -116,6 +133,8 @@ func NewSerialNumber() (sn *big.Int, err error) {
|
||||
return sn, nil
|
||||
}
|
||||
|
||||
// NewSelfSignedCertificateAuthority creates a self-signed CA configured for
|
||||
// server and client authentication.
|
||||
func NewSelfSignedCertificateAuthority(setters ...Option) (ca *CertificateAuthority, err error) {
|
||||
opts := NewDefaultOptions(setters...)
|
||||
|
||||
@ -147,78 +166,12 @@ func NewSelfSignedCertificateAuthority(setters ...Option) (ca *CertificateAuthor
|
||||
return rsaCertificateAuthority(crt, opts)
|
||||
}
|
||||
|
||||
return ecdsaCertificateAuthority(crt, opts)
|
||||
}
|
||||
|
||||
func rsaCertificateAuthority(template *x509.Certificate, opts *Options) (ca *CertificateAuthority, err error) {
|
||||
key, e := rsa.GenerateKey(rand.Reader, opts.Bits)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
keyBytes := x509.MarshalPKCS1PrivateKey(key)
|
||||
keyPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: keyBytes,
|
||||
})
|
||||
crtDER, e := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
crt, err := x509.ParseCertificate(crtDER)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
crtPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: crtDER,
|
||||
})
|
||||
|
||||
ca = &CertificateAuthority{
|
||||
Crt: crt,
|
||||
CrtPEM: crtPEM,
|
||||
Key: key,
|
||||
KeyPEM: keyPEM,
|
||||
}
|
||||
|
||||
return ca, nil
|
||||
}
|
||||
|
||||
func ecdsaCertificateAuthority(template *x509.Certificate, opts *Options) (ca *CertificateAuthority, err error) {
|
||||
key, e := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
keyBytes, e := x509.MarshalECPrivateKey(key)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
keyPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "EC PRIVATE KEY",
|
||||
Bytes: keyBytes,
|
||||
})
|
||||
crtDER, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
crt, err := x509.ParseCertificate(crtDER)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
crtPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: crtDER,
|
||||
})
|
||||
|
||||
ca = &CertificateAuthority{
|
||||
Crt: crt,
|
||||
CrtPEM: crtPEM,
|
||||
Key: key,
|
||||
KeyPEM: keyPEM,
|
||||
}
|
||||
|
||||
return ca, nil
|
||||
return ecdsaCertificateAuthority(crt)
|
||||
}
|
||||
|
||||
// NewCertificateSigningRequest creates a CSR. If the IPAddresses option is not
|
||||
// specified, the CSR will be generated with the default value set in
|
||||
// NewDefaultOptions.
|
||||
func NewCertificateSigningRequest(key *ecdsa.PrivateKey, setters ...Option) (csr *CertificateSigningRequest, err error) {
|
||||
opts := NewDefaultOptions(setters...)
|
||||
|
||||
@ -244,6 +197,7 @@ func NewCertificateSigningRequest(key *ecdsa.PrivateKey, setters ...Option) (csr
|
||||
return csr, err
|
||||
}
|
||||
|
||||
// NewKey generates an ECDSA private key.
|
||||
func NewKey() (key *Key, err error) {
|
||||
keyEC, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||
if err != nil {
|
||||
@ -268,6 +222,8 @@ func NewKey() (key *Key, err error) {
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// NewCertificateFromCSR creates and signs X.509 certificate using the provided
|
||||
// CSR.
|
||||
func NewCertificateFromCSR(ca *x509.Certificate, key *ecdsa.PrivateKey, csr *x509.CertificateRequest, setters ...Option) (crt *Certificate, err error) {
|
||||
opts := NewDefaultOptions(setters...)
|
||||
serialNumber, err := NewSerialNumber()
|
||||
@ -318,6 +274,9 @@ func NewCertificateFromCSR(ca *x509.Certificate, key *ecdsa.PrivateKey, csr *x50
|
||||
return crt, nil
|
||||
}
|
||||
|
||||
// NewKeyPair generates a certificate signed by the provided CA, and an ECDSA
|
||||
// private key. The certifcate and private key are then used to create an
|
||||
// tls.X509KeyPair.
|
||||
func NewKeyPair(ca *x509.Certificate, key *ecdsa.PrivateKey, setters ...Option) (keypair *KeyPair, err error) {
|
||||
csr, err := NewCertificateSigningRequest(key, setters...)
|
||||
if err != nil {
|
||||
@ -345,10 +304,79 @@ func NewKeyPair(ca *x509.Certificate, key *ecdsa.PrivateKey, setters ...Option)
|
||||
}
|
||||
|
||||
// Hash calculates the SHA-256 hash of the Subject Public Key Information (SPKI)
|
||||
// object in an x509 certificate (in DER encoding). It returns the full hash as a
|
||||
// hex encoded string (suitable for passing to Set.Allow).
|
||||
// See https://github.com/kubernetes/kubernetes/blob/f557e0f7e3ee9089769ed3f03187fdd4acbb9ac1/cmd/kubeadm/app/util/pubkeypin/pubkeypin.go
|
||||
// object in an x509 certificate (in DER encoding). It returns the full hash as
|
||||
// a hex encoded string (suitable for passing to Set.Allow). See
|
||||
// https://github.com/kubernetes/kubernetes/blob/f557e0f7e3ee9089769ed3f03187fdd4acbb9ac1/cmd/kubeadm/app/util/pubkeypin/pubkeypin.go
|
||||
func Hash(crt *x509.Certificate) string {
|
||||
spkiHash := sha256.Sum256(crt.RawSubjectPublicKeyInfo)
|
||||
return "sha256" + ":" + strings.ToLower(hex.EncodeToString(spkiHash[:]))
|
||||
}
|
||||
|
||||
func rsaCertificateAuthority(template *x509.Certificate, opts *Options) (ca *CertificateAuthority, err error) {
|
||||
key, e := rsa.GenerateKey(rand.Reader, opts.Bits)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
keyBytes := x509.MarshalPKCS1PrivateKey(key)
|
||||
keyPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: keyBytes,
|
||||
})
|
||||
crtDER, e := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
crt, err := x509.ParseCertificate(crtDER)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
crtPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: crtDER,
|
||||
})
|
||||
|
||||
ca = &CertificateAuthority{
|
||||
Crt: crt,
|
||||
CrtPEM: crtPEM,
|
||||
Key: key,
|
||||
KeyPEM: keyPEM,
|
||||
}
|
||||
|
||||
return ca, nil
|
||||
}
|
||||
|
||||
func ecdsaCertificateAuthority(template *x509.Certificate) (ca *CertificateAuthority, err error) {
|
||||
key, e := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
keyBytes, e := x509.MarshalECPrivateKey(key)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
keyPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "EC PRIVATE KEY",
|
||||
Bytes: keyBytes,
|
||||
})
|
||||
crtDER, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
crt, err := x509.ParseCertificate(crtDER)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
crtPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: crtDER,
|
||||
})
|
||||
|
||||
ca = &CertificateAuthority{
|
||||
Crt: crt,
|
||||
CrtPEM: crtPEM,
|
||||
Key: key,
|
||||
KeyPEM: keyPEM,
|
||||
}
|
||||
|
||||
return ca, nil
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ nameserver {{ $ip }}
|
||||
{{ end }}
|
||||
`
|
||||
|
||||
// Hosts renders a valid /etc/hosts file and writes it to disk.
|
||||
func Hosts(s, hostname, ip string) error {
|
||||
data := struct {
|
||||
IP string
|
||||
@ -52,6 +53,7 @@ func Hosts(s, hostname, ip string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResolvConf renders a valid /etc/resolv.conf file and writes it to disk.
|
||||
func ResolvConf(s string, userdata userdata.UserData) error {
|
||||
tmpl, err := template.New("").Parse(resolvConfTemplate)
|
||||
if err != nil {
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseProcCmdline parses /proc/cmdline and returns a map reprentation of the
|
||||
// kernel parameters.
|
||||
func ParseProcCmdline() (cmdline map[string]string, err error) {
|
||||
cmdline = map[string]string{}
|
||||
cmdlineBytes, err := ioutil.ReadFile("/proc/cmdline")
|
||||
|
@ -54,9 +54,7 @@ func Mount(s string) error {
|
||||
|
||||
// See https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt
|
||||
target = path.Join(s, "/sys/fs/cgroup", memoryCgroup, memoryUseHierarchy)
|
||||
if err := ioutil.WriteFile(target, memoryUseHierarchyContents, memoryUseHierarchyPermissions); err != nil {
|
||||
return err
|
||||
}
|
||||
err := ioutil.WriteFile(target, memoryUseHierarchyContents, memoryUseHierarchyPermissions)
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
// +build linux
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
||||
@ -12,35 +14,15 @@ import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type (
|
||||
// MountPoint represents a linux mount point.
|
||||
MountPoint struct {
|
||||
source string
|
||||
target string
|
||||
fstype string
|
||||
flags uintptr
|
||||
data string
|
||||
}
|
||||
|
||||
// BlockDevice represents the metadata on a block device probed by
|
||||
// libblkid.
|
||||
BlockDevice struct {
|
||||
dev string
|
||||
TYPE string
|
||||
UUID string
|
||||
LABEL string
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
instance struct {
|
||||
special map[string]*MountPoint
|
||||
blockdevices map[string]*MountPoint
|
||||
special map[string]*Point
|
||||
blockdevices map[string]*Point
|
||||
}
|
||||
|
||||
once sync.Once
|
||||
|
||||
special = map[string]*MountPoint{
|
||||
special = map[string]*Point{
|
||||
"dev": {"devtmpfs", "/dev", "devtmpfs", unix.MS_NOSUID, "mode=0755"},
|
||||
"proc": {"proc", "/proc", "proc", unix.MS_NOSUID | unix.MS_NOEXEC | unix.MS_NODEV, ""},
|
||||
"sys": {"sysfs", "/sys", "sysfs", unix.MS_NOSUID | unix.MS_NOEXEC | unix.MS_NODEV, ""},
|
||||
@ -49,15 +31,32 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Point represents a linux mount point.
|
||||
type Point struct {
|
||||
source string
|
||||
target string
|
||||
fstype string
|
||||
flags uintptr
|
||||
data string
|
||||
}
|
||||
|
||||
// BlockDevice represents the metadata on a block device probed by libblkid.
|
||||
type BlockDevice struct {
|
||||
dev string
|
||||
TYPE string
|
||||
UUID string
|
||||
LABEL string
|
||||
}
|
||||
|
||||
// Init initializes the mount points.
|
||||
func Init(s string) error {
|
||||
once.Do(func() {
|
||||
instance = struct {
|
||||
special map[string]*MountPoint
|
||||
blockdevices map[string]*MountPoint
|
||||
special map[string]*Point
|
||||
blockdevices map[string]*Point
|
||||
}{
|
||||
special,
|
||||
map[string]*MountPoint{},
|
||||
map[string]*Point{},
|
||||
}
|
||||
})
|
||||
|
||||
@ -75,16 +74,16 @@ func Init(s string) error {
|
||||
return fmt.Errorf("probe block devices: %s", err.Error())
|
||||
}
|
||||
for _, b := range probed {
|
||||
mountpoint := &MountPoint{
|
||||
mountpoint := &Point{
|
||||
source: b.dev,
|
||||
fstype: b.TYPE,
|
||||
flags: unix.MS_NOATIME,
|
||||
data: "",
|
||||
}
|
||||
switch b.LABEL {
|
||||
case constants.ROOTLabel:
|
||||
case constants.RootPartitionLabel:
|
||||
mountpoint.target = s
|
||||
case constants.DATALabel:
|
||||
case constants.DataPartitionLabel:
|
||||
mountpoint.target = path.Join(s, "var")
|
||||
}
|
||||
|
||||
@ -114,7 +113,7 @@ func Move(s string) error {
|
||||
return fmt.Errorf("move mount point %s to %s: %s", mountpoint.target, target, err.Error())
|
||||
}
|
||||
if label == "dev" {
|
||||
mountpoint = &MountPoint{"devpts", path.Join(s, "/dev/pts"), "devpts", unix.MS_NOSUID | unix.MS_NOEXEC, "ptmxmode=000,mode=620,gid=5"}
|
||||
mountpoint = &Point{"devpts", path.Join(s, "/dev/pts"), "devpts", unix.MS_NOSUID | unix.MS_NOEXEC, "ptmxmode=000,mode=620,gid=5"}
|
||||
if err := os.MkdirAll(mountpoint.target, os.ModeDir); err != nil {
|
||||
return fmt.Errorf("create %s: %s", mountpoint.target, err.Error())
|
||||
}
|
||||
@ -129,11 +128,7 @@ func Move(s string) error {
|
||||
|
||||
// Finalize moves the mount points created in Init, to the new root.
|
||||
func Finalize(s string) error {
|
||||
if err := unix.Mount(s, "/", "", unix.MS_MOVE, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return unix.Mount(s, "/", "", unix.MS_MOVE, "")
|
||||
}
|
||||
|
||||
// Mount moves the mount points created in Init, to the new root.
|
||||
@ -142,7 +137,7 @@ func Mount(s string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
mountpoint, ok := instance.blockdevices[constants.ROOTLabel]
|
||||
mountpoint, ok := instance.blockdevices[constants.RootPartitionLabel]
|
||||
if ok {
|
||||
mountpoint.flags = unix.MS_RDONLY | unix.MS_NOATIME
|
||||
if err := unix.Mount(mountpoint.source, mountpoint.target, mountpoint.fstype, mountpoint.flags, mountpoint.data); err != nil {
|
||||
@ -163,7 +158,7 @@ func Mount(s string) error {
|
||||
return fmt.Errorf("mount %s as shared: %s", mountpoint.target, err.Error())
|
||||
}
|
||||
}
|
||||
mountpoint, ok = instance.blockdevices[constants.DATALabel]
|
||||
mountpoint, ok = instance.blockdevices[constants.DataPartitionLabel]
|
||||
if ok {
|
||||
if err := unix.Mount(mountpoint.source, mountpoint.target, mountpoint.fstype, mountpoint.flags, mountpoint.data); err != nil {
|
||||
return fmt.Errorf("mount %s: %s", mountpoint.target, err.Error())
|
||||
@ -175,13 +170,13 @@ func Mount(s string) error {
|
||||
|
||||
// Unmount unmounts the ROOT and DATA block devices.
|
||||
func Unmount() error {
|
||||
mountpoint, ok := instance.blockdevices[constants.DATALabel]
|
||||
mountpoint, ok := instance.blockdevices[constants.DataPartitionLabel]
|
||||
if ok {
|
||||
if err := unix.Unmount(mountpoint.target, 0); err != nil {
|
||||
return fmt.Errorf("unmount mount point %s: %s", mountpoint.target, err.Error())
|
||||
}
|
||||
}
|
||||
mountpoint, ok = instance.blockdevices[constants.ROOTLabel]
|
||||
mountpoint, ok = instance.blockdevices[constants.RootPartitionLabel]
|
||||
if ok {
|
||||
if err := unix.Unmount(mountpoint.target, 0); err != nil {
|
||||
return fmt.Errorf("unmount mount point %s: %s", mountpoint.target, err.Error())
|
||||
@ -199,7 +194,7 @@ func probe() (b []*BlockDevice, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
if root, ok := arguments[constants.KernelRootFlag]; ok {
|
||||
if root, ok := arguments[constants.KernelParamRoot]; ok {
|
||||
if _, err := os.Stat(root); os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("device does not exist: %s", root)
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ func ip() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Prepare creates the files required by the installed binaries and libraries.
|
||||
func Prepare(s string, userdata userdata.UserData) error {
|
||||
// Create /etc/hosts
|
||||
hostname, err := os.Hostname()
|
||||
|
@ -1,3 +1,5 @@
|
||||
//+build linux
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
@ -15,7 +17,7 @@ import (
|
||||
"github.com/autonomy/dianemo/initramfs/src/init/pkg/constants"
|
||||
servicelog "github.com/autonomy/dianemo/initramfs/src/init/pkg/service/log"
|
||||
"github.com/autonomy/dianemo/initramfs/src/init/pkg/userdata"
|
||||
proto "github.com/autonomy/dianemo/initramfs/src/init/proto"
|
||||
"github.com/autonomy/dianemo/initramfs/src/init/proto"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/kubernetes-incubator/cri-o/client"
|
||||
"golang.org/x/sys/unix"
|
||||
@ -23,6 +25,8 @@ import (
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
// Server implements the proto.DianemoServer interface. It serves as the
|
||||
// concrete type with the required methods.
|
||||
type Server struct {
|
||||
server *grpc.Server
|
||||
port int
|
||||
@ -31,16 +35,23 @@ type Server struct {
|
||||
key string
|
||||
}
|
||||
|
||||
func NewServer(data *userdata.Security) (s *Server, err error) {
|
||||
// NewServer initializes a Server.
|
||||
func NewServer(data *userdata.Security) (s *Server) {
|
||||
s = &Server{
|
||||
port: 50000,
|
||||
ca: data.CA.Crt,
|
||||
crt: data.Identity.Crt,
|
||||
key: data.Identity.Key,
|
||||
}
|
||||
return s, err
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Listen configures TLS for mutual authtentication by loading the CA into a
|
||||
// CertPool and configuring the server's policy for TLS Client Authentication.
|
||||
// Once TLS is configured, the gRPC options are built to make use of the TLS
|
||||
// configuration and the receiver (Server) is registered to the gRPC server.
|
||||
// Finally the gRPC server is started.
|
||||
func (s *Server) Listen() (err error) {
|
||||
var (
|
||||
listener net.Listener
|
||||
@ -97,25 +108,34 @@ func (s *Server) Listen() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Server) Kubeconfig(ctx context.Context, in *empty.Empty) (r *proto.Data, err error) {
|
||||
// Kubeconfig implements the proto.DianemoServer interface. The admin kubeconfig
|
||||
// is generated by kubeadm and placed at /etc/kubernetes/admin.conf. This method
|
||||
// returns the contents of the generated admin.conf and returns it in the
|
||||
// response.
|
||||
func (s *Server) Kubeconfig(ctx context.Context, in *empty.Empty) (data *proto.Data, err error) {
|
||||
fileBytes, err := ioutil.ReadFile("/etc/kubernetes/admin.conf")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r = &proto.Data{
|
||||
data = &proto.Data{
|
||||
Bytes: fileBytes,
|
||||
}
|
||||
|
||||
return
|
||||
return data, err
|
||||
}
|
||||
|
||||
// Processes implements the proto.DianemoServer interface.
|
||||
func (s *Server) Processes(ctx context.Context, in *proto.ProcessesRequest) (r *proto.ProcessesReply, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Dmesg implements the proto.DianemoServer interface. The klogctl syscall is
|
||||
// used to read from the ring buffer at /proc/kmsg by taking the
|
||||
// SYSLOG_ACTION_READ_ALL action. This action reads all messages remaining in
|
||||
// the ring buffer non-destructively.
|
||||
func (s *Server) Dmesg(ctx context.Context, in *empty.Empty) (data *proto.Data, err error) {
|
||||
// Return the size of the kernel ring buffer
|
||||
size, err := unix.Klogctl(constants.SYSLOG_ACTION_SIZE_BUFFER, nil)
|
||||
@ -131,11 +151,13 @@ func (s *Server) Dmesg(ctx context.Context, in *empty.Empty) (data *proto.Data,
|
||||
|
||||
data = &proto.Data{Bytes: buf[:n]}
|
||||
|
||||
return
|
||||
return data, err
|
||||
}
|
||||
|
||||
// Logs implements the proto.DianemoServer interface. Service or container logs
|
||||
// can be requested and the contents of the log file are streamed in chunks.
|
||||
func (s *Server) Logs(r *proto.LogsRequest, l proto.Dianemo_LogsServer) (err error) {
|
||||
var stream chunker.ChunkReader
|
||||
var chunk chunker.ChunkReader
|
||||
if r.Container {
|
||||
// TODO: Use the specified container runtime.
|
||||
cli, e := client.New("/var/run/crio/crio.sock")
|
||||
@ -148,18 +170,20 @@ func (s *Server) Logs(r *proto.LogsRequest, l proto.Dianemo_LogsServer) (err err
|
||||
err = e
|
||||
return
|
||||
}
|
||||
stream = chunker.NewDefaultChunker(info.LogPath)
|
||||
chunk = chunker.NewDefaultChunker(info.LogPath)
|
||||
} else {
|
||||
stream = servicelog.Get(r.Process)
|
||||
if stream == nil {
|
||||
chunk = servicelog.Chunker(r.Process)
|
||||
if chunk == nil {
|
||||
err = fmt.Errorf("no such process: %s", r.Process)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for data := range stream.Read(l.Context()) {
|
||||
l.Send(&proto.Data{Bytes: data})
|
||||
for data := range chunk.Read(l.Context()) {
|
||||
if err = l.Send(&proto.Data{Bytes: data}); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
@ -5,12 +5,15 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// None is a service condition that has no conditions.
|
||||
func None() func() (bool, error) {
|
||||
return func() (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// FileExists is a service condition that checks for the existence of a file
|
||||
// once and only once.
|
||||
func FileExists(file string) func() (bool, error) {
|
||||
return func() (bool, error) {
|
||||
_, err := os.Stat(file)
|
||||
@ -26,6 +29,8 @@ func FileExists(file string) func() (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// WaitForFileExists is a service condition that will wait for the existence of
|
||||
// a file.
|
||||
func WaitForFileExists(file string) func() (bool, error) {
|
||||
return func() (bool, error) {
|
||||
for {
|
||||
|
@ -180,8 +180,11 @@ const crioPolicy = `
|
||||
}
|
||||
`
|
||||
|
||||
// CRIO implements the Service interface. It serves as the concrete type with
|
||||
// the required methods.
|
||||
type CRIO struct{}
|
||||
|
||||
// Pre implements the Service interface.
|
||||
func (p *CRIO) Pre(data userdata.UserData) error {
|
||||
if err := ioutil.WriteFile("/etc/crio/crio.conf", []byte(crioConf), 0644); err != nil {
|
||||
return fmt.Errorf("write crio.conf: %s", err.Error())
|
||||
@ -193,6 +196,7 @@ func (p *CRIO) Pre(data userdata.UserData) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cmd implements the Service interface.
|
||||
func (p *CRIO) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
name = "/bin/crio"
|
||||
args = []string{}
|
||||
@ -200,10 +204,13 @@ func (p *CRIO) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
return name, args
|
||||
}
|
||||
|
||||
// Condition implements the Service interface.
|
||||
func (p *CRIO) Condition(data userdata.UserData) func() (bool, error) {
|
||||
return conditions.None()
|
||||
}
|
||||
|
||||
// Env implements the Service interface.
|
||||
func (p *CRIO) Env() []string { return []string{} }
|
||||
|
||||
// Type implements the Service interface.
|
||||
func (p *CRIO) Type() Type { return Forever }
|
||||
|
@ -5,12 +5,16 @@ import (
|
||||
"github.com/autonomy/dianemo/initramfs/src/init/pkg/userdata"
|
||||
)
|
||||
|
||||
// Docker implements the Service interface. It serves as the concrete type with
|
||||
// the required methods.
|
||||
type Docker struct{}
|
||||
|
||||
// Pre implements the Service interface.
|
||||
func (p *Docker) Pre(data userdata.UserData) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cmd implements the Service interface.
|
||||
func (p *Docker) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
name = "/bin/dockerd"
|
||||
args = []string{
|
||||
@ -27,12 +31,15 @@ func (p *Docker) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
return name, args
|
||||
}
|
||||
|
||||
// Condition implements the Service interface.
|
||||
func (p *Docker) Condition(data userdata.UserData) func() (bool, error) {
|
||||
return conditions.None()
|
||||
}
|
||||
|
||||
// Env implements the Service interface.
|
||||
func (p *Docker) Env() []string {
|
||||
return []string{"DOCKER_NOFILE=1000000"}
|
||||
}
|
||||
|
||||
// Type implements the Service interface.
|
||||
func (p *Docker) Type() Type { return Forever }
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/autonomy/dianemo/initramfs/src/init/pkg/userdata"
|
||||
)
|
||||
|
||||
// MasterConfiguration is the kubeadm manifest for master nodes.
|
||||
const MasterConfiguration = `
|
||||
kind: MasterConfiguration
|
||||
apiVersion: kubeadm.k8s.io/v1alpha1
|
||||
@ -36,6 +37,7 @@ featureGates:
|
||||
CoreDNS: true
|
||||
`
|
||||
|
||||
// NodeConfiguration is the kubeadm manifest for worker nodes.
|
||||
const NodeConfiguration = `
|
||||
kind: NodeConfiguration
|
||||
apiVersion: kubeadm.k8s.io/v1alpha1
|
||||
@ -50,11 +52,12 @@ criSocket: {{ .CRISocket }}
|
||||
nodeName: {{ .NodeName }}
|
||||
`
|
||||
|
||||
// Kubeadm implements the Service interface. It serves as the concrete type with
|
||||
// the required methods.
|
||||
type Kubeadm struct{}
|
||||
|
||||
var cmd string
|
||||
|
||||
func (p *Kubeadm) Pre(data userdata.UserData) error {
|
||||
// Pre implements the Service interface.
|
||||
func (p *Kubeadm) Pre(data userdata.UserData) (err error) {
|
||||
var configuration string
|
||||
if data.Kubernetes.Join {
|
||||
configuration = NodeConfiguration
|
||||
@ -62,63 +65,28 @@ func (p *Kubeadm) Pre(data userdata.UserData) error {
|
||||
configuration = MasterConfiguration
|
||||
}
|
||||
|
||||
var criSocket string
|
||||
var socket string
|
||||
switch data.Kubernetes.ContainerRuntime {
|
||||
case constants.ContainerRuntimeDocker:
|
||||
criSocket = constants.ContainerRuntimeDockerSocket
|
||||
socket = constants.ContainerRuntimeDockerSocket
|
||||
case constants.ContainerRuntimeCRIO:
|
||||
criSocket = constants.ContainerRuntimeCRIOSocket
|
||||
socket = constants.ContainerRuntimeCRIOSocket
|
||||
}
|
||||
|
||||
aux := struct {
|
||||
*userdata.Kubernetes
|
||||
CRISocket string
|
||||
}{
|
||||
data.Kubernetes,
|
||||
criSocket,
|
||||
}
|
||||
|
||||
tmpl, err := template.New("").Parse(configuration)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var buf []byte
|
||||
writer := bytes.NewBuffer(buf)
|
||||
err = tmpl.Execute(writer, aux)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(constants.KubeadmConfig, writer.Bytes(), 0400); err != nil {
|
||||
return fmt.Errorf("write %s: %s", constants.KubeadmConfig, err.Error())
|
||||
if err = writeKubeadmManifest(data.Kubernetes, configuration, socket); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !data.Kubernetes.Join {
|
||||
caCrtBytes, err := base64.StdEncoding.DecodeString(data.Kubernetes.CA.Crt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(path.Dir(constants.KubeadmCACert), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(constants.KubeadmCACert, caCrtBytes, 0400); err != nil {
|
||||
return fmt.Errorf("write %s: %s", constants.KubeadmCACert, err.Error())
|
||||
}
|
||||
caKeyBytes, err := base64.StdEncoding.DecodeString(data.Kubernetes.CA.Key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(path.Dir(constants.KubeadmCAKey), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(constants.KubeadmCAKey, caKeyBytes, 0400); err != nil {
|
||||
return fmt.Errorf("write %s: %s", constants.KubeadmCAKey, err.Error())
|
||||
if err = writeKubeadmPKIFiles(data.Kubernetes); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cmd implements the Service interface.
|
||||
func (p *Kubeadm) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
var cmd string
|
||||
if data.Kubernetes.Join {
|
||||
@ -136,6 +104,7 @@ func (p *Kubeadm) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
return name, args
|
||||
}
|
||||
|
||||
// Condition implements the Service interface.
|
||||
func (p *Kubeadm) Condition(data userdata.UserData) func() (bool, error) {
|
||||
switch data.Kubernetes.ContainerRuntime {
|
||||
case constants.ContainerRuntimeDocker:
|
||||
@ -147,6 +116,61 @@ func (p *Kubeadm) Condition(data userdata.UserData) func() (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Env implements the Service interface.
|
||||
func (p *Kubeadm) Env() []string { return []string{} }
|
||||
|
||||
// Type implements the Service interface.
|
||||
func (p *Kubeadm) Type() Type { return Once }
|
||||
|
||||
func writeKubeadmManifest(data *userdata.Kubernetes, configuration, socket string) (err error) {
|
||||
aux := struct {
|
||||
*userdata.Kubernetes
|
||||
CRISocket string
|
||||
}{
|
||||
data,
|
||||
socket,
|
||||
}
|
||||
|
||||
tmpl, err := template.New("").Parse(configuration)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var buf []byte
|
||||
writer := bytes.NewBuffer(buf)
|
||||
err = tmpl.Execute(writer, aux)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(constants.KubeadmConfig, writer.Bytes(), 0400); err != nil {
|
||||
return fmt.Errorf("write %s: %s", constants.KubeadmConfig, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeKubeadmPKIFiles(data *userdata.Kubernetes) (err error) {
|
||||
caCrtBytes, err := base64.StdEncoding.DecodeString(data.CA.Crt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = os.MkdirAll(path.Dir(constants.KubeadmCACert), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = ioutil.WriteFile(constants.KubeadmCACert, caCrtBytes, 0400); err != nil {
|
||||
return fmt.Errorf("write %s: %s", constants.KubeadmCACert, err.Error())
|
||||
}
|
||||
|
||||
caKeyBytes, err := base64.StdEncoding.DecodeString(data.CA.Key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = os.MkdirAll(path.Dir(constants.KubeadmCAKey), 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = ioutil.WriteFile(constants.KubeadmCAKey, caKeyBytes, 0400); err != nil {
|
||||
return fmt.Errorf("write %s: %s", constants.KubeadmCAKey, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -9,8 +9,11 @@ import (
|
||||
"github.com/autonomy/dianemo/initramfs/src/init/pkg/userdata"
|
||||
)
|
||||
|
||||
// Kubelet implements the Service interface. It serves as the concrete type with
|
||||
// the required methods.
|
||||
type Kubelet struct{}
|
||||
|
||||
// Pre implements the Service interface.
|
||||
func (p *Kubelet) Pre(data userdata.UserData) error {
|
||||
if err := os.Mkdir("/run/flannel", os.ModeDir); err != nil {
|
||||
return fmt.Errorf("create /run/flannel: %s", err.Error())
|
||||
@ -25,6 +28,7 @@ func (p *Kubelet) Pre(data userdata.UserData) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cmd implements the Service interface.
|
||||
func (p *Kubelet) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
name = "/bin/kubelet"
|
||||
args = []string{
|
||||
@ -65,6 +69,7 @@ func (p *Kubelet) Cmd(data userdata.UserData) (name string, args []string) {
|
||||
return name, args
|
||||
}
|
||||
|
||||
// Condition implements the Service interface.
|
||||
func (p *Kubelet) Condition(data userdata.UserData) func() (bool, error) {
|
||||
switch data.Kubernetes.ContainerRuntime {
|
||||
case constants.ContainerRuntimeDocker:
|
||||
@ -76,6 +81,8 @@ func (p *Kubelet) Condition(data userdata.UserData) func() (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Env implements the Service interface.
|
||||
func (p *Kubelet) Env() []string { return []string{} }
|
||||
|
||||
// Type implements the Service interface.
|
||||
func (p *Kubelet) Type() Type { return Forever }
|
||||
|
@ -14,12 +14,15 @@ import (
|
||||
var instance = map[string]*Log{}
|
||||
var mu = &sync.Mutex{}
|
||||
|
||||
// Log represents the log of a service. It supports streaming of the contents of
|
||||
// the log file by way of implementing the chunker.Chunker interface.
|
||||
type Log struct {
|
||||
Name string
|
||||
Path string
|
||||
writeCloser io.WriteCloser
|
||||
}
|
||||
|
||||
// New initializes and registers a log for a service.
|
||||
func New(name string) (*Log, error) {
|
||||
if l, ok := instance[name]; ok {
|
||||
return l, nil
|
||||
@ -43,7 +46,8 @@ func New(name string) (*Log, error) {
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func Get(name string) chunker.Chunker {
|
||||
// Chunker returns a chunker.Chunker implementation.
|
||||
func Chunker(name string) chunker.Chunker {
|
||||
if l, ok := instance[name]; ok {
|
||||
return l
|
||||
}
|
||||
@ -51,14 +55,17 @@ func Get(name string) chunker.Chunker {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write implements io.WriteCloser.
|
||||
func (l *Log) Write(p []byte) (n int, err error) {
|
||||
return l.writeCloser.Write(p)
|
||||
}
|
||||
|
||||
// Close implements io.WriteCloser.
|
||||
func (l *Log) Close() error {
|
||||
return l.writeCloser.Close()
|
||||
}
|
||||
|
||||
// Read implements chunker.Chunker.
|
||||
func (l *Log) Read(ctx context.Context) <-chan []byte {
|
||||
c := chunker.NewDefaultChunker(l.Path)
|
||||
return c.Read(ctx)
|
||||
|
@ -12,34 +12,53 @@ import (
|
||||
"github.com/autonomy/dianemo/initramfs/src/init/pkg/userdata"
|
||||
)
|
||||
|
||||
// Type represents the service's restart policy.
|
||||
type Type int
|
||||
|
||||
const (
|
||||
// Forever will always restart a process.
|
||||
Forever Type = iota
|
||||
// Once will restart the process only if it did not exit successfully.
|
||||
Once
|
||||
OnceAndOnlyOnce
|
||||
)
|
||||
|
||||
// Service is an interface describing a process that is to be run as a system
|
||||
// level service.
|
||||
type Service interface {
|
||||
// Pre is invoked before a command is executed. It is useful for things like
|
||||
// preparing files that the process might depend on.
|
||||
Pre(userdata.UserData) error
|
||||
// Cmd describes the path to the binary, and the set of arguments to be
|
||||
// passed into it upon execution.
|
||||
Cmd(userdata.UserData) (string, []string)
|
||||
// Condition is invoked just before starting the process.
|
||||
Condition(userdata.UserData) func() (bool, error)
|
||||
// Env describes the service's environment variables. Elements should be in
|
||||
// the format <key=<value>
|
||||
Env() []string
|
||||
// Type describes the service's restart policy.
|
||||
Type() Type
|
||||
}
|
||||
|
||||
// Manager is a type with helper methods that build a service and invoke the set
|
||||
// of methods defined in the Service interface.
|
||||
type Manager struct {
|
||||
UserData userdata.UserData
|
||||
}
|
||||
|
||||
func (m *Manager) build(proc Service) (*exec.Cmd, error) {
|
||||
func (m *Manager) build(proc Service) (cmd *exec.Cmd, err error) {
|
||||
// Build the exec.Cmd
|
||||
name, args := proc.Cmd(m.UserData)
|
||||
cmd := exec.Command(name, args...)
|
||||
cmd = exec.Command(name, args...)
|
||||
|
||||
// Set the environment for the service.
|
||||
cmd.Env = append(proc.Env(), fmt.Sprintf("PATH=%s", constants.PATH))
|
||||
|
||||
// Setup logging.
|
||||
w, err := servicelog.New(path.Base(name))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("service log handler: %s", err.Error())
|
||||
err = fmt.Errorf("service log handler: %s", err.Error())
|
||||
return
|
||||
}
|
||||
cmd.Stdout = w
|
||||
cmd.Stderr = w
|
||||
@ -47,6 +66,9 @@ func (m *Manager) build(proc Service) (*exec.Cmd, error) {
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
// Start will invoke the service's Pre, Condition, and Type funcs. If the any
|
||||
// error occurs in the Pre or Condition invocations, it is up to the caller to
|
||||
// to restart the service.
|
||||
func (m *Manager) Start(proc Service) {
|
||||
go func(proc Service) {
|
||||
err := proc.Pre(m.UserData)
|
||||
@ -63,7 +85,7 @@ func (m *Manager) Start(proc Service) {
|
||||
return
|
||||
}
|
||||
// Wait for the command to exit. Then, based on the service Type, take
|
||||
// the appropriate actions.
|
||||
// the requested action.
|
||||
switch proc.Type() {
|
||||
case Forever:
|
||||
if err := m.waitAndRestart(proc); err != nil {
|
||||
@ -77,17 +99,17 @@ func (m *Manager) Start(proc Service) {
|
||||
}(proc)
|
||||
}
|
||||
|
||||
func (m *Manager) waitAndRestart(proc Service) error {
|
||||
func (m *Manager) waitAndRestart(proc Service) (err error) {
|
||||
cmd, err := m.build(proc)
|
||||
if err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
if err = cmd.Start(); err != nil {
|
||||
return
|
||||
}
|
||||
state, err := cmd.Process.Wait()
|
||||
if err != nil {
|
||||
// TODO: Write the error to the log writer.
|
||||
return
|
||||
}
|
||||
if state.Exited() {
|
||||
time.Sleep(5 * time.Second)
|
||||
@ -97,17 +119,17 @@ func (m *Manager) waitAndRestart(proc Service) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) waitForSuccess(proc Service) error {
|
||||
func (m *Manager) waitForSuccess(proc Service) (err error) {
|
||||
cmd, err := m.build(proc)
|
||||
if err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
if err = cmd.Start(); err != nil {
|
||||
return
|
||||
}
|
||||
state, err := cmd.Process.Wait()
|
||||
if err != nil {
|
||||
// TODO: Write the error to the log writer.
|
||||
return
|
||||
}
|
||||
if !state.Success() {
|
||||
time.Sleep(5 * time.Second)
|
||||
|
@ -1,3 +1,5 @@
|
||||
// +build linux
|
||||
|
||||
package switchroot
|
||||
|
||||
import (
|
||||
@ -16,9 +18,10 @@ func recursiveDelete(fd int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// The file descriptor is already open, but allocating a os.File
|
||||
// here makes reading the files in the dir so much nicer.
|
||||
// The file descriptor is already open, but allocating a os.File here makes
|
||||
// reading the files in the dir so much nicer.
|
||||
dir := os.NewFile(uintptr(fd), "__ignored__")
|
||||
// nolint: errcheck
|
||||
defer dir.Close()
|
||||
names, err := dir.Readdirnames(-1)
|
||||
if err != nil {
|
||||
@ -26,7 +29,8 @@ func recursiveDelete(fd int) error {
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
// Loop here, but handle loop in separate function to make defer work as expected.
|
||||
// Loop here, but handle loop in separate function to make defer work as
|
||||
// expected.
|
||||
if err := recusiveDeleteInner(fd, parentDev, name); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -35,8 +39,9 @@ func recursiveDelete(fd int) error {
|
||||
}
|
||||
|
||||
func recusiveDeleteInner(parentFd int, parentDev uint64, childName string) error {
|
||||
// O_DIRECTORY and O_NOFOLLOW make this open fail for all files and all symlinks (even when pointing to a dir).
|
||||
// We need to filter out symlinks because getDev later follows them.
|
||||
// O_DIRECTORY and O_NOFOLLOW make this open fail for all files and all
|
||||
// symlinks (even when pointing to a dir). We need to filter out symlinks
|
||||
// because getDev later follows them.
|
||||
childFd, err := unix.Openat(parentFd, childName, unix.O_DIRECTORY|unix.O_NOFOLLOW, unix.O_RDWR)
|
||||
if err != nil {
|
||||
// childName points to either a file or a symlink, delete in any case.
|
||||
@ -45,6 +50,7 @@ func recusiveDeleteInner(parentFd int, parentDev uint64, childName string) error
|
||||
}
|
||||
} else {
|
||||
// Open succeeded, which means childName points to a real directory.
|
||||
// nolint: errcheck
|
||||
defer unix.Close(childFd)
|
||||
|
||||
// Don't descent into other file systems.
|
||||
@ -76,7 +82,8 @@ func getDev(fd int) (dev uint64, err error) {
|
||||
return stat.Dev, nil
|
||||
}
|
||||
|
||||
// See https://github.com/karelzak/util-linux/blob/master/sys-utils/switch_root.c
|
||||
// Switch performs a switch_root equivalent. See
|
||||
// https://github.com/karelzak/util-linux/blob/master/sys-utils/switch_root.c
|
||||
func Switch(s string) error {
|
||||
// Mount the ROOT and DATA block devices at the new root.
|
||||
if err := mount.Mount(s); err != nil {
|
||||
@ -97,6 +104,7 @@ func Switch(s string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// nolint: errcheck
|
||||
defer oldRoot.Close()
|
||||
if err := mount.Finalize(s); err != nil {
|
||||
return err
|
||||
|
@ -17,37 +17,45 @@ type UserData struct {
|
||||
Kubernetes *Kubernetes `yaml:"kubernetes,omitempty"`
|
||||
}
|
||||
|
||||
// OS represents the operating system specific configuration options.
|
||||
type OS struct {
|
||||
Network *Network `yaml:"network,omitempty"`
|
||||
Security *Security `yaml:"security"`
|
||||
}
|
||||
|
||||
// Network represents the operating system networking specific configuration
|
||||
// options.
|
||||
type Network struct {
|
||||
Nameservers []string `yaml:"nameservers,omitempty"`
|
||||
}
|
||||
|
||||
// Security represents the operating system security specific configuration
|
||||
// options.
|
||||
type Security struct {
|
||||
CA *KeyPair `yaml:"ca"`
|
||||
Identity *KeyPair `yaml:"identity"`
|
||||
CA *CertificateAndKeyPaths `yaml:"ca"`
|
||||
Identity *CertificateAndKeyPaths `yaml:"identity"`
|
||||
}
|
||||
|
||||
type KeyPair struct {
|
||||
// CertificateAndKeyPaths represents the paths to the certificate and private
|
||||
// key.
|
||||
type CertificateAndKeyPaths struct {
|
||||
Crt string `yaml:"crt"`
|
||||
Key string `yaml:"key"`
|
||||
}
|
||||
|
||||
// Kubernetes represents the Kubernetes specific configuration options.
|
||||
type Kubernetes struct {
|
||||
CA *KeyPair `yaml:"ca,omitempty"`
|
||||
Token string `yaml:"token"`
|
||||
Join bool `yaml:"join,omitempty"`
|
||||
APIServer string `yaml:"apiServer,omitempty"`
|
||||
NodeName string `yaml:"nodeName,omitempty"`
|
||||
Labels map[string]string `yaml:"labels,omitempty"`
|
||||
ContainerRuntime string `yaml:"containerRuntime,omitempty"`
|
||||
DiscoveryTokenCACertHashes []string `yaml:"discoveryTokenCACertHashes,omitempty"`
|
||||
CA *CertificateAndKeyPaths `yaml:"ca,omitempty"`
|
||||
Token string `yaml:"token"`
|
||||
Join bool `yaml:"join,omitempty"`
|
||||
APIServer string `yaml:"apiServer,omitempty"`
|
||||
NodeName string `yaml:"nodeName,omitempty"`
|
||||
Labels map[string]string `yaml:"labels,omitempty"`
|
||||
ContainerRuntime string `yaml:"containerRuntime,omitempty"`
|
||||
DiscoveryTokenCACertHashes []string `yaml:"discoveryTokenCACertHashes,omitempty"`
|
||||
}
|
||||
|
||||
// Download downloads the user data and executes the instructions.
|
||||
// Download initializes a UserData struct from a remote URL.
|
||||
func Download() (UserData, error) {
|
||||
userData := UserData{}
|
||||
|
||||
@ -55,7 +63,7 @@ func Download() (UserData, error) {
|
||||
if err != nil {
|
||||
return userData, fmt.Errorf("parse kernel parameters: %s", err.Error())
|
||||
}
|
||||
url, ok := arguments[constants.UserDataURLFlag]
|
||||
url, ok := arguments[constants.KernelParamUserData]
|
||||
if !ok {
|
||||
return userData, nil
|
||||
}
|
||||
@ -64,6 +72,7 @@ func Download() (UserData, error) {
|
||||
if err != nil {
|
||||
return userData, err
|
||||
}
|
||||
// nolint: errcheck
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
|
@ -17,7 +17,6 @@ metadata:
|
||||
srcFindutils: http://ftp.gnu.org/gnu/findutils/findutils-4.6.0.tar.gz
|
||||
srcGlib2: http://ftp.gnome.org/pub/gnome/sources/glib/2.56/glib-2.56.0.tar.xz
|
||||
srcGlibc: http://ftp.gnu.org/gnu/glibc/glibc-2.26.tar.xz
|
||||
srcGo: https://dl.google.com/go/go1.10.linux-amd64.tar.gz
|
||||
srcGPGME: https://www.gnupg.org/ftp/gcrypt/gpgme/gpgme-1.10.0.tar.bz2
|
||||
srcIproute2: https://www.kernel.org/pub/linux/utils/net/iproute2/iproute2-4.15.0.tar.xz
|
||||
srcKubeadm: https://storage.googleapis.com/kubernetes-release/release/v1.10.2/bin/linux/amd64/kubeadm
|
||||
@ -79,15 +78,11 @@ stages:
|
||||
- docker
|
||||
- kubernetes
|
||||
- etc
|
||||
- cleanup
|
||||
rootfs:
|
||||
tasks:
|
||||
- rootfs
|
||||
tasks:
|
||||
docker:
|
||||
template: |
|
||||
WORKDIR {{ index .Variables "rootfs" }}/bin
|
||||
RUN curl -L {{ index .Variables "srcDocker" }} | tar --strip-components=1 -xz \
|
||||
&& rm docker
|
||||
btrfs-progs:
|
||||
template: |
|
||||
WORKDIR {{ index .Variables "dest" }}/{{ .Docker.CurrentStage }}
|
||||
@ -104,6 +99,11 @@ tasks:
|
||||
template: |
|
||||
RUN mkdir -p {{ index .Variables "rootfs" }}/etc/ssl/certs
|
||||
RUN curl -o {{ index .Variables "rootfs" }}/etc/ssl/certs/ca-certificates.crt https://curl.haxx.se/ca/cacert.pem
|
||||
cleanup:
|
||||
template: |
|
||||
COPY src/cleanup.sh /bin/cleanup.sh
|
||||
RUN chmod +x /bin/cleanup.sh
|
||||
RUN /bin/cleanup.sh
|
||||
conntrack-tools:
|
||||
template: |
|
||||
WORKDIR {{ index .Variables "dest" }}/{{ .Docker.CurrentStage }}
|
||||
@ -129,9 +129,9 @@ tasks:
|
||||
cri-o:
|
||||
template: |
|
||||
WORKDIR {{ index .Variables "dest" }}/{{ .Docker.CurrentStage }}
|
||||
RUN curl -L {{ index .Variables "srcGo" }} | tar -C /tools/usr/local -xz
|
||||
ENV PATH $PATH:/tools/usr/local/go/bin
|
||||
ENV GOPATH {{ index .Variables "dest" }}
|
||||
ENV GOROOT /tools/usr/local/go
|
||||
ENV GOPATH /tools/go
|
||||
ENV PATH $PATH:$GOROOT/bin:$GOPATH/bin
|
||||
RUN curl -L {{ index .Variables "srcCRITools" }} | tar -xz -C {{ index .Variables "rootfs" }}/bin
|
||||
RUN curl -L {{ index .Variables "srcCRIO" }} | tar --strip-components=1 -xz
|
||||
RUN ln -s {{ index .Variables "rootfs" }}/etc/ssl /etc/ssl
|
||||
@ -139,6 +139,11 @@ tasks:
|
||||
RUN mkdir bin
|
||||
RUN make -j $(($(nproc) / 2)) BUILDTAGS=""
|
||||
RUN make install install.config
|
||||
docker:
|
||||
template: |
|
||||
WORKDIR {{ index .Variables "rootfs" }}/bin
|
||||
RUN curl -L {{ index .Variables "srcDocker" }} | tar --strip-components=1 -xz \
|
||||
&& rm docker
|
||||
ebtables:
|
||||
template: |
|
||||
WORKDIR {{ index .Variables "dest" }}/{{ .Docker.CurrentStage }}
|
||||
@ -394,9 +399,6 @@ tasks:
|
||||
FROM alpine:3.7 AS {{ .Docker.CurrentStage }}
|
||||
COPY --from={{ .Repository }}:build-phase-2 {{ index .Variables "rootfs" }} {{ index .Variables "rootfs" }}
|
||||
RUN apk --update add bash
|
||||
COPY src/cleanup.sh /bin/cleanup.sh
|
||||
RUN chmod +x /bin/cleanup.sh
|
||||
RUN /bin/cleanup.sh
|
||||
FROM scratch
|
||||
LABEL maintainer="Andrew Rynhard <andrew.rynhard@autonomy.io>"
|
||||
COPY --from={{ .Docker.CurrentStage }} {{ index .Variables "rootfs" }} {{ index .Variables "rootfs" }}
|
||||
|
@ -9,6 +9,7 @@ metadata:
|
||||
srcBzip2: http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz
|
||||
srcCheck: https://github.com/libcheck/check/releases/download/0.12.0/check-0.12.0.tar.gz
|
||||
srcCoreutils: http://ftp.gnu.org/gnu/coreutils/coreutils-8.27.tar.xz
|
||||
srcCPIO: https://ftp.gnu.org/gnu/cpio/cpio-2.12.tar.gz
|
||||
srcCurl: https://curl.haxx.se/download/curl-7.56.1.tar.xz
|
||||
srcDejagnu: http://ftp.gnu.org/gnu/dejagnu/dejagnu-1.6.1.tar.gz
|
||||
srcDiffutils: http://ftp.gnu.org/gnu/diffutils/diffutils-3.6.tar.xz
|
||||
@ -26,6 +27,7 @@ metadata:
|
||||
srcGit: https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.16.2.tar.xz
|
||||
srcGlibc: http://ftp.gnu.org/gnu/glibc/glibc-2.26.tar.xz
|
||||
srcGmp: http://ftp.gnu.org/gnu/gmp/gmp-6.1.2.tar.xz
|
||||
srcGo: https://dl.google.com/go/go1.10.linux-amd64.tar.gz
|
||||
srcGperf: http://ftp.gnu.org/gnu/gperf/gperf-3.0.4.tar.gz
|
||||
srcGrep: http://ftp.gnu.org/gnu/grep/grep-3.1.tar.xz
|
||||
srcGzip: http://ftp.gnu.org/gnu/gzip/gzip-1.8.tar.xz
|
||||
@ -145,6 +147,8 @@ stages:
|
||||
- kmod
|
||||
- autoconf
|
||||
- git
|
||||
- cpio
|
||||
- golang
|
||||
tasks:
|
||||
autoconf:
|
||||
template: |
|
||||
@ -258,6 +262,15 @@ tasks:
|
||||
--enable-install-program=hostname
|
||||
RUN make -j $(($(nproc) / 2))
|
||||
RUN make install
|
||||
cpio:
|
||||
template: |
|
||||
WORKDIR $SRC/{{ .Docker.CurrentStage }}
|
||||
RUN curl -L {{ index .Variables "srcCPIO" }} | tar --strip-components=1 -xz
|
||||
WORKDIR build
|
||||
RUN ../configure \
|
||||
--prefix=$PREFIX
|
||||
RUN make
|
||||
RUN make install
|
||||
curl:
|
||||
template: |
|
||||
RUN mkdir -p /tools/etc/ssl/certs
|
||||
@ -493,6 +506,11 @@ tasks:
|
||||
RUN $TARGET-gcc dummy.c
|
||||
RUN readelf -l a.out | grep "$PREFIX"
|
||||
RUN rm -v dummy.c a.out
|
||||
golang:
|
||||
template: |
|
||||
WORKDIR $SRC/{{ .Docker.CurrentStage }}
|
||||
WORKDIR /tools/usr/local
|
||||
RUN curl -L {{ index .Variables "srcGo" }} | tar -C /tools/usr/local -xz
|
||||
gmp:
|
||||
template: |
|
||||
WORKDIR $SRC/{{ .Docker.CurrentStage }}
|
||||
@ -808,7 +826,11 @@ tasks:
|
||||
RUN [ "/tools/bin/bash", "-c", "rm -rf /tools/share/info /tools/share/man /tools/share/doc" ]
|
||||
FROM scratch
|
||||
COPY --from={{ .Docker.CurrentStage }} /tools /tools
|
||||
ENV GOROOT /tools/usr/local/go
|
||||
ENV GOPATH /tools/go
|
||||
ENV PATH /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/tools/bin
|
||||
ENV PATH $PATH:$GOROOT/bin:$GOPATH/bin
|
||||
RUN [ "mkdir", "/tools/go" ]
|
||||
RUN [ "mkdir", "/bin" ]
|
||||
RUN [ "ln", "-s", "/tools/bin/bash", "/bin/sh" ]
|
||||
RUN [ "ln", "-s", "/tools/bin/bash", "/bin/bash" ]
|
||||
|
Loading…
x
Reference in New Issue
Block a user