diff --git a/Dockerfile b/Dockerfile index 32ad81f99..b81b690db 100644 --- a/Dockerfile +++ b/Dockerfile @@ -93,6 +93,8 @@ COPY ./api/cluster/cluster.proto /api/cluster/cluster.proto RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api cluster/cluster.proto COPY ./api/resource/resource.proto /api/resource/resource.proto RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api resource/resource.proto +COPY ./api/inspect/inspect.proto /api/inspect/inspect.proto +RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api inspect/inspect.proto # Gofumports generated files to adjust import order RUN gofumports -w -local github.com/talos-systems/talos /api/ @@ -112,6 +114,7 @@ COPY --from=generate-build /api/network/*.pb.go /pkg/machinery/api/network/ COPY --from=generate-build /api/cluster/*.pb.go /pkg/machinery/api/cluster/ COPY --from=generate-build /api/storage/*.pb.go /pkg/machinery/api/storage/ COPY --from=generate-build /api/resource/*.pb.go /pkg/machinery/api/resource/ +COPY --from=generate-build /api/inspect/*.pb.go /pkg/machinery/api/inspect/ COPY --from=generate-build /pkg/machinery/config/types/v1alpha1/*_doc.go /pkg/machinery/config/types/v1alpha1/ # The base target provides a container that can be used to build all Talos @@ -268,27 +271,6 @@ RUN printf "FROM scratch\nCOPY ./routerd /routerd\nENTRYPOINT [\"/routerd\"]" > RUN --security=insecure img build --tag ${USERNAME}/routerd:${TAG} --output type=docker,dest=/routerd.tar --no-console . -# The bootkube target builds the bootkube image. - -FROM base AS bootkube-build -ARG SHA -ARG TAG -ARG PKGS -ARG EXTRAS -ARG VERSION_PKG="github.com/talos-systems/talos/pkg/version" -WORKDIR /src/internal/app/bootkube -RUN --mount=type=cache,target=/.cache/go-build go build -ldflags "-s -w -X ${VERSION_PKG}.Name=Server -X ${VERSION_PKG}.SHA=${SHA} -X ${VERSION_PKG}.Tag=${TAG} -X ${VERSION_PKG}.PkgsVersion=${PKGS} -X ${VERSION_PKG}.ExtrasVersion=${EXTRAS}" -o /bootkube -RUN chmod +x /bootkube - -FROM base AS bootkube-image -ARG TAG -ARG USERNAME -COPY --from=bootkube-build /bootkube /scratch/bootkube -WORKDIR /scratch -RUN printf "FROM scratch\nCOPY ./bootkube /bootkube\nENTRYPOINT [\"/bootkube\"]" > Dockerfile -RUN --security=insecure img build --tag ${USERNAME}/bootkube:${TAG} --output type=docker,dest=/bootkube.tar --no-console . - - # The talosctl targets build the talosctl binaries. FROM base AS talosctl-linux-amd64-build @@ -392,7 +374,6 @@ COPY --from=pkg-kmod /usr/lib/libkmod.* /rootfs/lib/ COPY --from=pkg-kernel /lib/modules /rootfs/lib/modules COPY --from=machined /machined /rootfs/sbin/init COPY --from=apid-image /apid.tar /rootfs/usr/images/ -COPY --from=bootkube-image /bootkube.tar /rootfs/usr/images/ COPY --from=timed-image /timed.tar /rootfs/usr/images/ COPY --from=trustd-image /trustd.tar /rootfs/usr/images/ COPY --from=networkd-image /networkd.tar /rootfs/usr/images/ @@ -645,6 +626,7 @@ RUN protoc \ -I/protos \ -I/protos/common \ -I/protos/health \ + -I/protos/inspect \ -I/protos/machine \ -I/protos/network \ -I/protos/resource \ @@ -656,6 +638,7 @@ RUN protoc \ --doc_out=/tmp \ /protos/common/*.proto \ /protos/health/*.proto \ + /protos/inspect/*.proto \ /protos/machine/*.proto \ /protos/network/*.proto \ /protos/resource/*.proto \ diff --git a/api/inspect/inspect.proto b/api/inspect/inspect.proto new file mode 100644 index 000000000..821ebd124 --- /dev/null +++ b/api/inspect/inspect.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; + +package inspect; + +option go_package = "github.com/talos-systems/talos/pkg/machinery/api/inspect"; +option java_multiple_files = true; +option java_outer_classname = "InspectApi"; +option java_package = "com.inspect.api"; + +import "google/protobuf/empty.proto"; +import "common/common.proto"; + +// The inspect service definition. +// +// InspectService provides auxilary API to inspect OS internals. +service InspectService { + rpc ControllerRuntimeDependencies(google.protobuf.Empty) returns (ControllerRuntimeDependenciesResponse); +} + +// The ControllerRuntimeDependency message contains the graph of controller-resource dependencies. +message ControllerRuntimeDependency { + common.Metadata metadata = 1; + repeated ControllerDependencyEdge edges = 2; +} + +message ControllerRuntimeDependenciesResponse { repeated ControllerRuntimeDependency messages = 1; } + +enum DependencyEdgeType { + MANAGES = 0; + STRONG = 1; + WEAK = 2; +} + +message ControllerDependencyEdge { + string controller_name = 1; + + DependencyEdgeType edge_type = 2; + + string resource_namespace = 3; + string resource_type = 4; + string resource_id = 5; +} diff --git a/api/machine/machine.proto b/api/machine/machine.proto index 2cd9bdbb7..d3f6722a7 100644 --- a/api/machine/machine.proto +++ b/api/machine/machine.proto @@ -126,6 +126,7 @@ message ServiceStateEvent { }; Action action = 2; string message = 3; + ServiceHealth health = 4; }; message EventsRequest { diff --git a/cmd/talosctl/cmd/talos/images.go b/cmd/talosctl/cmd/talos/images.go index 6d03dfedc..185940086 100644 --- a/cmd/talosctl/cmd/talos/images.go +++ b/cmd/talosctl/cmd/talos/images.go @@ -9,8 +9,7 @@ import ( "github.com/spf13/cobra" - "github.com/talos-systems/talos/internal/app/bootkube/images" - imagespkg "github.com/talos-systems/talos/pkg/images" + "github.com/talos-systems/talos/pkg/images" "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1" ) @@ -44,8 +43,8 @@ var imagesCmd = &cobra.Command{ fmt.Printf("%s\n", images.KubeScheduler) fmt.Printf("%s\n", images.KubeProxy) fmt.Printf("%s\n", images.Kubelet) - fmt.Printf("%s\n", images.PodCheckpointer) - fmt.Printf("%s\n", imagespkg.DefaultInstallerImage) + fmt.Printf("%s\n", images.Installer) + fmt.Printf("%s\n", images.Pause) return nil }, diff --git a/cmd/talosctl/cmd/talos/inspect.go b/cmd/talosctl/cmd/talos/inspect.go new file mode 100644 index 000000000..1c9e3c736 --- /dev/null +++ b/cmd/talosctl/cmd/talos/inspect.go @@ -0,0 +1,185 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package talos + +import ( + "context" + "fmt" + "io" + "os" + + "github.com/emicklei/dot" + "github.com/spf13/cobra" + "github.com/talos-systems/os-runtime/pkg/resource" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/talos-systems/talos/cmd/talosctl/pkg/talos/helpers" + "github.com/talos-systems/talos/pkg/cli" + "github.com/talos-systems/talos/pkg/machinery/api/inspect" + "github.com/talos-systems/talos/pkg/machinery/client" +) + +// inspectCmd represents the inspect command. +var inspectCmd = &cobra.Command{ + Use: "inspect", + Short: "Inspect internals of Talos", + Long: ``, +} + +var inspectDependenciesCmdFlags struct { + withResources bool +} + +// inspectDependenciesCmd represents the inspect dependencies command. +var inspectDependenciesCmd = &cobra.Command{ + Use: "dependencies", + Short: "Inspect controller-resource dependencies as graphviz graph.", + Long: `Inspect controller-resource dependencies as graphviz graph. + +Pipe the output of the command through the "dot" program (part of graphviz package) +to render the graph: + + talosctl inspect dependencies | dot -Tpng > graph.png +`, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + return WithClient(func(ctx context.Context, c *client.Client) error { + if err := helpers.FailIfMultiNodes(ctx, "inspect dependencies"); err != nil { + return err + } + + resp, err := c.Inspect.ControllerRuntimeDependencies(ctx) + if err != nil { + if resp == nil { + return fmt.Errorf("error getting controller runtime dependencies: %s", err) + } + + cli.Warning("%s", err) + } + + graph := dot.NewGraph(dot.Directed) + + resourceTypeID := func(edge *inspect.ControllerDependencyEdge) string { + return fmt.Sprintf("%s:%s", edge.GetResourceNamespace(), edge.GetResourceType()) + } + + resourceID := func(r resource.Resource) string { + return r.Metadata().ID() + } + + if inspectDependenciesCmdFlags.withResources { + resources := map[string][]resource.Resource{} + + for _, msg := range resp.GetMessages() { + for _, edge := range msg.GetEdges() { + resourceType := resourceTypeID(edge) + + if _, ok := resources[resourceType]; ok { + continue + } + + listClient, err := c.Resources.List(ctx, edge.GetResourceNamespace(), edge.GetResourceType()) + if err != nil { + return fmt.Errorf("error listing resources: %w", err) + } + + for { + resp, err := listClient.Recv() + if err != nil { + if err == io.EOF || status.Code(err) == codes.Canceled { + break + } + + return fmt.Errorf("error listing resources: %w", err) + } + + if resp.Resource != nil { + resources[resourceType] = append(resources[resourceType], resp.Resource) + } + } + } + } + + for _, msg := range resp.GetMessages() { + for _, edge := range msg.GetEdges() { + graph.Node(edge.ControllerName).Box() + } + } + + for resourceType, resourceList := range resources { + cluster := graph.Subgraph(resourceType, dot.ClusterOption{}) + + for _, resource := range resourceList { + cluster.Node(resourceID(resource)). + Attr("shape", "note"). + Attr("fillcolor", "azure2"). + Attr("style", "filled") + } + } + + for _, msg := range resp.GetMessages() { + for _, edge := range msg.GetEdges() { + for _, resource := range resources[resourceTypeID(edge)] { + if edge.GetResourceId() != "" && resource.Metadata().ID() != edge.GetResourceId() { + continue + } + + switch edge.GetEdgeType() { + case inspect.DependencyEdgeType_MANAGES: + graph.Edge(graph.Node(edge.ControllerName), graph.Subgraph(resourceTypeID(edge)).Node(resourceID(resource))).Solid() + case inspect.DependencyEdgeType_STRONG: + graph.Edge(graph.Subgraph(resourceTypeID(edge)).Node(resourceID(resource)), graph.Node(edge.ControllerName)).Solid() + case inspect.DependencyEdgeType_WEAK: + graph.Edge(graph.Subgraph(resourceTypeID(edge)).Node(resourceID(resource)), graph.Node(edge.ControllerName)).Dotted() + } + } + } + } + } else { + for _, msg := range resp.GetMessages() { + for _, edge := range msg.GetEdges() { + graph.Node(edge.ControllerName).Box() + + graph.Node(resourceTypeID(edge)). + Attr("shape", "note"). + Attr("fillcolor", "azure2"). + Attr("style", "filled") + } + } + + for _, msg := range resp.GetMessages() { + for _, edge := range msg.GetEdges() { + idLabels := []string{} + + if edge.GetResourceId() != "" { + idLabels = append(idLabels, edge.GetResourceId()) + } + + switch edge.GetEdgeType() { + case inspect.DependencyEdgeType_MANAGES: + graph.Edge(graph.Node(edge.ControllerName), graph.Node(resourceTypeID(edge))).Bold() + case inspect.DependencyEdgeType_STRONG: + graph.Edge(graph.Node(resourceTypeID(edge)), graph.Node(edge.ControllerName), idLabels...).Solid() + case inspect.DependencyEdgeType_WEAK: + graph.Edge(graph.Node(resourceTypeID(edge)), graph.Node(edge.ControllerName), idLabels...).Dotted() + } + } + } + } + + graph.Write(os.Stdout) + + return nil + }) + }, +} + +func init() { + addCommand(inspectCmd) + + inspectCmd.AddCommand(inspectDependenciesCmd) + inspectDependenciesCmd.Flags().BoolVar(&inspectDependenciesCmdFlags.withResources, "with-resources", false, "display live resource information with dependencies") +} diff --git a/go.mod b/go.mod index dad919c3a..eeb9abfd1 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ replace ( ) require ( + github.com/AlekSi/pointer v1.1.0 github.com/BurntSushi/toml v0.3.1 github.com/Microsoft/hcsshim v0.8.10 // indirect github.com/Microsoft/hcsshim/test v0.0.0-20201124231931-de74fe8b94ae // indirect @@ -24,10 +25,15 @@ require ( github.com/containernetworking/cni v0.8.0 github.com/containernetworking/plugins v0.8.7 github.com/coreos/go-iptables v0.4.5 + github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect github.com/docker/distribution v2.7.1+incompatible github.com/docker/docker v1.13.1 github.com/docker/go-connections v0.4.0 github.com/dustin/go-humanize v1.0.0 + github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 // indirect + github.com/elazarl/goproxy/ext v0.0.0-20191011121108-aa519ddbe484 // indirect + github.com/emicklei/dot v0.15.0 + github.com/emicklei/go-restful v2.11.1+incompatible // indirect github.com/fatih/color v1.10.0 github.com/firecracker-microvm/firecracker-go-sdk v0.22.0 github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa @@ -37,11 +43,11 @@ require ( github.com/golang/protobuf v1.4.3 github.com/google/uuid v1.1.2 github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 + github.com/grpc-ecosystem/grpc-gateway v1.11.3 // indirect github.com/hashicorp/go-getter v1.5.1 github.com/hashicorp/go-multierror v1.1.0 github.com/insomniacslk/dhcp v0.0.0-20201112113307-4de412bc85d8 github.com/jsimonetti/rtnetlink v0.0.0-20201125080424-8bebea019a6c - github.com/kubernetes-sigs/bootkube v0.14.1-0.20200817205730-0b4482256ca1 github.com/mattn/go-isatty v0.0.12 github.com/mdlayher/genetlink v1.0.0 github.com/mdlayher/netlink v1.1.1 @@ -55,24 +61,24 @@ require ( github.com/ryanuber/columnize v2.1.2+incompatible github.com/smira/go-xz v0.0.0-20201019130106-9921ed7a9935 github.com/spf13/cobra v1.1.1 - github.com/stretchr/testify v1.6.1 + github.com/stretchr/testify v1.7.0 github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 - github.com/talos-systems/bootkube-plugin v0.0.0-20201223175004-aee474d8d060 - github.com/talos-systems/crypto v0.2.1-0.20201203131813-e0dd56ac4745 + github.com/talos-systems/crypto v0.2.1-0.20210125160556-cf75519cab82 github.com/talos-systems/go-blockdevice v0.1.1-0.20201218174450-f2728a581972 github.com/talos-systems/go-loadbalancer v0.1.0 github.com/talos-systems/go-procfs v0.0.0-20210108152626-8cbc42d3dc24 github.com/talos-systems/go-retry v0.2.0 github.com/talos-systems/go-smbios v0.0.0-20200807005123-80196199691e github.com/talos-systems/grpc-proxy v0.2.0 - github.com/talos-systems/net v0.2.0 - github.com/talos-systems/os-runtime v0.0.0-20210119124441-98acf0d2d332 + github.com/talos-systems/net v0.2.1-0.20210121122956-005a94f8b36b + github.com/talos-systems/os-runtime v0.0.0-20210126185717-734f1e1cee9e github.com/talos-systems/talos/pkg/machinery v0.0.0-20200818212414-6a7cc0264819 github.com/u-root/u-root v7.0.0+incompatible github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae // indirect github.com/vmware-tanzu/sonobuoy v0.19.0 github.com/vmware/vmw-guestinfo v0.0.0-20200218095840-687661b8bd8e go.etcd.io/etcd v0.5.0-alpha.5.0.20201125193152-8a03d2e9614b + go.uber.org/zap v1.14.1 // indirect golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 // indirect golang.org/x/net v0.0.0-20201110031124-69a78807bb2b golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 @@ -86,11 +92,11 @@ require ( gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect gopkg.in/freddierice/go-losetup.v1 v1.0.0-20170407175016-fc9adea44124 gopkg.in/fsnotify.v1 v1.4.7 - gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b honnef.co/go/tools v0.0.1-2020.1.6 // indirect k8s.io/api v0.20.2 k8s.io/apimachinery v0.20.2 - k8s.io/apiserver v0.20.2 + k8s.io/apiserver v0.20.2 // indirect k8s.io/client-go v0.20.2 k8s.io/cri-api v0.20.2 k8s.io/kubelet v0.20.2 diff --git a/go.sum b/go.sum index df65a6edc..88cd8fed3 100644 --- a/go.sum +++ b/go.sum @@ -7,14 +7,12 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.47.0/go.mod h1:5p3Ky/7f3N10VBkhuR5LFtddroTiMyjZV/Kj5qOQFxU= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0 h1:3ithwDMr7/3vpAMXiH+ZQnYbuIsh+OPhUPMFC9enmn0= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.2.0/go.mod h1:Cqg1qaK3wRdys8sKlow0jIBVFwSTiHoFx5um4ujCpyE= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0 h1:xE3CPsOgttP4ACBePh79zTKALtXwn/Edhcr16R5hMWU= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -27,7 +25,6 @@ cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+ cloud.google.com/go/pubsub v1.2.0 h1:Lpy6hKgdcl7a3WGSfJIFmxmcdjSpP6OmBEfcOv1Y680= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.2.1/go.mod h1:kpwTAahUQmhyVVGgLWQh2GdyPDZSA3UJDjMm/fDV2oQ= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0 h1:UDpwYIwla4jHGzZJaEJYx1tOejbgSoNqsAfHAUYe2r8= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= @@ -40,12 +37,10 @@ github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.1/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.2/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.11.1 h1:eVvIXUKiTgv++6YnWb42DUA1YL7qDugnKP0HljexdnQ= github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.6.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= @@ -79,7 +74,6 @@ github.com/Microsoft/hcsshim v0.8.10/go.mod h1:g5uw8EV2mAlzqe94tfNBNdr89fnbD/n3H github.com/Microsoft/hcsshim/test v0.0.0-20201124231931-de74fe8b94ae h1:O4x+p9kPOz8k0zIZauAgoq9zRAGD1nShUxjlVH/rBK4= github.com/Microsoft/hcsshim/test v0.0.0-20201124231931-de74fe8b94ae/go.mod h1:IrOsC3sbIiki4idDR4z1Plxm8vAUM5dKN/HEVkRU0GI= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -124,7 +118,6 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= @@ -137,6 +130,8 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0Bsq github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae h1:2Zmk+8cNvAGuY8AyvZuWpUdpQUAXwfom4ReVMe/CTIo= github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= +github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm4fSc= +github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -192,9 +187,7 @@ github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ github.com/containernetworking/plugins v0.8.7 h1:bU7QieuAp+sACI2vCzESJ3FoT860urYP+lThyZkb/2M= github.com/containernetworking/plugins v0.8.7/go.mod h1:R7lXeZaBzpfqapcAbHRW8/CYwm0dHzbz0XEjofx0uB0= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.12+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-iptables v0.4.5 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38= @@ -211,7 +204,6 @@ github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+ github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= @@ -226,7 +218,6 @@ github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1S github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= -github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -241,7 +232,6 @@ github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyG github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible h1:dvc1KSkIYTVjZgHf/CTC2diTYC8PzhaA5sFISRfNVrE= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo= github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -260,7 +250,6 @@ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3 github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 h1:pEtiCjIXx3RvGjlUJuCNxNOw0MNblyR9Wi+vJGBFh+8= @@ -268,8 +257,11 @@ github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/El github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/elazarl/goproxy/ext v0.0.0-20191011121108-aa519ddbe484 h1:aBgSK7SOjFeL1wfzfbIb/pkPpfRr6EP7b1Af4o/xkpU= github.com/elazarl/goproxy/ext v0.0.0-20191011121108-aa519ddbe484/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/emicklei/dot v0.15.0 h1:XDBW0Xco1QNyRb33cqLe10cT04yMWL1XpCZfa98Q6Og= +github.com/emicklei/dot v0.15.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.11.1+incompatible h1:CjKsv3uWcCMvySPQYKxO8XX3f9zD4FeZRsW4G0B4ffE= github.com/emicklei/go-restful v2.11.1+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -347,7 +339,6 @@ github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI= -github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= github.com/go-openapi/loads v0.19.5 h1:jZVYWawIQiA1NBnHla28ktg6hrcfTHsCE+3QLVRBIls= github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= @@ -362,7 +353,6 @@ github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/spec v0.19.8 h1:qAdZLh1r6QF/hI/gTq+TJTvsQUodZsM7KLqkAJdiJNg= github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= @@ -385,7 +375,6 @@ github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfT github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo= -github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8= github.com/go-openapi/validate v0.19.11 h1:8lCr0b9lNWKjVjW/hSZZvltUy+bULl7vbnCTsOzlhPo= github.com/go-openapi/validate v0.19.11/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0waH08tGe6kAQ4= @@ -435,7 +424,6 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -472,7 +460,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -480,7 +467,6 @@ github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPg github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191105193234-27840fff0d09/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -495,13 +481,10 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gophercloud/gophercloud v0.2.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gophercloud/gophercloud v0.6.0 h1:Xb2lcqZtml1XjgYZxbeayEemq7ASbeTp09m36gQFpEU= -github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= @@ -510,16 +493,11 @@ github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= @@ -562,8 +540,6 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= -github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -598,7 +574,6 @@ github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqo github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= github.com/jsimonetti/rtnetlink v0.0.0-20201125080424-8bebea019a6c h1:SIKkaHgrNzRnHEB3QtUR3VUwy9+QpnTwhZ9GYBC0QyU= github.com/jsimonetti/rtnetlink v0.0.0-20201125080424-8bebea019a6c/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= -github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -624,13 +599,9 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kubernetes-sigs/bootkube v0.14.1-0.20200416193108-93ff8fc5e457/go.mod h1:CIpoNLW4Lm9zNVFRgqQIylnbZi/x9TnulTEA8edC0O4= -github.com/kubernetes-sigs/bootkube v0.14.1-0.20200817205730-0b4482256ca1 h1:kjwCNY83bnHUNR6XijS2HDxuXqIp+W8lwk17N2RXlKI= -github.com/kubernetes-sigs/bootkube v0.14.1-0.20200817205730-0b4482256ca1/go.mod h1:tgR06vqFs3qxPEkOFmiMDy9UbQ0PMcee/FK6dOyiHFs= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= @@ -702,7 +673,6 @@ github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/f github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -722,14 +692,11 @@ github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:v github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -753,7 +720,6 @@ github.com/opencontainers/selinux v1.6.0 h1:+bIAS/Za3q5FTwWym4fTB0vObnfCf3G/NC7K github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v0.0.0-20150603214016-ca53cad383ca/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -767,7 +733,6 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -776,7 +741,6 @@ github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -789,7 +753,6 @@ github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7q github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -797,7 +760,6 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= @@ -811,11 +773,9 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= -github.com/rogpeppe/go-charset v0.0.0-20190617161244-0dc95cdf6f31/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= @@ -861,7 +821,6 @@ github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.0-20170515075120-4cdb38c072b8/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= @@ -885,7 +844,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -893,15 +851,15 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.0/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/talos-systems/bootkube-plugin v0.0.0-20201223175004-aee474d8d060 h1:mPJ7w+edz0xQhhZ9Qp1iF7w5vcj7owK2ExmS8usDsFA= -github.com/talos-systems/bootkube-plugin v0.0.0-20201223175004-aee474d8d060/go.mod h1:AbdJAgHK5rJNDPUN3msPTfQJSR9b4DKb5xNN07uG8/Y= -github.com/talos-systems/crypto v0.2.1-0.20201203131813-e0dd56ac4745 h1:Smw6ebFiEiwrkaOD2hEYYb+xkIhQTMZNq3WVYKLszB8= -github.com/talos-systems/crypto v0.2.1-0.20201203131813-e0dd56ac4745/go.mod h1:KwqG+jANKU1FNQIapmioHQ5fkovY1DJkAqMenjYBGh0= +github.com/talos-systems/crypto v0.2.1-0.20210125160556-cf75519cab82 h1:5TsM3o/yJJF6kakHyPee88D0yWNNDNKZJ2NCX9MFsKk= +github.com/talos-systems/crypto v0.2.1-0.20210125160556-cf75519cab82/go.mod h1:OXCK52Q0dzm88YRG4VdTBdidkPUtqrCxCyW7bUs4DAw= github.com/talos-systems/go-blockdevice v0.1.1-0.20201218174450-f2728a581972 h1:/yEPl6h6+pK9XIfQEiZ989GDuw6dCUBeinzUcCu6dyY= github.com/talos-systems/go-blockdevice v0.1.1-0.20201218174450-f2728a581972/go.mod h1:efEE9wjtgxiovqsZAV39xlOd/AOI/0sLuZqb5jEgeqo= github.com/talos-systems/go-loadbalancer v0.1.0 h1:MQFONvSjoleU8RrKq1O1Z8CyTCJGd4SLqdAHDlR6o9s= @@ -915,10 +873,10 @@ github.com/talos-systems/go-smbios v0.0.0-20200807005123-80196199691e h1:uCp8BfH github.com/talos-systems/go-smbios v0.0.0-20200807005123-80196199691e/go.mod h1:HxhrzAoTZ7ed5Z5VvtCvnCIrOxyXDS7V2B5hCetAMW8= github.com/talos-systems/grpc-proxy v0.2.0 h1:DN75bLfaW4xfhq0r0mwFRnfGhSB+HPhK1LNzuMEs9Pw= github.com/talos-systems/grpc-proxy v0.2.0/go.mod h1:sm97Vc/z2cok3pu6ruNeszQej4KDxFrDgfWs4C1mtC4= -github.com/talos-systems/net v0.2.0 h1:QJ2ofYboG1Zjew9b+3RAjtLIfL0mIONGuc6/LyO68MM= -github.com/talos-systems/net v0.2.0/go.mod h1:VreSAyRmxMtqussAHSKMKkJQa1YwBTSVfkmE4Jydam4= -github.com/talos-systems/os-runtime v0.0.0-20210119124441-98acf0d2d332 h1:Ib5HAIpv8GjAfdKSzcPfvUPN2mbzYwsre61Sogjt/kk= -github.com/talos-systems/os-runtime v0.0.0-20210119124441-98acf0d2d332/go.mod h1:pQ8E1nmr8SODM9TD9HXH5HlzgyfyeCO8yug4x6fDKlQ= +github.com/talos-systems/net v0.2.1-0.20210121122956-005a94f8b36b h1:y3mBkTJdW7cUn+ff53TZN0yyWCpjS6XrVmlx+vx9pwA= +github.com/talos-systems/net v0.2.1-0.20210121122956-005a94f8b36b/go.mod h1:VreSAyRmxMtqussAHSKMKkJQa1YwBTSVfkmE4Jydam4= +github.com/talos-systems/os-runtime v0.0.0-20210126185717-734f1e1cee9e h1:HrAdgwnXhVr9LlWjpc+kejkLVUpTRKbNTAJe7H+kRXM= +github.com/talos-systems/os-runtime v0.0.0-20210126185717-734f1e1cee9e/go.mod h1:+E9CUVoYpReh0nhOEvFpy7pwLiyq0700WF03I06giyk= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -927,9 +885,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/u-root/u-root v7.0.0+incompatible h1:u+KSS04pSxJGI5E7WE4Bs9+Zd75QjFv+REkjy/aoAc8= github.com/u-root/u-root v7.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -967,16 +923,13 @@ github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPS github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.etcd.io/etcd v0.5.0-alpha.5.0.20201125193152-8a03d2e9614b h1:PLwvCoe5rvpuo9Un6/hlNRMAfOMVb7zBsOOeKAjV81g= go.etcd.io/etcd v0.5.0-alpha.5.0.20201125193152-8a03d2e9614b/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= go.mongodb.org/mongo-driver v1.3.4 h1:zs/dKNwX0gYUtzwrN9lLiR15hCO0nDwQj5xXx+vjCdE= go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= @@ -1014,7 +967,6 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191108234033-bd318be0434a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1024,10 +976,7 @@ golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= -golang.org/x/exp v0.0.0-20191024150812-c286b889502e/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= @@ -1037,7 +986,6 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1051,7 +999,6 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7 golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mobile v0.0.0-20191031020345-0945064e013a/go.mod h1:p895TfNkDgPEmEQrNiOtIl3j98d/tGU95djDj7NfyjQ= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -1083,13 +1030,11 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191109021931-daa7c04131f5/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1151,7 +1096,6 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1160,7 +1104,6 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1235,18 +1178,11 @@ golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190909214602-067311248421/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191010171213-8abd42400456/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191028194131-d78a1f2664a0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191105231337-689d0f08e67a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191111154804-8cb0d02132ec/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1303,8 +1239,6 @@ google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dT google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= @@ -1362,7 +1296,6 @@ gopkg.in/freddierice/go-losetup.v1 v1.0.0-20170407175016-fc9adea44124/go.mod h1: gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= @@ -1384,6 +1317,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= @@ -1399,71 +1334,44 @@ honnef.co/go/tools v0.0.1-2020.1.6 h1:W18jzjh8mfPez+AwGLxmOImucz/IFjpNlrKVnaj2YV honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY= inet.af/tcpproxy v0.0.0-20200125044825-b6bb9b5b8252 h1:gmJCKidOfjKDUHF1jjke+I+2iQIyE3HNNxu2OKO/FUI= inet.af/tcpproxy v0.0.0-20200125044825-b6bb9b5b8252/go.mod h1:zq+R+tLcdHugi7Jt+FtIQY6m6wtX34lr2CdQVH2fhW0= -k8s.io/api v0.0.0-20191016110408-35e52d86657a/go.mod h1:/L5qH+AD540e7Cetbui1tuJeXdmNhO8jM6VkXeDdDhQ= -k8s.io/api v0.0.0-20191109101513-0171b7c15da1/go.mod h1:VJq7+38rpM4TSUbRiZX4P5UVAKK2UQpNQLZClkFQkpE= -k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.18.5/go.mod h1:tN+e/2nbdGKOAH55NMV8oGrMG+3uRlA9GaRfvnCCSNk= k8s.io/api v0.20.2 h1:y/HR22XDZY3pniu9hIFDLpUCPq2w5eQ6aV/VFQ7uJMw= k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8= -k8s.io/apiextensions-apiserver v0.0.0-20190202013456-d4288ab64945/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE= -k8s.io/apiextensions-apiserver v0.18.2 h1:I4v3/jAuQC+89L3Z7dDgAiN4EOjN6sbm6iBqQwHTah8= -k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= -k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ= -k8s.io/apimachinery v0.0.0-20191109100837-dffb012825f2/go.mod h1:+6CX7hP4aLfX2sb91JYDMIp0VqDSog2kZu0BHe+lP+s= -k8s.io/apimachinery v0.0.0-20191111054156-6eb29fdf75dc/go.mod h1:+6CX7hP4aLfX2sb91JYDMIp0VqDSog2kZu0BHe+lP+s= -k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.5/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= k8s.io/apimachinery v0.20.2 h1:hFx6Sbt1oG0n6DZ+g4bFt5f6BoMkOjKWsQFu077M3Vg= k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= k8s.io/apiserver v0.20.2 h1:lGno2t3gcZnLtzsKH4oG0xA9/4GTiBzMO1DGp+K+Bak= k8s.io/apiserver v0.20.2/go.mod h1:2nKd93WyMhZx4Hp3RfgH2K5PhwyTrprrkWYnI7id7jA= -k8s.io/client-go v0.0.0-20191016111102-bec269661e48/go.mod h1:hrwktSwYGI4JK+TJA3dMaFyyvHVi/aLarVHpbs8bgCU= -k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= k8s.io/client-go v0.18.5/go.mod h1:EsiD+7Fx+bRckKWZXnAXRKKetm1WuzPagH4iOSC8x58= k8s.io/client-go v0.20.2 h1:uuf+iIAbfnCSw8IGAv/Rg0giM+2bOzHLOsbbrwrdhNQ= k8s.io/client-go v0.20.2/go.mod h1:kH5brqWqp7HDxUFKoEgiI4v8G1xzbe9giaCenUWJzgE= -k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= -k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= k8s.io/component-base v0.20.2 h1:LMmu5I0pLtwjpp5009KLuMGFqSc2S2isGw8t1hpYKLE= k8s.io/component-base v0.20.2/go.mod h1:pzFtCiwe/ASD0iV7ySMu8SYVJjCapNM9bjvk7ptpKh0= k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= k8s.io/cri-api v0.20.2 h1:GPwBRUF2dQvf7ZaXVUmHbmyYRDlxDuCBSfn/2wpccQk= k8s.io/cri-api v0.20.2/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20191108084044-e500ee069b5c/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd h1:sOHNzJIkytDF6qadMNKhhDRpc6ODik8lVC6nOur7B2c= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kubelet v0.20.2 h1:TbOqhr5pN6GsGy798WnwiBAw1JIyZ5H4rugKf1q2jNw= k8s.io/kubelet v0.20.2/go.mod h1:i441hnZtH2wUiDNqpXVZYaNCqEOBd2sM7x2mV0n7dJs= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20191030222137-2b95a09bc58d/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v1.0.0 h1:JI5bQQfabPDe8cSuK/lFMm2xB3faNkWyXyxT69FVmS8= -sigs.k8s.io/structured-merge-diff v1.0.0/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8= diff --git a/internal/app/bootkube/assets.go b/internal/app/bootkube/assets.go deleted file mode 100644 index b6e39f389..000000000 --- a/internal/app/bootkube/assets.go +++ /dev/null @@ -1,276 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package main - -import ( - "context" - "crypto/x509" - "encoding/pem" - "errors" - "fmt" - "io/ioutil" - "net" - "net/http" - "net/url" - "os" - "path" - "path/filepath" - "strings" - - "github.com/hashicorp/go-getter" - "github.com/hashicorp/go-multierror" - "github.com/kubernetes-sigs/bootkube/pkg/tlsutil" - "github.com/talos-systems/bootkube-plugin/pkg/asset" - tnet "github.com/talos-systems/net" - - "github.com/talos-systems/talos/internal/app/bootkube/images" - "github.com/talos-systems/talos/pkg/machinery/config" - "github.com/talos-systems/talos/pkg/machinery/constants" -) - -// nolint: gocyclo -func generateAssets(config config.Provider) (err error) { - // Ensure assets directory does not exist / is left over from a failed install - if err = os.RemoveAll(constants.AssetsDirectory); err != nil { - // Ignore if the directory does not exist - if !errors.Is(err, os.ErrNotExist) { - return err - } - } - - peerCrt, err := ioutil.ReadFile(constants.KubernetesEtcdPeerCert) - if err != nil { - return err - } - - block, _ := pem.Decode(peerCrt) - if block == nil { - return errors.New("failed to decode peer certificate") - } - - peer, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return fmt.Errorf("failed to parse client certificate: %w", err) - } - - caCrt, err := ioutil.ReadFile(constants.KubernetesEtcdCACert) - if err != nil { - return err - } - - block, _ = pem.Decode(caCrt) - if block == nil { - return errors.New("failed to decode CA certificate") - } - - ca, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return fmt.Errorf("failed to parse etcd CA certificate: %w", err) - } - - peerKey, err := ioutil.ReadFile(constants.KubernetesEtcdPeerKey) - if err != nil { - return err - } - - block, _ = pem.Decode(peerKey) - if block == nil { - return errors.New("failed to peer key") - } - - key, err := x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - return fmt.Errorf("failed to parse client key: %w", err) - } - - etcdServer, err := url.Parse("https://127.0.0.1:2379") - if err != nil { - return err - } - - podCIDRs, err := splitCIDRs(config.Cluster().Network().PodCIDR()) - if err != nil { - return fmt.Errorf("failed to process Pod CIDRs: %w", err) - } - - serviceCIDRs, err := splitCIDRs(config.Cluster().Network().ServiceCIDR()) - if err != nil { - return fmt.Errorf("failed to process Service CIDRs: %w", err) - } - - urls := []string{config.Cluster().Endpoint().Hostname()} - urls = append(urls, config.Cluster().CertSANs()...) - altNames := altNamesFromURLs(urls) - - k8sCA, err := config.Cluster().CA().GetCert() - if err != nil { - return fmt.Errorf("failed to get Kubernetes CA certificate: %w", err) - } - - k8sKey, err := config.Cluster().CA().GetRSAKey() - if err != nil { - return fmt.Errorf("failed to parse Kubernetes key: %w", err) - } - - apiServiceIPs, err := nthIPInCIDRSet(serviceCIDRs, 1) - if err != nil { - return fmt.Errorf("failed to calculate API service IP: %w", err) - } - - dnsServiceIPs, err := nthIPInCIDRSet(serviceCIDRs, 10) - if err != nil { - return fmt.Errorf("failed to calculate DNS service IP: %w", err) - } - - images := images.List(config) - - conf := asset.Config{ - ClusterName: config.Cluster().Name(), - APIServerExtraArgs: config.Cluster().APIServer().ExtraArgs(), - ControllerManagerExtraArgs: config.Cluster().ControllerManager().ExtraArgs(), - ProxyMode: config.Cluster().Proxy().Mode(), - ProxyExtraArgs: config.Cluster().Proxy().ExtraArgs(), - SchedulerExtraArgs: config.Cluster().Scheduler().ExtraArgs(), - CACert: k8sCA, - CAPrivKey: k8sKey, - EtcdCACert: ca, - EtcdClientCert: peer, - EtcdClientKey: key, - EtcdServers: []*url.URL{etcdServer}, - EtcdUseTLS: true, - ControlPlaneEndpoint: config.Cluster().Endpoint(), - LocalAPIServerPort: config.Cluster().LocalAPIServerPort(), - APIServiceIPs: apiServiceIPs, - DNSServiceIPs: dnsServiceIPs, - PodCIDRs: podCIDRs, - ServiceCIDRs: serviceCIDRs, - NetworkProvider: config.Cluster().Network().CNI().Name(), - AltNames: altNames, - Images: images, - BootstrapSecretsSubdir: "/assets/tls", - BootstrapTokenID: config.Cluster().Token().ID(), - BootstrapTokenSecret: config.Cluster().Token().Secret(), - AESCBCEncryptionSecret: config.Cluster().AESCBCEncryptionSecret(), - ClusterDomain: config.Cluster().Network().DNSDomain(), - } - - if err = asset.Render(constants.AssetsDirectory, conf); err != nil { - return err - } - - // If "custom" is the CNI, we expect the user to supply one or more urls that point to CNI yamls - if config.Cluster().Network().CNI().Name() == constants.CustomCNI { - if err = fetchManifests(config.Cluster().Network().CNI().URLs(), map[string]string{}); err != nil { - return err - } - } - - if len(config.Cluster().ExtraManifestURLs()) > 0 { - if err = fetchManifests(config.Cluster().ExtraManifestURLs(), config.Cluster().ExtraManifestHeaderMap()); err != nil { - return err - } - } - - return nil -} - -func altNamesFromURLs(urls []string) *tlsutil.AltNames { - var an tlsutil.AltNames - - for _, u := range urls { - ip := net.ParseIP(u) - if ip != nil { - an.IPs = append(an.IPs, ip) - - continue - } - - an.DNSNames = append(an.DNSNames, u) - } - - return &an -} - -// fetchManifests will lay down manifests in the provided urls to the bootkube assets directory. -func fetchManifests(urls []string, headers map[string]string) error { - ctx := context.Background() - - var result *multierror.Error - - for _, url := range urls { - fileName := path.Base(url) - - pwd, err := os.Getwd() - if err != nil { - result = multierror.Append(result, err) - - continue - } - - // Disable netrc since we don't have getent installed, and most likely - // never will. - httpGetter := &getter.HttpGetter{ - Netrc: false, - Client: http.DefaultClient, - } - - httpGetter.Header = make(http.Header) - - for k, v := range headers { - httpGetter.Header.Add(k, v) - } - - getter.Getters["http"] = httpGetter - getter.Getters["https"] = httpGetter - - // We will squirrel all user-supplied manifests into a `zzz-talos` directory. - // Bootkube applies manifests alphabetically, so pushing these into a subdir with this name - // allows us to ensure they're the last things that get applied and things like PSPs and whatnot are present - client := &getter.Client{ - Ctx: ctx, - Src: url, - Dst: filepath.Join(constants.AssetsDirectory, "manifests", "zzz-talos", fileName), - Pwd: pwd, - Mode: getter.ClientModeFile, - Options: []getter.ClientOption{}, - } - - fmt.Printf("Downloading manifest: %q -> %q", client.Src, client.Dst) - - if err = client.Get(); err != nil { - result = multierror.Append(result, fmt.Errorf("error fetching manifest by URL %q: %w", url, err)) - - continue - } - } - - return result.ErrorOrNil() -} - -func splitCIDRs(cidrList string) (out []*net.IPNet, err error) { - for _, podCIDR := range strings.Split(cidrList, ",") { - _, cidr, err := net.ParseCIDR(podCIDR) - if err != nil { - return nil, fmt.Errorf("failed to parse %q as a CIDR: %w", podCIDR, err) - } - - out = append(out, cidr) - } - - return out, nil -} - -func nthIPInCIDRSet(cidrList []*net.IPNet, offset int) (out []net.IP, err error) { - for _, cidr := range cidrList { - ip, err := tnet.NthIPInNetwork(cidr, offset) - if err != nil { - return nil, fmt.Errorf("failed to calculate offset %d from CIDR %q: %w", offset, cidr, err) - } - - out = append(out, ip) - } - - return out, nil -} diff --git a/internal/app/bootkube/main.go b/internal/app/bootkube/main.go deleted file mode 100644 index 2c9b0c93d..000000000 --- a/internal/app/bootkube/main.go +++ /dev/null @@ -1,137 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package main - -import ( - "flag" - "fmt" - "log" - "os" - "path/filepath" - - "github.com/hashicorp/go-multierror" - "github.com/kubernetes-sigs/bootkube/pkg/bootkube" - "github.com/kubernetes-sigs/bootkube/pkg/util" - - "github.com/talos-systems/talos/pkg/machinery/config/configloader" - "github.com/talos-systems/talos/pkg/machinery/constants" -) - -var ( - strict *bool - recover *bool - recoverSource *string -) - -func init() { - log.SetFlags(log.Lshortfile | log.Ldate | log.Lmicroseconds | log.Ltime) - - strict = flag.Bool("strict", true, "require all manifests to cleanly apply") - recover = flag.Bool("recover", false, "run recovery instead of generate") - recoverSource = flag.String("recover-source", "ETCD", "recovery source to use") - - flag.Parse() -} - -//nolint: gocyclo -func run() error { - util.InitLogs() - - defer util.FlushLogs() - - config, err := configloader.NewFromStdin() - if err != nil { - return err - } - - if *recover { - if err = recoverAssets(config); err != nil { - return fmt.Errorf("error recovering assets: %w", err) - } - } else { - if err = generateAssets(config); err != nil { - return fmt.Errorf("error generating assets: %w", err) - } - } - - if err = os.MkdirAll(constants.ManifestsDirectory, 0o644); err != nil { - return err - } - - // cleanup manifests which might have been left from previous bootkube run - cleanupManifests("bootkube-*") //nolint: errcheck - cleanupManifests("kube-system-pod-checkpointer-*") //nolint: errcheck - - defaultRequiredPods := []string{ - "kube-system/pod-checkpointer", - "kube-system/kube-apiserver", - "kube-system/kube-scheduler", - "kube-system/kube-controller-manager", - } - - cfg := bootkube.Config{ - AssetDir: constants.AssetsDirectory, - PodManifestPath: constants.ManifestsDirectory, - Strict: *strict, - RequiredPods: defaultRequiredPods, - } - - bk, err := bootkube.NewBootkube(cfg) - if err != nil { - return err - } - - failed := true - - defer func() { - // We want to cleanup the manifests directory only if bootkube fails. - if failed { - if err = os.RemoveAll(constants.ManifestsDirectory); err != nil { - log.Printf("failed to cleanup manifests dir %s", constants.ManifestsDirectory) - } - } - - if err = os.RemoveAll(constants.AssetsDirectory); err != nil { - log.Printf("failed to cleanup bootkube assets dir %s", constants.AssetsDirectory) - } - - if err = cleanupManifests("bootstrap-*"); err != nil { - log.Printf("%s", err) - } - }() - - if err = bk.Run(); err != nil { - return err - } - - failed = false - - return nil -} - -func cleanupManifests(wildcard string) error { - bootstrapWildcard := filepath.Join(constants.ManifestsDirectory, wildcard) - - bootstrapFiles, err := filepath.Glob(bootstrapWildcard) - if err != nil { - return fmt.Errorf("error finding bootstrap files in manifests dir %s", constants.ManifestsDirectory) - } - - var multiErr *multierror.Error - - for _, bootstrapFile := range bootstrapFiles { - if err = os.Remove(bootstrapFile); err != nil { - multiErr = multierror.Append(multiErr, fmt.Errorf("error deleting bootstrap file in manifests dir: %s", err)) - } - } - - return multiErr.ErrorOrNil() -} - -func main() { - if err := run(); err != nil { - log.Fatalf("bootkube failed: %s", err) - } -} diff --git a/internal/app/bootkube/recover.go b/internal/app/bootkube/recover.go deleted file mode 100644 index 857f6912e..000000000 --- a/internal/app/bootkube/recover.go +++ /dev/null @@ -1,111 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package main - -import ( - "bytes" - "context" - "crypto/aes" - "encoding/base64" - "errors" - "fmt" - "os" - - "github.com/kubernetes-sigs/bootkube/pkg/recovery" - k8saes "k8s.io/apiserver/pkg/storage/value/encrypt/aes" - - "github.com/talos-systems/talos/internal/pkg/etcd" - machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine" - "github.com/talos-systems/talos/pkg/machinery/config" - "github.com/talos-systems/talos/pkg/machinery/constants" -) - -//nolint: gocyclo -func recoverAssets(config config.Provider) error { - // Ensure assets directory does not exist / is left over from a failed install - if err := os.RemoveAll(constants.AssetsDirectory); err != nil { - // Ignore if the directory does not exist - if !errors.Is(err, os.ErrNotExist) { - return err - } - } - - var ( - backend recovery.Backend - err error - ) - - switch *recoverSource { - case machineapi.RecoverRequest_ETCD.String(): - var client *etcd.Client - - client, err = etcd.NewClient([]string{"127.0.0.1:2379"}) - if err != nil { - return err - } - - var transform recovery.TransformerFromStorage - - transform, err = aesTransformer(config.Cluster()) - if err != nil { - return err - } - - backend = recovery.NewEtcdBackendWithTransformer(client.Client, "/registry", transform) - case machineapi.RecoverRequest_APISERVER.String(): - backend, err = recovery.NewAPIServerBackend(constants.RecoveryKubeconfig) - if err != nil { - return err - } - } - - as, err := recovery.Recover(context.Background(), backend, constants.RecoveryKubeconfig) - if err != nil { - return err - } - - if err = os.MkdirAll(constants.AssetsDirectory, 0o600); err != nil { - return err - } - - if err = as.WriteFiles(constants.AssetsDirectory); err != nil { - return fmt.Errorf("failed to write recovered assets: %w", err) - } - - return nil -} - -func aesTransformer(clusterConfig config.ClusterConfig) (recovery.TransformerFromStorage, error) { - key, err := base64.StdEncoding.DecodeString(clusterConfig.AESCBCEncryptionSecret()) - if err != nil { - return nil, err - } - - cipher, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - - transformer := k8saes.NewCBCTransformer(cipher) - - return func(value []byte) ([]byte, error) { - const ( - aesCBCTransformerPrefixV1 = "k8s:enc:aescbc:v1:" - aesCBCKeyName = "key1:" - - aesCBCPrefix = aesCBCTransformerPrefixV1 + aesCBCKeyName - ) - - if !bytes.HasPrefix(value, []byte(aesCBCPrefix)) { - return value, nil - } - - value = value[len(aesCBCPrefix):] - - value, _, e := transformer.TransformFromStorage(value, nil) - - return value, e - }, nil -} diff --git a/internal/app/machined/internal/server/v1alpha1/v1alpha1_inspect.go b/internal/app/machined/internal/server/v1alpha1/v1alpha1_inspect.go new file mode 100644 index 000000000..5e80c4fe5 --- /dev/null +++ b/internal/app/machined/internal/server/v1alpha1/v1alpha1_inspect.go @@ -0,0 +1,62 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package runtime + +import ( + "context" + "fmt" + + "github.com/golang/protobuf/ptypes/empty" + "github.com/talos-systems/os-runtime/pkg/controller" + + inspectapi "github.com/talos-systems/talos/pkg/machinery/api/inspect" +) + +// InspectServer implements InspectService API. +type InspectServer struct { + server *Server +} + +// ControllerRuntimeDependencies implements inspect.InspectService interface. +func (s *InspectServer) ControllerRuntimeDependencies(ctx context.Context, in *empty.Empty) (*inspectapi.ControllerRuntimeDependenciesResponse, error) { + graph, err := s.server.Controller.V1Alpha2().DependencyGraph() + if err != nil { + return nil, fmt.Errorf("error fetching dependency graph: %w", err) + } + + edges := make([]*inspectapi.ControllerDependencyEdge, 0, len(graph.Edges)) + + for i := range graph.Edges { + var edgeType inspectapi.DependencyEdgeType + + switch graph.Edges[i].EdgeType { + case controller.EdgeManages: + edgeType = inspectapi.DependencyEdgeType_MANAGES + case controller.EdgeDependsStrong: + edgeType = inspectapi.DependencyEdgeType_STRONG + case controller.EdgeDependsWeak: + edgeType = inspectapi.DependencyEdgeType_WEAK + } + + edges = append(edges, &inspectapi.ControllerDependencyEdge{ + + ControllerName: graph.Edges[i].ControllerName, + + EdgeType: edgeType, + + ResourceNamespace: graph.Edges[i].ResourceNamespace, + ResourceType: graph.Edges[i].ResourceType, + ResourceId: graph.Edges[i].ResourceID, + }) + } + + return &inspectapi.ControllerRuntimeDependenciesResponse{ + Messages: []*inspectapi.ControllerRuntimeDependency{ + { + Edges: edges, + }, + }, + }, nil +} diff --git a/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go b/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go index aedb649d3..4d44bc453 100644 --- a/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go +++ b/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go @@ -57,6 +57,7 @@ import ( "github.com/talos-systems/talos/pkg/chunker/stream" "github.com/talos-systems/talos/pkg/machinery/api/cluster" "github.com/talos-systems/talos/pkg/machinery/api/common" + "github.com/talos-systems/talos/pkg/machinery/api/inspect" "github.com/talos-systems/talos/pkg/machinery/api/machine" "github.com/talos-systems/talos/pkg/machinery/api/resource" "github.com/talos-systems/talos/pkg/machinery/config" @@ -98,6 +99,7 @@ func (s *Server) Register(obj *grpc.Server) { machine.RegisterMachineServiceServer(obj, s) cluster.RegisterClusterServiceServer(obj, s) resource.RegisterResourceServiceServer(obj, &ResourceServer{server: s}) + inspect.RegisterInspectServiceServer(obj, &InspectServer{server: s}) } // ApplyConfiguration implements machine.MachineService. @@ -530,25 +532,7 @@ func (s *Server) Recover(ctx context.Context, in *machine.RecoverRequest) (reply return nil, fmt.Errorf("recover can only be performed on a control plane node") } - go func() { - if err := s.Controller.Run(runtime.SequenceRecover, in); err != nil { - log.Println("recover failed:", err) - - if err != runtime.ErrLocked { - // NB: We stop the gRPC server since a failed sequence triggers a - // reboot. - s.server.GracefulStop() - } - } - }() - - reply = &machine.RecoverResponse{ - Messages: []*machine.Recover{ - {}, - }, - } - - return reply, nil + return nil, fmt.Errorf("recover is not supported since Talos 0.9, use apply-config to update control plane configuration") } // ServiceList returns list of the registered services and their status. @@ -1638,7 +1622,7 @@ func (s *Server) EtcdMemberList(ctx context.Context, in *machine.EtcdMemberListR var client *etcd.Client if in.QueryLocal { - client, err = etcd.NewClient([]string{"127.0.0.1:2379"}) + client, err = etcd.NewLocalClient() } else { client, err = etcd.NewClientFromControlPlaneIPs(ctx, s.Controller.Runtime().Config().Cluster().CA(), s.Controller.Runtime().Config().Cluster().Endpoint()) } diff --git a/internal/app/machined/pkg/controllers/config/config.go b/internal/app/machined/pkg/controllers/config/config.go new file mode 100644 index 000000000..230c5b5d2 --- /dev/null +++ b/internal/app/machined/pkg/controllers/config/config.go @@ -0,0 +1,6 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package config provides controllers which manage config resources. +package config diff --git a/internal/app/machined/pkg/controllers/config/k8s_control_plane.go b/internal/app/machined/pkg/controllers/config/k8s_control_plane.go new file mode 100644 index 000000000..16285798a --- /dev/null +++ b/internal/app/machined/pkg/controllers/config/k8s_control_plane.go @@ -0,0 +1,237 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package config + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/AlekSi/pointer" + talosnet "github.com/talos-systems/net" + "github.com/talos-systems/os-runtime/pkg/controller" + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/state" + + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/config" + "github.com/talos-systems/talos/pkg/images" + talosconfig "github.com/talos-systems/talos/pkg/machinery/config" + "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/talos-systems/talos/pkg/machinery/constants" +) + +// K8sControlPlaneController manages config.K8sControlPlane based on configuration. +type K8sControlPlaneController struct { +} + +// Name implements controller.Controller interface. +func (ctrl *K8sControlPlaneController) Name() string { + return "config.K8sControlPlaneController" +} + +// ManagedResources implements controller.Controller interface. +func (ctrl *K8sControlPlaneController) ManagedResources() (resource.Namespace, resource.Type) { + return config.NamespaceName, config.K8sControlPlaneType +} + +// Run implements controller.Controller interface. +// +//nolint: gocyclo +func (ctrl *K8sControlPlaneController) Run(ctx context.Context, r controller.Runtime, logger *log.Logger) error { + if err := r.UpdateDependencies([]controller.Dependency{ + { + Namespace: config.NamespaceName, + Type: config.V1Alpha1Type, + ID: pointer.ToString(config.V1Alpha1ID), + Kind: controller.DependencyWeak, + }, + { + Namespace: config.NamespaceName, + Type: config.MachineTypeType, + ID: pointer.ToString(config.MachineTypeID), + Kind: controller.DependencyWeak, + }, + }); err != nil { + return fmt.Errorf("error setting up dependencies: %w", err) + } + + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + cfg, err := r.Get(ctx, resource.NewMetadata(config.NamespaceName, config.V1Alpha1Type, config.V1Alpha1ID, resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + if err = ctrl.teardownAll(ctx, r, logger); err != nil { + return fmt.Errorf("error destroying resources: %w", err) + } + + continue + } + + return fmt.Errorf("error getting config: %w", err) + } + + cfgProvider := cfg.(*config.V1Alpha1).Config() + + machineTypeRes, err := r.Get(ctx, resource.NewMetadata(config.NamespaceName, config.MachineTypeType, config.MachineTypeID, resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return fmt.Errorf("error getting machine type: %w", err) + } + + machineType := machineTypeRes.(*config.MachineType).MachineType() + + if machineType != machine.TypeControlPlane && machineType != machine.TypeInit { + if err = ctrl.teardownAll(ctx, r, logger); err != nil { + return fmt.Errorf("error destroying resources: %w", err) + } + + continue + } + + for _, f := range []func(context.Context, controller.Runtime, *log.Logger, talosconfig.Provider) error{ + ctrl.manageAPIServerConfig, + ctrl.manageControllerManagerConfig, + ctrl.manageSchedulerConfig, + ctrl.manageManifestsConfig, + ctrl.manageExtraManifestsConfig, + } { + if err = f(ctx, r, logger, cfgProvider); err != nil { + return fmt.Errorf("error updating objects: %w", err) + } + } + } +} + +func (ctrl *K8sControlPlaneController) manageAPIServerConfig(ctx context.Context, r controller.Runtime, logger *log.Logger, cfgProvider talosconfig.Provider) error { + return r.Update(ctx, config.NewK8sControlPlaneAPIServer(), func(r resource.Resource) error { + r.(*config.K8sControlPlane).SetAPIServer(config.K8sControlPlaneAPIServerSpec{ + Image: cfgProvider.Cluster().APIServer().Image(), + CloudProvider: "", // TODO: add cloud provider to config one day + ControlPlaneEndpoint: cfgProvider.Cluster().Endpoint().String(), + EtcdServers: []string{"https://127.0.0.1:2379"}, + LocalPort: cfgProvider.Cluster().LocalAPIServerPort(), + ServiceCIDR: cfgProvider.Cluster().Network().ServiceCIDR(), + ExtraArgs: cfgProvider.Cluster().APIServer().ExtraArgs(), + }) + + return nil + }) +} + +func (ctrl *K8sControlPlaneController) manageControllerManagerConfig(ctx context.Context, r controller.Runtime, logger *log.Logger, cfgProvider talosconfig.Provider) error { + return r.Update(ctx, config.NewK8sControlPlaneControllerManager(), func(r resource.Resource) error { + r.(*config.K8sControlPlane).SetControllerManager(config.K8sControlPlaneControllerManagerSpec{ + Image: cfgProvider.Cluster().ControllerManager().Image(), + CloudProvider: "", // TODO: add cloud provider to config one day + PodCIDR: cfgProvider.Cluster().Network().PodCIDR(), + ServiceCIDR: cfgProvider.Cluster().Network().ServiceCIDR(), + ExtraArgs: cfgProvider.Cluster().ControllerManager().ExtraArgs(), + }) + + return nil + }) +} + +func (ctrl *K8sControlPlaneController) manageSchedulerConfig(ctx context.Context, r controller.Runtime, logger *log.Logger, cfgProvider talosconfig.Provider) error { + return r.Update(ctx, config.NewK8sControlPlaneScheduler(), func(r resource.Resource) error { + r.(*config.K8sControlPlane).SetScheduler(config.K8sControlPlaneSchedulerSpec{ + Image: cfgProvider.Cluster().Scheduler().Image(), + ExtraArgs: cfgProvider.Cluster().Scheduler().ExtraArgs(), + }) + + return nil + }) +} + +func (ctrl *K8sControlPlaneController) manageManifestsConfig(ctx context.Context, r controller.Runtime, logger *log.Logger, cfgProvider talosconfig.Provider) error { + dnsServiceIPs, err := cfgProvider.Cluster().Network().DNSServiceIPs() + if err != nil { + return fmt.Errorf("error calculating DNS service IPs: %w", err) + } + + dnsServiceIP := "" + dnsServiceIPv6 := "" + + if len(dnsServiceIPs) == 1 { + dnsServiceIP = dnsServiceIPs[0].String() + } else { + for _, ip := range dnsServiceIPs { + if dnsServiceIP == "" && ip.To4().Equal(ip) { + dnsServiceIP = ip.String() + } + + if dnsServiceIPv6 == "" && talosnet.IsNonLocalIPv6(ip) { + dnsServiceIPv6 = ip.String() + } + } + } + + return r.Update(ctx, config.NewK8sManifests(), func(r resource.Resource) error { + images := images.List(cfgProvider) + + r.(*config.K8sControlPlane).SetManifests(config.K8sManifestsSpec{ + Server: cfgProvider.Cluster().Endpoint().String(), + ClusterDomain: cfgProvider.Cluster().Network().DNSDomain(), + + PodCIDRs: cfgProvider.Cluster().Network().PodCIDR(), + FirstPodCIDR: strings.Split(cfgProvider.Cluster().Network().PodCIDR(), ",")[0], + + ProxyImage: cfgProvider.Cluster().Proxy().Image(), + ProxyMode: cfgProvider.Cluster().Proxy().Mode(), + ProxyExtraArgs: cfgProvider.Cluster().Proxy().ExtraArgs(), + + CoreDNSImage: cfgProvider.Cluster().CoreDNS().Image(), + + DNSServiceIP: dnsServiceIP, + DNSServiceIPv6: dnsServiceIPv6, + + FlannelEnabled: cfgProvider.Cluster().Network().CNI().Name() != constants.CustomCNI, + FlannelImage: images.Flannel, + FlannelCNIImage: images.FlannelCNI, + }) + + return nil + }) +} + +func (ctrl *K8sControlPlaneController) manageExtraManifestsConfig(ctx context.Context, r controller.Runtime, logger *log.Logger, cfgProvider talosconfig.Provider) error { + return r.Update(ctx, config.NewK8sExtraManifests(), func(r resource.Resource) error { + spec := config.K8sExtraManifestsSpec{} + + if cfgProvider.Cluster().Network().CNI().Name() == constants.CustomCNI { + for _, url := range cfgProvider.Cluster().Network().CNI().URLs() { + spec.ExtraManifests = append(spec.ExtraManifests, config.ExtraManifest{ + URL: url, + Priority: "05", // push CNI to the top + }) + } + } + + for _, url := range cfgProvider.Cluster().ExtraManifestURLs() { + spec.ExtraManifests = append(spec.ExtraManifests, config.ExtraManifest{ + URL: url, + Priority: "99", // make sure extra manifests come last, when PSP is already created + ExtraHeaders: cfgProvider.Cluster().ExtraManifestHeaderMap(), + }) + } + + r.(*config.K8sControlPlane).SetExtraManifests(spec) + + return nil + }) +} + +func (ctrl *K8sControlPlaneController) teardownAll(ctx context.Context, r controller.Runtime, logger *log.Logger) error { + return nil +} diff --git a/internal/app/machined/pkg/controllers/config/machine_type.go b/internal/app/machined/pkg/controllers/config/machine_type.go new file mode 100644 index 000000000..49bd8423c --- /dev/null +++ b/internal/app/machined/pkg/controllers/config/machine_type.go @@ -0,0 +1,74 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package config + +import ( + "context" + "fmt" + "log" + + "github.com/AlekSi/pointer" + "github.com/talos-systems/os-runtime/pkg/controller" + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/state" + + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/config" + "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" +) + +// MachineTypeController manages config.MachineType based on configuration. +type MachineTypeController struct { +} + +// Name implements controller.Controller interface. +func (ctrl *MachineTypeController) Name() string { + return "config.MachineTypeController" +} + +// ManagedResources implements controller.Controller interface. +func (ctrl *MachineTypeController) ManagedResources() (resource.Namespace, resource.Type) { + return config.NamespaceName, config.MachineTypeType +} + +// Run implements controller.Controller interface. +func (ctrl *MachineTypeController) Run(ctx context.Context, r controller.Runtime, logger *log.Logger) error { + if err := r.UpdateDependencies([]controller.Dependency{ + { + Namespace: config.NamespaceName, + Type: config.V1Alpha1Type, + ID: pointer.ToString(config.V1Alpha1ID), + Kind: controller.DependencyWeak, + }, + }); err != nil { + return fmt.Errorf("error setting up dependencies: %w", err) + } + + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + var machineType machine.Type + + cfg, err := r.Get(ctx, resource.NewMetadata(config.NamespaceName, config.V1Alpha1Type, config.V1Alpha1ID, resource.VersionUndefined)) + if err != nil { + if !state.IsNotFoundError(err) { + return fmt.Errorf("error getting config: %w", err) + } + } else { + machineType = cfg.(*config.V1Alpha1).Config().Machine().Type() + } + + if err = r.Update(ctx, config.NewMachineType(), func(r resource.Resource) error { + r.(*config.MachineType).SetMachineType(machineType) + + return nil + }); err != nil { + return fmt.Errorf("error updating objects: %w", err) + } + } +} diff --git a/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod.go b/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod.go new file mode 100644 index 000000000..1139c73bc --- /dev/null +++ b/internal/app/machined/pkg/controllers/k8s/control_plane_static_pod.go @@ -0,0 +1,410 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "context" + "fmt" + "log" + "path/filepath" + "strings" + + "github.com/AlekSi/pointer" + "github.com/talos-systems/os-runtime/pkg/controller" + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/state" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/config" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/k8s" + "github.com/talos-systems/talos/pkg/machinery/constants" +) + +// ControlPlaneStaticPodController manages k8s.StaticPod based on control plane configuration. +type ControlPlaneStaticPodController struct{} + +// Name implements controller.Controller interface. +func (ctrl *ControlPlaneStaticPodController) Name() string { + return "k8s.ControlPlaneStaticPodController" +} + +// ManagedResources implements controller.Controller interface. +func (ctrl *ControlPlaneStaticPodController) ManagedResources() (resource.Namespace, resource.Type) { + return k8s.ControlPlaneNamespaceName, k8s.StaticPodType +} + +// Run implements controller.Controller interface. +// +//nolint: gocyclo +func (ctrl *ControlPlaneStaticPodController) Run(ctx context.Context, r controller.Runtime, logger *log.Logger) error { + if err := r.UpdateDependencies([]controller.Dependency{ + { + Namespace: config.NamespaceName, + Type: config.K8sControlPlaneType, + Kind: controller.DependencyWeak, + }, + { + Namespace: k8s.ControlPlaneNamespaceName, + Type: k8s.SecretsStatusType, + ID: pointer.ToString(k8s.StaticPodSecretsStaticPodID), + Kind: controller.DependencyWeak, + }, + }); err != nil { + return fmt.Errorf("error setting up dependencies: %w", err) + } + + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + secretsStatusResource, err := r.Get(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.SecretsStatusType, k8s.StaticPodSecretsStaticPodID, resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + if err = ctrl.teardownAll(ctx, r); err != nil { + return fmt.Errorf("error tearing down: %w", err) + } + + continue + } + + return err + } + + secretsVersion := secretsStatusResource.(*k8s.SecretsStatus).Status().Version + + for _, pod := range []struct { + f func(context.Context, controller.Runtime, *log.Logger, *config.K8sControlPlane, string) error + id resource.ID + }{ + { + f: ctrl.manageAPIServer, + id: config.K8sControlPlaneAPIServerID, + }, + { + f: ctrl.manageControllerManager, + id: config.K8sControlPlaneControllerManagerID, + }, + { + f: ctrl.manageScheduler, + id: config.K8sControlPlaneSchedulerID, + }, + } { + res, err := r.Get(ctx, resource.NewMetadata(config.NamespaceName, config.K8sControlPlaneType, pod.id, resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return fmt.Errorf("error getting control plane config: %w", err) + } + + if err = pod.f(ctx, r, logger, res.(*config.K8sControlPlane), secretsVersion); err != nil { + return fmt.Errorf("error updating static pod for %q: %w", pod.id, err) + } + } + } +} + +func (ctrl *ControlPlaneStaticPodController) teardownAll(ctx context.Context, r controller.Runtime) error { + list, err := r.List(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.StaticPodType, "", resource.VersionUndefined)) + if err != nil { + return err + } + + // TODO: change this to proper teardown sequence + + for _, res := range list.Items { + if err = r.Destroy(ctx, res.Metadata()); err != nil { + return err + } + } + + return nil +} + +func (ctrl *ControlPlaneStaticPodController) manageAPIServer(ctx context.Context, r controller.Runtime, logger *log.Logger, configResource *config.K8sControlPlane, secretsVersion string) error { + cfg := configResource.APIServer() + + args := []string{ + "/go-runner", + "/usr/local/bin/kube-apiserver", + "--enable-admission-plugins=PodSecurityPolicy,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeClaimResize,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,Priority,NodeRestriction", //nolint: lll + "--advertise-address=$(POD_IP)", + "--allow-privileged=true", + fmt.Sprintf("--api-audiences=%s", cfg.ControlPlaneEndpoint), + "--authorization-mode=Node,RBAC", + "--bind-address=0.0.0.0", + fmt.Sprintf("--client-ca-file=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "ca.crt")), + fmt.Sprintf("--requestheader-client-ca-file=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "aggregator-ca.crt")), + "--requestheader-allowed-names=front-proxy-client", + "--requestheader-extra-headers-prefix=X-Remote-Extra-", + "--requestheader-group-headers=X-Remote-Group", + "--requestheader-username-headers=X-Remote-User", + fmt.Sprintf("--proxy-client-cert-file=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "front-proxy-client.crt")), + fmt.Sprintf("--proxy-client-key-file=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "front-proxy-client.key")), + fmt.Sprintf("--cloud-provider=%s", cfg.CloudProvider), + "--enable-bootstrap-token-auth=true", + "--tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256", //nolint: lll + fmt.Sprintf("--encryption-provider-config=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "encryptionconfig.yaml")), + fmt.Sprintf("--audit-policy-file=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "auditpolicy.yaml")), + "--audit-log-path=-", + "--audit-log-maxage=30", + "--audit-log-maxbackup=3", + "--audit-log-maxsize=50", + "--profiling=false", + fmt.Sprintf("--etcd-cafile=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "etcd-client-ca.crt")), + fmt.Sprintf("--etcd-certfile=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "etcd-client.crt")), + fmt.Sprintf("--etcd-keyfile=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "etcd-client.key")), + fmt.Sprintf("--etcd-servers=%s", strings.Join(cfg.EtcdServers, ",")), + "--insecure-port=0", + fmt.Sprintf("--kubelet-client-certificate=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "apiserver-kubelet-client.crt")), + fmt.Sprintf("--kubelet-client-key=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "apiserver-kubelet-client.key")), + fmt.Sprintf("--secure-port=%d", cfg.LocalPort), + fmt.Sprintf("--service-account-issuer=%s", cfg.ControlPlaneEndpoint), + fmt.Sprintf("--service-account-key-file=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "service-account.pub")), + fmt.Sprintf("--service-account-signing-key-file=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "service-account.key")), + fmt.Sprintf("--service-cluster-ip-range=%s", cfg.ServiceCIDR), + fmt.Sprintf("--tls-cert-file=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "apiserver.crt")), + fmt.Sprintf("--tls-private-key-file=%s", filepath.Join(constants.KubernetesAPIServerSecretsDir, "apiserver.key")), + "--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname", + } + + for k, v := range cfg.ExtraArgs { + args = append(args, fmt.Sprintf("--%s=%s", k, v)) + } + + return r.Update(ctx, k8s.NewStaticPod(k8s.ControlPlaneNamespaceName, "kube-apiserver", nil), func(r resource.Resource) error { + r.(*k8s.StaticPod).SetPod(&v1.Pod{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Pod", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "kube-apiserver", + Namespace: "kube-system", + Labels: map[string]string{ + "tier": "control-plane", + "k8s-app": "kube-apiserver", + "secrets-version": secretsVersion, + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "kube-apiserver", + Image: cfg.Image, + Command: args, + Env: []v1.EnvVar{ + { + Name: "POD_IP", + ValueFrom: &v1.EnvVarSource{ + FieldRef: &v1.ObjectFieldSelector{ + FieldPath: "status.podIP", + }, + }, + }, + }, + VolumeMounts: []v1.VolumeMount{ + { + Name: "secrets", + MountPath: constants.KubernetesAPIServerSecretsDir, + ReadOnly: true, + }, + }, + }, + }, + HostNetwork: true, + SecurityContext: &v1.PodSecurityContext{ + RunAsNonRoot: pointer.ToBool(true), + RunAsUser: pointer.ToInt64(constants.KubernetesRunUser), + }, + Volumes: []v1.Volume{ + { + Name: "secrets", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: constants.KubernetesAPIServerSecretsDir, + }, + }, + }, + }, + }, + }) + + return nil + }) +} + +func (ctrl *ControlPlaneStaticPodController) manageControllerManager(ctx context.Context, r controller.Runtime, + logger *log.Logger, configResource *config.K8sControlPlane, secretsVersion string) error { + cfg := configResource.ControllerManager() + + args := []string{ + "/go-runner", + "/usr/local/bin/kube-controller-manager", + "--allocate-node-cidrs=true", + fmt.Sprintf("--cloud-provider=%s", cfg.CloudProvider), + fmt.Sprintf("--cluster-cidr=%s", cfg.PodCIDR), + fmt.Sprintf("--service-cluster-ip-range=%s", cfg.ServiceCIDR), + fmt.Sprintf("--cluster-signing-cert-file=%s", filepath.Join(constants.KubernetesControllerManagerSecretsDir, "ca.crt")), + fmt.Sprintf("--cluster-signing-key-file=%s", filepath.Join(constants.KubernetesControllerManagerSecretsDir, "ca.key")), + "--configure-cloud-routes=false", + fmt.Sprintf("--kubeconfig=%s", filepath.Join(constants.KubernetesControllerManagerSecretsDir, "kubeconfig")), + "--leader-elect=true", + fmt.Sprintf("--root-ca-file=%s", filepath.Join(constants.KubernetesControllerManagerSecretsDir, "ca.crt")), + fmt.Sprintf("--service-account-private-key-file=%s", filepath.Join(constants.KubernetesControllerManagerSecretsDir, "service-account.key")), + "--profiling=false", + } + + for k, v := range cfg.ExtraArgs { + args = append(args, fmt.Sprintf("--%s=%s", k, v)) + } + + //nolint: dupl + return r.Update(ctx, k8s.NewStaticPod(k8s.ControlPlaneNamespaceName, "kube-controller-manager", nil), func(r resource.Resource) error { + r.(*k8s.StaticPod).SetPod(&v1.Pod{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Pod", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "kube-controller-manager", + Namespace: "kube-system", + Labels: map[string]string{ + "tier": "control-plane", + "k8s-app": "kube-controller-manager", + "secrets-version": secretsVersion, + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "kube-controller-manager", + Image: cfg.Image, + Command: args, + VolumeMounts: []v1.VolumeMount{ + { + Name: "secrets", + MountPath: constants.KubernetesControllerManagerSecretsDir, + ReadOnly: true, + }, + }, + LivenessProbe: &v1.Probe{ + Handler: v1.Handler{ + HTTPGet: &v1.HTTPGetAction{ + Path: "/healthz", + Port: intstr.FromInt(10252), + }, + }, + InitialDelaySeconds: 15, + TimeoutSeconds: 15, + }, + }, + }, + HostNetwork: true, + SecurityContext: &v1.PodSecurityContext{ + RunAsNonRoot: pointer.ToBool(true), + RunAsUser: pointer.ToInt64(constants.KubernetesRunUser), + }, + Volumes: []v1.Volume{ + { + Name: "secrets", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: constants.KubernetesControllerManagerSecretsDir, + }, + }, + }, + }, + }, + }) + + return nil + }) +} + +func (ctrl *ControlPlaneStaticPodController) manageScheduler(ctx context.Context, r controller.Runtime, + logger *log.Logger, configResource *config.K8sControlPlane, secretsVersion string) error { + cfg := configResource.Scheduler() + + args := []string{ + "/go-runner", + "/usr/local/bin/kube-scheduler", + fmt.Sprintf("--kubeconfig=%s", filepath.Join(constants.KubernetesSchedulerSecretsDir, "kubeconfig")), + "--leader-elect=true", + "--profiling=false", + } + + for k, v := range cfg.ExtraArgs { + args = append(args, fmt.Sprintf("--%s=%s", k, v)) + } + + //nolint: dupl + return r.Update(ctx, k8s.NewStaticPod(k8s.ControlPlaneNamespaceName, "kube-scheduler", nil), func(r resource.Resource) error { + r.(*k8s.StaticPod).SetPod(&v1.Pod{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Pod", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "kube-scheduler", + Namespace: "kube-system", + Labels: map[string]string{ + "tier": "control-plane", + "k8s-app": "kube-scheduler", + "secrets-version": secretsVersion, + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "kube-scheduler", + Image: cfg.Image, + Command: args, + VolumeMounts: []v1.VolumeMount{ + { + Name: "secrets", + MountPath: constants.KubernetesSchedulerSecretsDir, + ReadOnly: true, + }, + }, + LivenessProbe: &v1.Probe{ + Handler: v1.Handler{ + HTTPGet: &v1.HTTPGetAction{ + Path: "/healthz", + Port: intstr.FromInt(10251), + }, + }, + InitialDelaySeconds: 15, + TimeoutSeconds: 15, + }, + }, + }, + HostNetwork: true, + SecurityContext: &v1.PodSecurityContext{ + RunAsNonRoot: pointer.ToBool(true), + RunAsUser: pointer.ToInt64(constants.KubernetesRunUser), + }, + Volumes: []v1.Volume{ + { + Name: "secrets", + VolumeSource: v1.VolumeSource{ + HostPath: &v1.HostPathVolumeSource{ + Path: constants.KubernetesSchedulerSecretsDir, + }, + }, + }, + }, + }, + }) + + return nil + }) +} diff --git a/internal/app/machined/pkg/controllers/k8s/extra_manifest.go b/internal/app/machined/pkg/controllers/k8s/extra_manifest.go new file mode 100644 index 000000000..f4116a024 --- /dev/null +++ b/internal/app/machined/pkg/controllers/k8s/extra_manifest.go @@ -0,0 +1,215 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "context" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "path/filepath" + + "github.com/AlekSi/pointer" + "github.com/hashicorp/go-getter" + "github.com/hashicorp/go-multierror" + "github.com/talos-systems/os-runtime/pkg/controller" + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/state" + + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/config" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/k8s" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/v1alpha1" +) + +// ExtraManifestController renders manifests based on templates and config/secrets. +type ExtraManifestController struct{} + +// Name implements controller.Controller interface. +func (ctrl *ExtraManifestController) Name() string { + return "k8s.ExtraManifestController" +} + +// ManagedResources implements controller.Controller interface. +func (ctrl *ExtraManifestController) ManagedResources() (resource.Namespace, resource.Type) { + return k8s.ExtraNamespaceName, k8s.ManifestType +} + +// Run implements controller.Controller interface. +// +//nolint: gocyclo +func (ctrl *ExtraManifestController) Run(ctx context.Context, r controller.Runtime, logger *log.Logger) error { + if err := r.UpdateDependencies([]controller.Dependency{ + { + Namespace: config.NamespaceName, + Type: config.K8sControlPlaneType, + ID: pointer.ToString(config.K8sExtraManifestsID), + Kind: controller.DependencyWeak, + }, + { + Namespace: v1alpha1.NamespaceName, + Type: v1alpha1.ServiceType, + ID: pointer.ToString("networkd"), + Kind: controller.DependencyWeak, + }, + }); err != nil { + return fmt.Errorf("error setting up dependencies: %w", err) + } + + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + // wait for networkd to be healthy as networking is required to download extra manifests + networkdResource, err := r.Get(ctx, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, "networkd", resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return err + } + + if !networkdResource.(*v1alpha1.Service).Healthy() { + continue + } + + configResource, err := r.Get(ctx, resource.NewMetadata(config.NamespaceName, config.K8sControlPlaneType, config.K8sExtraManifestsID, resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + if err = ctrl.teardownAll(ctx, r); err != nil { + return fmt.Errorf("error tearing down: %w", err) + } + + continue + } + + return err + } + + config := configResource.(*config.K8sControlPlane).ExtraManifests() + + var multiErr *multierror.Error + + presentManifests := map[resource.ID]struct{}{} + + for _, manifest := range config.ExtraManifests { + var id resource.ID + + id, err = ctrl.download(ctx, r, logger, manifest) + if err != nil { + multiErr = multierror.Append(multiErr, err) + } + + presentManifests[id] = struct{}{} + } + + if multiErr.ErrorOrNil() != nil { + return multiErr.ErrorOrNil() + } + + allManifests, err := r.List(ctx, resource.NewMetadata(k8s.ExtraNamespaceName, k8s.ManifestType, "", resource.VersionUndefined)) + if err != nil { + return fmt.Errorf("error listing extra manifests: %w", err) + } + + for _, manifest := range allManifests.Items { + if _, exists := presentManifests[manifest.Metadata().ID()]; !exists { + if err = r.Destroy(ctx, manifest.Metadata()); err != nil { + return fmt.Errorf("error cleaning up extra manifest: %w", err) + } + } + } + } +} + +func (ctrl *ExtraManifestController) download(ctx context.Context, r controller.Runtime, logger *log.Logger, manifest config.ExtraManifest) (id resource.ID, err error) { + id = fmt.Sprintf("%s-%s", manifest.Priority, manifest.URL) + + var tmpDir string + + tmpDir, err = ioutil.TempDir("", "talos") + if err != nil { + return + } + + defer os.RemoveAll(tmpDir) //nolint: errcheck + + fileName := filepath.Base(manifest.URL) + + // I wish we never used go-getter package, as it doesn't allow downloading into memory. + // But there's not much we can do about it right now, as it supports lots of magic + // users might rely upon now. + + // Disable netrc since we don't have getent installed, and most likely + // never will. + httpGetter := &getter.HttpGetter{ + Netrc: false, + Client: http.DefaultClient, + } + + httpGetter.Header = make(http.Header) + + for k, v := range manifest.ExtraHeaders { + httpGetter.Header.Add(k, v) + } + + getter.Getters["http"] = httpGetter + getter.Getters["https"] = httpGetter + + client := &getter.Client{ + Ctx: ctx, + Src: manifest.URL, + Dst: filepath.Join(tmpDir, fileName), + Pwd: tmpDir, + Mode: getter.ClientModeFile, + Options: []getter.ClientOption{}, + } + + if err = client.Get(); err != nil { + err = fmt.Errorf("error downloading %q: %w", manifest.URL, err) + + return + } + + logger.Printf("downloaded manifest %q", manifest.URL) + + var contents []byte + + contents, err = ioutil.ReadFile(client.Dst) + if err != nil { + return + } + + if err = r.Update(ctx, k8s.NewManifest(k8s.ExtraNamespaceName, id), + func(r resource.Resource) error { + return r.(*k8s.Manifest).SetYAML(contents) + }); err != nil { + err = fmt.Errorf("error updating manifests: %w", err) + + return + } + + return id, nil +} + +func (ctrl *ExtraManifestController) teardownAll(ctx context.Context, r controller.Runtime) error { + manifests, err := r.List(ctx, resource.NewMetadata(k8s.ExtraNamespaceName, k8s.ManifestType, "", resource.VersionUndefined)) + if err != nil { + return fmt.Errorf("error listing extra manifests: %w", err) + } + + for _, manifest := range manifests.Items { + if err = r.Destroy(ctx, manifest.Metadata()); err != nil { + return fmt.Errorf("error destroying extra manifest: %w", err) + } + } + + return nil +} diff --git a/internal/app/machined/pkg/controllers/k8s/k8s.go b/internal/app/machined/pkg/controllers/k8s/k8s.go new file mode 100644 index 000000000..9aef70c2e --- /dev/null +++ b/internal/app/machined/pkg/controllers/k8s/k8s.go @@ -0,0 +1,16 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package k8s provides controllers which manage Kubernetes resources. +package k8s + +import ( + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +func init() { + // ugly hack, but it doesn't look like there's better API + // cut out error handler which logs error to standard logger + utilruntime.ErrorHandlers = utilruntime.ErrorHandlers[len(utilruntime.ErrorHandlers)-1:] +} diff --git a/internal/app/machined/pkg/controllers/k8s/kubelet_static_pod_controller.go b/internal/app/machined/pkg/controllers/k8s/kubelet_static_pod_controller.go new file mode 100644 index 000000000..2843928f3 --- /dev/null +++ b/internal/app/machined/pkg/controllers/k8s/kubelet_static_pod_controller.go @@ -0,0 +1,287 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "bytes" + "context" + "crypto/tls" + "fmt" + "io/ioutil" + "log" + "os" + "path/filepath" + "time" + + "github.com/AlekSi/pointer" + "github.com/talos-systems/os-runtime/pkg/controller" + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/state" + "gopkg.in/yaml.v3" + + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/k8s" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/secrets" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/v1alpha1" + "github.com/talos-systems/talos/pkg/kubernetes/kubelet" + "github.com/talos-systems/talos/pkg/machinery/constants" +) + +// KubeletStaticPodController renders static pod definitions and manages k8s.StaticPodStatus. +type KubeletStaticPodController struct{} + +// Name implements controller.Controller interface. +func (ctrl *KubeletStaticPodController) Name() string { + return "k8s.KubeletStaticPodController" +} + +// ManagedResources implements controller.Controller interface. +func (ctrl *KubeletStaticPodController) ManagedResources() (resource.Namespace, resource.Type) { + return k8s.ControlPlaneNamespaceName, k8s.StaticPodStatusType +} + +// Run implements controller.Controller interface. +// +//nolint: gocyclo +func (ctrl *KubeletStaticPodController) Run(ctx context.Context, r controller.Runtime, logger *log.Logger) error { + if err := r.UpdateDependencies([]controller.Dependency{ + { + Namespace: k8s.ControlPlaneNamespaceName, + Type: k8s.StaticPodType, + Kind: controller.DependencyStrong, + }, + { + Namespace: v1alpha1.NamespaceName, + Type: v1alpha1.ServiceType, + ID: pointer.ToString("kubelet"), + Kind: controller.DependencyWeak, + }, + { + Namespace: secrets.NamespaceName, + Type: secrets.KubernetesType, + ID: pointer.ToString(secrets.KubernetesID), + Kind: controller.DependencyWeak, + }, + { + Namespace: v1alpha1.NamespaceName, + Type: v1alpha1.BootstrapStatusType, + ID: pointer.ToString(v1alpha1.BootstrapStatusID), + Kind: controller.DependencyWeak, + }, + }); err != nil { + return fmt.Errorf("error setting up dependencies: %w", err) + } + + var kubeletClient *kubelet.Client + + refreshTicker := time.NewTicker(15 * time.Second) // refresh kubelet pods status every 15 seconds + defer refreshTicker.Stop() + + for { + select { + case <-ctx.Done(): + return nil + case <-refreshTicker.C: + if kubeletClient != nil { + if err := ctrl.refreshPodStatus(ctx, r, kubeletClient); err != nil { + return fmt.Errorf("error refreshing pod status: %w", err) + } + } + + continue + case <-r.EventCh(): + } + + kubeletResource, err := r.Get(ctx, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, "kubelet", resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + kubeletClient = nil + + if err = ctrl.teardownStatuses(ctx, r); err != nil { + return fmt.Errorf("error tearing down: %w", err) + } + + continue + } + + return err + } + + if !kubeletResource.(*v1alpha1.Service).Running() { + kubeletClient = nil + + if err = ctrl.teardownStatuses(ctx, r); err != nil { + return fmt.Errorf("error tearing down: %w", err) + } + + continue + } + + secretsResources, err := r.Get(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesType, secrets.KubernetesID, resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return err + } + + secrets := secretsResources.(*secrets.Kubernetes).Secrets() + + bootstrapStatus, err := r.Get(ctx, v1alpha1.NewBootstrapStatus().Metadata()) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return err + } + + if bootstrapStatus.(*v1alpha1.BootstrapStatus).Status().SelfHostedControlPlane { + logger.Print("skipped as running self-hosted control plane") + + continue + } + + kubeletClientCert, err := tls.X509KeyPair(secrets.APIServerKubeletClient.Crt, secrets.APIServerKubeletClient.Key) + if err != nil { + return fmt.Errorf("error loading apiserver kubelet client cert: %w", err) + } + + kubeletClient, err = kubelet.NewClient(kubeletClientCert) + if err != nil { + return fmt.Errorf("error building kubelet client: %w", err) + } + + staticPods, err := r.List(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.StaticPodType, "", resource.VersionUndefined)) + if err != nil { + return fmt.Errorf("error listing static pods: %w", err) + } + + for _, staticPod := range staticPods.Items { + switch staticPod.Metadata().Phase() { + case resource.PhaseRunning: + if err = ctrl.runPod(ctx, r, logger, staticPod.(*k8s.StaticPod)); err != nil { + return fmt.Errorf("error running pod: %w", err) + } + case resource.PhaseTearingDown: + if err = ctrl.teardownPod(logger, staticPod.(*k8s.StaticPod)); err != nil { + return fmt.Errorf("error tearing down pod: %w", err) + } + } + } + } +} + +func (ctrl *KubeletStaticPodController) runPod(ctx context.Context, r controller.Runtime, logger *log.Logger, staticPod *k8s.StaticPod) error { + staticPodStatus := k8s.NewStaticPodStatus(staticPod.Metadata().Namespace(), staticPod.Metadata().ID()) + + if err := r.AddFinalizer(ctx, staticPod.Metadata(), staticPodStatus.String()); err != nil { + return err + } + + renderedPod, err := yaml.Marshal(staticPod.Spec()) + if err != nil { + return nil + } + + podPath := filepath.Join(constants.ManifestsDirectory, fmt.Sprintf("%s.yaml", staticPod.Metadata().ID())) + + existingPod, err := ioutil.ReadFile(podPath) + if err != nil { + if !os.IsNotExist(err) { + return err + } + } + + if bytes.Equal(renderedPod, existingPod) { + return nil + } + + logger.Printf("writing static pod %q", podPath) + + return ioutil.WriteFile(podPath, renderedPod, 0o600) +} + +func (ctrl *KubeletStaticPodController) teardownPod(logger *log.Logger, staticPod *k8s.StaticPod) error { + podPath := filepath.Join(constants.ManifestsDirectory, fmt.Sprintf("%s.yaml", staticPod.Metadata().ID())) + + _, err := os.Stat(podPath) + if err != nil { + if os.IsNotExist(err) { + return nil + } + + return fmt.Errorf("error checking static pod status: %w", err) + } + + logger.Printf("removing static pod %q", podPath) + + if err = os.Remove(podPath); err != nil { + return fmt.Errorf("error removing static pod %q: %w", podPath, err) + } + + return nil +} + +func (ctrl *KubeletStaticPodController) teardownStatuses(ctx context.Context, r controller.Runtime) error { + statuses, err := r.List(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.StaticPodStatusType, "", resource.VersionUndefined)) + if err != nil { + return fmt.Errorf("error listing pod statuses: %w", err) + } + + for _, status := range statuses.Items { + // TODO: proper teardown sequence? + if err = r.Destroy(ctx, status.Metadata()); err != nil { + return fmt.Errorf("error destroying stale pod status: %w", err) + } + } + + return nil +} + +func (ctrl *KubeletStaticPodController) refreshPodStatus(ctx context.Context, r controller.Runtime, kubeletClient *kubelet.Client) error { + podList, err := kubeletClient.Pods(ctx) + if err != nil { + return fmt.Errorf("error fetching pod status: %w", err) + } + + podsSeen := map[string]struct{}{} + + for _, pod := range podList.Items { + if pod.OwnerReferences != nil { + continue + } + + pod := pod + + statusID := fmt.Sprintf("%s/%s", pod.Namespace, pod.Name) + + podsSeen[statusID] = struct{}{} + + if err = r.Update(ctx, k8s.NewStaticPodStatus(k8s.ControlPlaneNamespaceName, statusID), func(r resource.Resource) error { + r.(*k8s.StaticPodStatus).SetStatus(&pod.Status) + + return nil + }); err != nil { + return fmt.Errorf("error updating pod status: %w", err) + } + } + + statuses, err := r.List(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.StaticPodStatusType, "", resource.VersionUndefined)) + if err != nil { + return fmt.Errorf("error listing pod statuses: %w", err) + } + + for _, status := range statuses.Items { + if _, exists := podsSeen[status.Metadata().ID()]; !exists { + // TODO: proper teardown sequence? + if err = r.Destroy(ctx, status.Metadata()); err != nil { + return fmt.Errorf("error destroying stale pod status: %w", err) + } + } + } + + return nil +} diff --git a/internal/app/machined/pkg/controllers/k8s/manifest.go b/internal/app/machined/pkg/controllers/k8s/manifest.go new file mode 100644 index 000000000..726060767 --- /dev/null +++ b/internal/app/machined/pkg/controllers/k8s/manifest.go @@ -0,0 +1,218 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "bytes" + "context" + "fmt" + "html/template" + "log" + + "github.com/AlekSi/pointer" + "github.com/talos-systems/os-runtime/pkg/controller" + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/state" + + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/config" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/k8s" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/secrets" +) + +// ManifestController renders manifests based on templates and config/secrets. +type ManifestController struct{} + +// Name implements controller.Controller interface. +func (ctrl *ManifestController) Name() string { + return "k8s.ManifestController" +} + +// ManagedResources implements controller.Controller interface. +func (ctrl *ManifestController) ManagedResources() (resource.Namespace, resource.Type) { + return k8s.ControlPlaneNamespaceName, k8s.ManifestType +} + +// Run implements controller.Controller interface. +// +//nolint: gocyclo +func (ctrl *ManifestController) Run(ctx context.Context, r controller.Runtime, logger *log.Logger) error { + if err := r.UpdateDependencies([]controller.Dependency{ + { + Namespace: config.NamespaceName, + Type: config.K8sControlPlaneType, + ID: pointer.ToString(config.K8sManifestsID), + Kind: controller.DependencyWeak, + }, + { + Namespace: secrets.NamespaceName, + Type: secrets.KubernetesType, + ID: pointer.ToString(secrets.KubernetesID), + Kind: controller.DependencyWeak, + }, + }); err != nil { + return fmt.Errorf("error setting up dependencies: %w", err) + } + + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + configResource, err := r.Get(ctx, resource.NewMetadata(config.NamespaceName, config.K8sControlPlaneType, config.K8sManifestsID, resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + if err = ctrl.teardownAll(ctx, r); err != nil { + return fmt.Errorf("error tearing down: %w", err) + } + + continue + } + + return err + } + + config := configResource.(*config.K8sControlPlane).Manifests() + + secretsResources, err := r.Get(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesType, secrets.KubernetesID, resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + if err = ctrl.teardownAll(ctx, r); err != nil { + return fmt.Errorf("error tearing down: %w", err) + } + + continue + } + + return err + } + + secrets := secretsResources.(*secrets.Kubernetes).Secrets() + + renderedManifests, err := ctrl.render(config, *secrets) + if err != nil { + return err + } + + for _, renderedManifest := range renderedManifests { + renderedManifest := renderedManifest + + if err = r.Update(ctx, k8s.NewManifest(k8s.ControlPlaneNamespaceName, renderedManifest.name), + func(r resource.Resource) error { + return r.(*k8s.Manifest).SetYAML(renderedManifest.data) + }); err != nil { + return fmt.Errorf("error updating manifests: %w", err) + } + } + + // remove any manifests which weren't rendered + manifests, err := r.List(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, "", resource.VersionUndefined)) + if err != nil { + return fmt.Errorf("error listing manifests: %w", err) + } + + manifestsToDelete := map[string]struct{}{} + + for _, manifest := range manifests.Items { + manifestsToDelete[manifest.Metadata().ID()] = struct{}{} + } + + for _, renderedManifest := range renderedManifests { + delete(manifestsToDelete, renderedManifest.name) + } + + for id := range manifestsToDelete { + if err = r.Destroy(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, id, resource.VersionUndefined)); err != nil { + return fmt.Errorf("error cleaning up manifests: %w", err) + } + } + } +} + +type renderedManifest struct { + name string + data []byte +} + +func (ctrl *ManifestController) render(cfg config.K8sManifestsSpec, scrt secrets.KubernetesSpec) ([]renderedManifest, error) { + templateConfig := struct { + config.K8sManifestsSpec + + Secrets secrets.KubernetesSpec + }{ + K8sManifestsSpec: cfg, + Secrets: scrt, + } + + type manifestDesc struct { + name string + template []byte + } + + defaultManifests := []manifestDesc{ + {"00-kubelet-bootstrapping-token", kubeletBootstrappingToken}, + {"01-csr-node-bootstrap", csrNodeBootstrapTemplate}, + {"01-csr-approver-role-binding", csrApproverRoleBindingTemplate}, + {"01-csr-renewal-role-binding", csrRenewalRoleBindingTemplate}, + {"02-kube-system-sa-role-binding", kubeSystemSARoleBindingTemplate}, + {"03-default-pod-security-policy", podSecurityPolicy}, + {"10-kube-proxy", kubeProxyTemplate}, + {"11-kube-config-in-cluster", kubeConfigInClusterTemplate}, + {"11-core-dns", coreDNSTemplate}, + {"11-core-dns-svc", coreDNSSvcTemplate}, + } + + if cfg.DNSServiceIPv6 != "" { + defaultManifests = append(defaultManifests, + []manifestDesc{ + {"11-core-dns-v6-svc", coreDNSv6SvcTemplate}, + }..., + ) + } + + if cfg.FlannelEnabled { + defaultManifests = append(defaultManifests, + []manifestDesc{ + {"05-flannel", flannelTemplate}, + }..., + ) + } + + manifests := make([]renderedManifest, len(defaultManifests)) + + for i := range defaultManifests { + tmpl, err := template.New(defaultManifests[i].name).Parse(string(defaultManifests[i].template)) + if err != nil { + return nil, fmt.Errorf("error parsing manifest template %q: %w", defaultManifests[i].name, err) + } + + var buf bytes.Buffer + + if err = tmpl.Execute(&buf, &templateConfig); err != nil { + return nil, fmt.Errorf("error executing template %q: %w", defaultManifests[i].name, err) + } + + manifests[i].name = defaultManifests[i].name + manifests[i].data = buf.Bytes() + } + + return manifests, nil +} + +func (ctrl *ManifestController) teardownAll(ctx context.Context, r controller.Runtime) error { + manifests, err := r.List(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, "", resource.VersionUndefined)) + if err != nil { + return fmt.Errorf("error listing manifests: %w", err) + } + + for _, manifest := range manifests.Items { + if err = r.Destroy(ctx, manifest.Metadata()); err != nil { + return fmt.Errorf("error destroying manifest: %w", err) + } + } + + return nil +} diff --git a/internal/app/machined/pkg/controllers/k8s/manifest_apply.go b/internal/app/machined/pkg/controllers/k8s/manifest_apply.go new file mode 100644 index 000000000..ac13d6e7a --- /dev/null +++ b/internal/app/machined/pkg/controllers/k8s/manifest_apply.go @@ -0,0 +1,305 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "context" + "fmt" + "log" + "sort" + + "github.com/AlekSi/pointer" + "github.com/talos-systems/os-runtime/pkg/controller" + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/state" + "go.etcd.io/etcd/clientv3/concurrency" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" + memory "k8s.io/client-go/discovery/cached" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/k8s" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/secrets" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/v1alpha1" + "github.com/talos-systems/talos/internal/pkg/etcd" + "github.com/talos-systems/talos/pkg/machinery/constants" +) + +// ManifestApplyController applies manifests via control plane endpoint. +type ManifestApplyController struct{} + +// Name implements controller.Controller interface. +func (ctrl *ManifestApplyController) Name() string { + return "k8s.ManifestApplyController" +} + +// ManagedResources implements controller.Controller interface. +func (ctrl *ManifestApplyController) ManagedResources() (resource.Namespace, resource.Type) { + return k8s.ControlPlaneNamespaceName, k8s.ManifestStatusType +} + +// Run implements controller.Controller interface. +// +//nolint: gocyclo +func (ctrl *ManifestApplyController) Run(ctx context.Context, r controller.Runtime, logger *log.Logger) error { + if err := r.UpdateDependencies([]controller.Dependency{ + { + Namespace: secrets.NamespaceName, + Type: secrets.KubernetesType, + ID: pointer.ToString(secrets.KubernetesID), + Kind: controller.DependencyWeak, + }, + { + Namespace: k8s.ControlPlaneNamespaceName, + Type: k8s.ManifestType, + Kind: controller.DependencyWeak, + }, + { + Namespace: k8s.ExtraNamespaceName, + Type: k8s.ManifestType, + Kind: controller.DependencyWeak, + }, + { + Namespace: v1alpha1.NamespaceName, + Type: v1alpha1.BootstrapStatusType, + ID: pointer.ToString(v1alpha1.BootstrapStatusID), + Kind: controller.DependencyWeak, + }, + }); err != nil { + return fmt.Errorf("error setting up dependencies: %w", err) + } + + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + secretsResources, err := r.Get(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesType, secrets.KubernetesID, resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return err + } + + secrets := secretsResources.(*secrets.Kubernetes).Secrets() + + bootstrapStatus, err := r.Get(ctx, v1alpha1.NewBootstrapStatus().Metadata()) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return err + } + + if bootstrapStatus.(*v1alpha1.BootstrapStatus).Status().SelfHostedControlPlane { + logger.Print("skipped as running self-hosted control plane") + + continue + } + + manifests, err := r.List(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, "", resource.VersionUndefined)) + if err != nil { + return fmt.Errorf("error listing manifests: %w", err) + } + + extraManifests, err := r.List(ctx, resource.NewMetadata(k8s.ExtraNamespaceName, k8s.ManifestType, "", resource.VersionUndefined)) + if err != nil { + return fmt.Errorf("error listing extra manifests: %w", err) + } + + manifests.Items = append(manifests.Items, extraManifests.Items...) + + sort.Slice(manifests.Items, func(i, j int) bool { + return manifests.Items[i].Metadata().ID() < manifests.Items[j].Metadata().ID() + }) + + if len(manifests.Items) > 0 { + var ( + kubeconfig *rest.Config + dc *discovery.DiscoveryClient + dyn dynamic.Interface + ) + + kubeconfig, err = clientcmd.BuildConfigFromKubeconfigGetter("", func() (*clientcmdapi.Config, error) { + return clientcmd.Load([]byte(secrets.AdminKubeconfig)) + }) + if err != nil { + return fmt.Errorf("error loading kubeconfig: %w", err) + } + + dc, err = discovery.NewDiscoveryClientForConfig(kubeconfig) + if err != nil { + return fmt.Errorf("error building discovery client: %w", err) + } + + mapper := restmapper.NewDeferredDiscoveryRESTMapper(memory.NewMemCacheClient(dc)) + + dyn, err = dynamic.NewForConfig(kubeconfig) + if err != nil { + return fmt.Errorf("error building dynamic client: %w", err) + } + + if err = ctrl.etcdLock(ctx, logger, func() error { + return ctrl.apply(ctx, logger, mapper, dyn, manifests) + }); err != nil { + return err + } + } + + if err = r.Update(ctx, k8s.NewManifestStatus(k8s.ControlPlaneNamespaceName), func(r resource.Resource) error { + status := r.(*k8s.ManifestStatus).Status() + + status.ManifestsApplied = make([]string, 0, len(manifests.Items)) + + for _, manifest := range manifests.Items { + status.ManifestsApplied = append(status.ManifestsApplied, manifest.Metadata().ID()) + } + + return nil + }); err != nil { + return fmt.Errorf("error updating manifest status: %w", err) + } + } +} + +func (ctrl *ManifestApplyController) etcdLock(ctx context.Context, logger *log.Logger, f func() error) error { + etcdClient, err := etcd.NewLocalClient() + if err != nil { + return fmt.Errorf("error creating etcd client: %w", err) + } + + defer etcdClient.Close() //nolint: errcheck + + session, err := concurrency.NewSession(etcdClient.Client) + if err != nil { + return fmt.Errorf("error creating etcd session: %w", err) + } + + defer session.Close() //nolint: errcheck + + mutex := concurrency.NewMutex(session, constants.EtcdTalosManifestApplyMutex) + + logger.Printf("waiting for mutex") + + if err := mutex.Lock(ctx); err != nil { + return fmt.Errorf("error acquiring mutex: %w", err) + } + + logger.Printf("mutex acquired") + + defer mutex.Unlock(ctx) //nolint: errcheck + + return f() +} + +//nolint: gocyclo +func (ctrl *ManifestApplyController) apply(ctx context.Context, logger *log.Logger, mapper *restmapper.DeferredDiscoveryRESTMapper, dyn dynamic.Interface, manifests resource.List) error { + // flatten list of objects to be applied + objects := make([]*unstructured.Unstructured, 0, len(manifests.Items)) + + for _, manifest := range manifests.Items { + objects = append(objects, manifest.(*k8s.Manifest).Objects()...) + } + + // sort the list so that namespaces come first, followed by CRDs and everything else after that + sort.SliceStable(objects, func(i, j int) bool { + objL := objects[i] + objR := objects[j] + + gvkL := objL.GroupVersionKind() + gvkR := objR.GroupVersionKind() + + if isNamespace(gvkL) { + if !isNamespace(gvkR) { + return true + } + + return objL.GetName() < objR.GetName() + } + + if isNamespace(gvkR) { + return false + } + + if isCRD(gvkL) { + if !isCRD(gvkR) { + return true + } + + return objL.GetName() < objR.GetName() + } + + if isCRD(gvkR) { + return false + } + + return false + }) + + for _, obj := range objects { + gvk := obj.GroupVersionKind() + objName := fmt.Sprintf("%s/%s/%s/%s", gvk.Group, gvk.Version, gvk.Kind, obj.GetName()) + + mapping, err := mapper.RESTMapping(obj.GroupVersionKind().GroupKind(), obj.GroupVersionKind().Version) + if err != nil { + return fmt.Errorf("error creating mapping for object %s: %w", objName, err) + } + + var dr dynamic.ResourceInterface + if mapping.Scope.Name() == meta.RESTScopeNameNamespace { + // namespaced resources should specify the namespace + dr = dyn.Resource(mapping.Resource).Namespace(obj.GetNamespace()) + } else { + // for cluster-wide resources + dr = dyn.Resource(mapping.Resource) + } + + _, err = dr.Get(ctx, obj.GetName(), metav1.GetOptions{}) + if err == nil { + // already exists + continue + } + + if !apierrors.IsNotFound(err) { + return fmt.Errorf("error checking resource existence: %w", err) + } + + _, err = dr.Create(ctx, obj, metav1.CreateOptions{ + FieldManager: "talos", + }) + if err != nil { + if apierrors.IsAlreadyExists(err) { + // later on we might want to do something here, e.g. do server-side apply, for now do nothing + } else { + return fmt.Errorf("error creating %s: %w", objName, err) + } + } else { + logger.Printf("created %s", objName) + } + } + + return nil +} + +func isNamespace(gvk schema.GroupVersionKind) bool { + return gvk.Kind == "Namespace" && gvk.Version == "v1" +} + +func isCRD(gvk schema.GroupVersionKind) bool { + return gvk.Kind == "CustomResourceDefinition" && gvk.Group == "apiextensions.k8s.io" +} diff --git a/internal/app/machined/pkg/controllers/k8s/render_secrets_static_pod.go b/internal/app/machined/pkg/controllers/k8s/render_secrets_static_pod.go new file mode 100644 index 000000000..25f26c590 --- /dev/null +++ b/internal/app/machined/pkg/controllers/k8s/render_secrets_static_pod.go @@ -0,0 +1,250 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "bytes" + "context" + "fmt" + "io/ioutil" + "log" + "os" + "path/filepath" + stdlibtemplate "text/template" + + "github.com/talos-systems/crypto/x509" + "github.com/talos-systems/os-runtime/pkg/controller" + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/state" + + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/k8s" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/secrets" + "github.com/talos-systems/talos/pkg/machinery/constants" +) + +// RenderSecretsStaticPodController manages k8s.SecretsReady and renders secrets from secrets.Kubernetes. +type RenderSecretsStaticPodController struct{} + +// Name implements controller.Controller interface. +func (ctrl *RenderSecretsStaticPodController) Name() string { + return "k8s.RenderSecretsStaticPodController" +} + +// ManagedResources implements controller.Controller interface. +func (ctrl *RenderSecretsStaticPodController) ManagedResources() (resource.Namespace, resource.Type) { + return k8s.ControlPlaneNamespaceName, k8s.SecretsStatusType +} + +// Run implements controller.Controller interface. +// +//nolint: gocyclo +func (ctrl *RenderSecretsStaticPodController) Run(ctx context.Context, r controller.Runtime, logger *log.Logger) error { + if err := r.UpdateDependencies([]controller.Dependency{ + { + Namespace: secrets.NamespaceName, + Type: secrets.KubernetesType, + Kind: controller.DependencyWeak, + }, + }); err != nil { + return fmt.Errorf("error setting up dependencies: %w", err) + } + + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + secretsRes, err := r.Get(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesType, secrets.KubernetesID, resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return fmt.Errorf("error getting secrets resource: %w", err) + } + + secrets := secretsRes.(*secrets.Kubernetes).Secrets() + + serviceAccountKey, err := secrets.ServiceAccount.GetRSAKey() + if err != nil { + return fmt.Errorf("error parsing service account key: %w", err) + } + + type secret struct { + getter func() *x509.PEMEncodedCertificateAndKey + certFilename string + keyFilename string + } + + type template struct { + filename string + template []byte + } + + for _, pod := range []struct { + name string + directory string + secrets []secret + templates []template + }{ + { + name: "kube-apiserver", + directory: constants.KubernetesAPIServerSecretsDir, + secrets: []secret{ + { + getter: func() *x509.PEMEncodedCertificateAndKey { return secrets.EtcdCA }, + certFilename: "etcd-client-ca.crt", + }, + { + getter: func() *x509.PEMEncodedCertificateAndKey { return secrets.EtcdPeer }, + certFilename: "etcd-client.crt", + keyFilename: "etcd-client.key", + }, + { + getter: func() *x509.PEMEncodedCertificateAndKey { return secrets.CA }, + certFilename: "ca.crt", + }, + { + getter: func() *x509.PEMEncodedCertificateAndKey { return secrets.APIServer }, + certFilename: "apiserver.crt", + keyFilename: "apiserver.key", + }, + { + getter: func() *x509.PEMEncodedCertificateAndKey { return secrets.APIServerKubeletClient }, + certFilename: "apiserver-kubelet-client.crt", + keyFilename: "apiserver-kubelet-client.key", + }, + { + getter: func() *x509.PEMEncodedCertificateAndKey { + return &x509.PEMEncodedCertificateAndKey{ + Crt: serviceAccountKey.PublicKeyPEM, + Key: serviceAccountKey.KeyPEM, + } + }, + certFilename: "service-account.pub", + keyFilename: "service-account.key", + }, + { + getter: func() *x509.PEMEncodedCertificateAndKey { return secrets.AggregatorCA }, + certFilename: "aggregator-ca.crt", + }, + { + getter: func() *x509.PEMEncodedCertificateAndKey { return secrets.FrontProxy }, + certFilename: "front-proxy-client.crt", + keyFilename: "front-proxy-client.key", + }, + }, + templates: []template{ + { + filename: "encryptionconfig.yaml", + template: kubeSystemEncryptionConfigTemplate, + }, + { + filename: "auditpolicy.yaml", + template: kubeSystemAuditPolicyTemplate, + }, + }, + }, + { + name: "kube-controller-manager", + directory: constants.KubernetesControllerManagerSecretsDir, + secrets: []secret{ + { + getter: func() *x509.PEMEncodedCertificateAndKey { return secrets.CA }, + certFilename: "ca.crt", + keyFilename: "ca.key", + }, + { + getter: func() *x509.PEMEncodedCertificateAndKey { + return &x509.PEMEncodedCertificateAndKey{ + Crt: serviceAccountKey.PublicKeyPEM, + Key: serviceAccountKey.KeyPEM, + } + }, + keyFilename: "service-account.key", + }, + }, + templates: []template{ + { + filename: "kubeconfig", + template: []byte("{{ .AdminKubeconfig }}"), + }, + }, + }, + { + name: "kube-scheduler", + directory: constants.KubernetesSchedulerSecretsDir, + templates: []template{ + { + filename: "kubeconfig", + template: []byte("{{ .AdminKubeconfig }}"), + }, + }, + }, + } { + if err = os.MkdirAll(pod.directory, 0o755); err != nil { + return fmt.Errorf("error creating secrets directory for %q: %w", pod.name, err) + } + + for _, secret := range pod.secrets { + certAndKey := secret.getter() + + if secret.certFilename != "" { + if err = ioutil.WriteFile(filepath.Join(pod.directory, secret.certFilename), certAndKey.Crt, 0o400); err != nil { + return fmt.Errorf("error writing certificate %q for %q: %w", secret.certFilename, pod.name, err) + } + + if err = os.Chown(filepath.Join(pod.directory, secret.certFilename), constants.KubernetesRunUser, -1); err != nil { + return fmt.Errorf("error chowning %q for %q: %w", secret.certFilename, pod.name, err) + } + } + + if secret.keyFilename != "" { + if err = ioutil.WriteFile(filepath.Join(pod.directory, secret.keyFilename), certAndKey.Key, 0o400); err != nil { + return fmt.Errorf("error writing key %q for %q: %w", secret.keyFilename, pod.name, err) + } + + if err = os.Chown(filepath.Join(pod.directory, secret.keyFilename), constants.KubernetesRunUser, -1); err != nil { + return fmt.Errorf("error chowning %q for %q: %w", secret.keyFilename, pod.name, err) + } + } + } + + for _, templ := range pod.templates { + var t *stdlibtemplate.Template + + t, err = stdlibtemplate.New(templ.filename).Parse(string(templ.template)) + if err != nil { + return fmt.Errorf("error parsing template %q: %w", templ.filename, err) + } + + var buf bytes.Buffer + + if err = t.Execute(&buf, secrets); err != nil { + return fmt.Errorf("error executing template %q: %w", templ.filename, err) + } + + if err = ioutil.WriteFile(filepath.Join(pod.directory, templ.filename), buf.Bytes(), 0o400); err != nil { + return fmt.Errorf("error writing template %q for %q: %w", templ.filename, pod.name, err) + } + + if err = os.Chown(filepath.Join(pod.directory, templ.filename), constants.KubernetesRunUser, -1); err != nil { + return fmt.Errorf("error chowning %q for %q: %w", templ.filename, pod.name, err) + } + } + } + + if err = r.Update(ctx, k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, k8s.StaticPodSecretsStaticPodID), func(r resource.Resource) error { + r.(*k8s.SecretsStatus).Status().Ready = true + r.(*k8s.SecretsStatus).Status().Version = secretsRes.Metadata().Version().String() + + return nil + }); err != nil { + return err + } + } +} diff --git a/internal/app/machined/pkg/controllers/k8s/templates.go b/internal/app/machined/pkg/controllers/k8s/templates.go new file mode 100644 index 000000000..fdde37dbe --- /dev/null +++ b/internal/app/machined/pkg/controllers/k8s/templates.go @@ -0,0 +1,701 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +// kube-apiserver configuration: + +var kubeSystemEncryptionConfigTemplate = []byte(`apiVersion: v1 +kind: EncryptionConfig +resources: +- resources: + - secrets + providers: + - aescbc: + keys: + - name: key1 + secret: {{ .AESCBCEncryptionSecret }} + - identity: {} +`) + +var kubeSystemAuditPolicyTemplate = []byte(`apiVersion: audit.k8s.io/v1beta1 +kind: Policy +rules: +- level: Metadata +`) + +// manifests injected into kube-apiserver + +var kubeletBootstrappingToken = []byte(`apiVersion: v1 +kind: Secret +metadata: + name: bootstrap-token-{{ .Secrets.BootstrapTokenID }} + namespace: kube-system +type: bootstrap.kubernetes.io/token +stringData: + token-id: "{{ .Secrets.BootstrapTokenID }}" + token-secret: "{{ .Secrets.BootstrapTokenSecret }}" + usage-bootstrap-authentication: "true" +`) + +// csrNodeBootstrapTemplate lets bootstrapping tokens and nodes request CSRs. +var csrNodeBootstrapTemplate = []byte(`kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: system-bootstrap-node-bootstrapper +subjects: +- kind: Group + name: system:bootstrappers + apiGroup: rbac.authorization.k8s.io +- kind: Group + name: system:nodes + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: ClusterRole + name: system:node-bootstrapper + apiGroup: rbac.authorization.k8s.io +`) + +// csrApproverRoleBindingTemplate instructs the csrapprover controller to +// automatically approve CSRs made by bootstrapping tokens for client +// credentials. +// +// This binding should be removed to disable CSR auto-approval. +var csrApproverRoleBindingTemplate = []byte(`kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: system-bootstrap-approve-node-client-csr +subjects: +- kind: Group + name: system:bootstrappers + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: ClusterRole + name: system:certificates.k8s.io:certificatesigningrequests:nodeclient + apiGroup: rbac.authorization.k8s.io +`) + +// csrRenewalRoleBindingTemplate instructs the csrapprover controller to +// automatically approve all CSRs made by nodes to renew their client +// certificates. +// +// This binding should be altered in the future to hold a list of node +// names instead of targeting `system:nodes` so we can revoke invidivual +// node's ability to renew its certs. +var csrRenewalRoleBindingTemplate = []byte(`kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: system-bootstrap-node-renewal +subjects: +- kind: Group + name: system:nodes + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: ClusterRole + name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient + apiGroup: rbac.authorization.k8s.io +`) + +var kubeSystemSARoleBindingTemplate = []byte(`apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: system:default-sa +subjects: + - kind: ServiceAccount + name: default + namespace: kube-system +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: rbac.authorization.k8s.io +`) + +var kubeProxyTemplate = []byte(`apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: kube-proxy + namespace: kube-system + labels: + tier: node + k8s-app: kube-proxy +spec: + selector: + matchLabels: + tier: node + k8s-app: kube-proxy + template: + metadata: + labels: + tier: node + k8s-app: kube-proxy + spec: + containers: + - name: kube-proxy + image: {{ .ProxyImage }} + command: + - /usr/local/bin/kube-proxy + - --cluster-cidr={{ .PodCIDRs }} + - --hostname-override=$(NODE_NAME) + - --kubeconfig=/etc/kubernetes/kubeconfig + - --proxy-mode={{ .ProxyMode }} + - --conntrack-max-per-core=0 + {{- range $k, $v := .ProxyExtraArgs }} + - --{{ $k }}={{ $v }} + {{- end }} + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + securityContext: + privileged: true + volumeMounts: + - mountPath: /lib/modules + name: lib-modules + readOnly: true + - mountPath: /etc/ssl/certs + name: ssl-certs-host + readOnly: true + - name: kubeconfig + mountPath: /etc/kubernetes + readOnly: true + hostNetwork: true + serviceAccountName: kube-proxy + tolerations: + - effect: NoSchedule + operator: Exists + - effect: NoExecute + operator: Exists + volumes: + - name: lib-modules + hostPath: + path: /lib/modules + - name: ssl-certs-host + hostPath: + path: /etc/ssl/certs + - name: kubeconfig + configMap: + name: kubeconfig-in-cluster + updateStrategy: + rollingUpdate: + maxUnavailable: 1 + type: RollingUpdate +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: kube-system + name: kube-proxy +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: kube-proxy +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:node-proxier # Automatically created system role. +subjects: +- kind: ServiceAccount + name: kube-proxy + namespace: kube-system +`) + +// kubeConfigInCluster instructs clients to use their service account token, +// but unlike an in-cluster client doesn't rely on the `KUBERNETES_SERVICE_PORT` +// and `KUBERNETES_PORT` to determine the API servers address. +// +// This kubeconfig is used by bootstrapping pods that might not have access to +// these env vars, such as kube-proxy, which sets up the API server endpoint +// (chicken and egg), and the checkpointer, which needs to run as a static pod +// even if the API server isn't available. +var kubeConfigInClusterTemplate = []byte(`apiVersion: v1 +kind: ConfigMap +metadata: + name: kubeconfig-in-cluster + namespace: kube-system +data: + kubeconfig: | + apiVersion: v1 + clusters: + - name: local + cluster: + server: {{ .Server }} + certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + users: + - name: service-account + user: + # Use service account token + tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + contexts: + - context: + cluster: local + user: service-account +`) + +var coreDNSTemplate = []byte(`apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: system:coredns + labels: + kubernetes.io/bootstrapping: rbac-defaults + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:coredns +subjects: + - kind: ServiceAccount + name: coredns + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: system:coredns + labels: + kubernetes.io/bootstrapping: rbac-defaults +rules: + - apiGroups: [""] + resources: + - endpoints + - services + - pods + - namespaces + verbs: + - list + - watch + - apiGroups: [""] + resources: + - nodes + verbs: + - get +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: coredns + namespace: kube-system +data: + Corefile: | + .:53 { + errors + health { + lameduck 5s + } + ready + log . { + class error + } + kubernetes {{ .ClusterDomain }} in-addr.arpa ip6.arpa { + pods insecure + fallthrough in-addr.arpa ip6.arpa + } + prometheus :9153 + forward . /etc/resolv.conf + cache 30 + loop + reload + loadbalance + } +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: coredns + namespace: kube-system + labels: + k8s-app: kube-dns + kubernetes.io/name: "CoreDNS" + kubernetes.io/cluster-service: "true" +spec: + replicas: 2 + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + selector: + matchLabels: + k8s-app: kube-dns + template: + metadata: + labels: + k8s-app: kube-dns + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: k8s-app + operator: In + values: + - kube-dns + topologyKey: kubernetes.io/hostname + serviceAccountName: coredns + priorityClassName: system-cluster-critical + tolerations: + - key: node-role.kubernetes.io/master + operator: Exists + effect: NoSchedule + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: NoSchedule + containers: + - name: coredns + image: {{ .CoreDNSImage }} + imagePullPolicy: IfNotPresent + resources: + limits: + memory: 170Mi + requests: + cpu: 100m + memory: 70Mi + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns + readOnly: true + ports: + - name: dns + protocol: UDP + containerPort: 53 + - name: dns-tcp + protocol: TCP + containerPort: 53 + - name: metrics + protocol: TCP + containerPort: 9153 + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + readinessProbe: + httpGet: + path: /ready + port: 8181 + scheme: HTTP + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - NET_BIND_SERVICE + drop: + - all + readOnlyRootFilesystem: true + dnsPolicy: Default + volumes: + - name: config-volume + configMap: + name: coredns + items: + - key: Corefile + path: Corefile +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: coredns + namespace: kube-system + labels: + kubernetes.io/cluster-service: "true" +`) + +var coreDNSSvcTemplate = []byte(`apiVersion: v1 +kind: Service +metadata: + name: kube-dns + namespace: kube-system + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9153" + labels: + k8s-app: kube-dns + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" +spec: + selector: + k8s-app: kube-dns + clusterIP: {{ .DNSServiceIP }} + ports: + - name: dns + port: 53 + protocol: UDP + - name: dns-tcp + port: 53 + protocol: TCP +`) + +var coreDNSv6SvcTemplate = []byte(`apiVersion: v1 +kind: Service +metadata: + name: kube-dnsv6 + namespace: kube-system + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9153" + labels: + k8s-app: kube-dns + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" +spec: + selector: + k8s-app: kube-dns + clusterIP: {{ .DNSServiceIPv6 }} + ipFamily: IPv6 + ports: + - name: dns + port: 53 + protocol: UDP + - name: dns-tcp + port: 53 + protocol: TCP +`) + +var flannelTemplate = []byte(`apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: flannel +rules: + - apiGroups: ['extensions'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: ['psp.flannel.unprivileged'] + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - apiGroups: + - "" + resources: + - nodes + verbs: + - list + - watch + - apiGroups: + - "" + resources: + - nodes/status + verbs: + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: flannel +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: flannel +subjects: +- kind: ServiceAccount + name: flannel + namespace: kube-system +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: flannel + namespace: kube-system +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: kube-flannel-cfg + namespace: kube-system + labels: + tier: node + k8s-app: flannel +data: + cni-conf.json: | + { + "name": "cbr0", + "cniVersion": "0.3.1", + "plugins": [ + { + "type": "flannel", + "delegate": { + "hairpinMode": true, + "isDefaultGateway": true + } + }, + { + "type": "portmap", + "capabilities": { + "portMappings": true + } + } + ] + } + net-conf.json: | + { + "Network": "{{ .FirstPodCIDR }}", + "Backend": { + "Type": "vxlan", + "Port": 4789 + } + } +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: kube-flannel + namespace: kube-system + labels: + tier: node + k8s-app: flannel +spec: + selector: + matchLabels: + tier: node + k8s-app: flannel + template: + metadata: + labels: + tier: node + k8s-app: flannel + spec: + serviceAccountName: flannel + initContainers: + - name: install-config + image: {{ .FlannelImage }} + command: + - cp + args: + - -f + - /etc/kube-flannel/cni-conf.json + - /etc/cni/net.d/10-flannel.conflist + volumeMounts: + - name: cni + mountPath: /etc/cni/net.d + - name: flannel-cfg + mountPath: /etc/kube-flannel/ + - name: install-cni + image: {{ .FlannelCNIImage }} + command: ["/install-cni.sh"] + volumeMounts: + - name: host-cni-bin + mountPath: /host/opt/cni/bin/ + containers: + - name: kube-flannel + image: {{ .FlannelImage }} + command: + - /opt/bin/flanneld + args: + - --ip-masq + - --kube-subnet-mgr + securityContext: + privileged: true + capabilities: + add: ["NET_ADMIN", "NET_RAW"] + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + volumeMounts: + - name: run + mountPath: /run/flannel + - name: flannel-cfg + mountPath: /etc/kube-flannel/ + hostNetwork: true + tolerations: + - effect: NoSchedule + operator: Exists + - effect: NoExecute + operator: Exists + volumes: + - name: run + hostPath: + path: /run/flannel + - name: cni + hostPath: + path: /etc/cni/net.d + - name: flannel-cfg + configMap: + name: kube-flannel-cfg + - name: host-cni-bin + hostPath: + path: /opt/cni/bin + updateStrategy: + rollingUpdate: + maxUnavailable: 1 + type: RollingUpdate +`) + +// podSecurityPolicy is the default PSP. +var podSecurityPolicy = []byte(`kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: psp:privileged +rules: +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - privileged +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: psp:privileged +roleRef: + kind: ClusterRole + name: psp:privileged + apiGroup: rbac.authorization.k8s.io +subjects: +# Authorize all service accounts in a namespace: +- kind: Group + apiGroup: rbac.authorization.k8s.io + name: system:serviceaccounts +# Authorize all authenticated users in a namespace: +- kind: Group + apiGroup: rbac.authorization.k8s.io + name: system:authenticated +--- +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: privileged + annotations: + seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*' +spec: + fsGroup: + rule: RunAsAny + privileged: true + runAsUser: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + volumes: + - '*' + allowedCapabilities: + - '*' + hostPID: true + hostIPC: true + hostNetwork: true + hostPorts: + - min: 1 + max: 65536 +`) diff --git a/internal/app/machined/pkg/controllers/secrets/kubernetes.go b/internal/app/machined/pkg/controllers/secrets/kubernetes.go new file mode 100644 index 000000000..8f37000dc --- /dev/null +++ b/internal/app/machined/pkg/controllers/secrets/kubernetes.go @@ -0,0 +1,286 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package secrets + +import ( + "bytes" + "context" + "fmt" + "log" + "net" + "time" + + "github.com/AlekSi/pointer" + "github.com/talos-systems/crypto/x509" + "github.com/talos-systems/os-runtime/pkg/controller" + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/state" + + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/config" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/secrets" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/v1alpha1" + "github.com/talos-systems/talos/internal/pkg/etcd" + "github.com/talos-systems/talos/internal/pkg/kubeconfig" + talosconfig "github.com/talos-systems/talos/pkg/machinery/config" + "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" + "github.com/talos-systems/talos/pkg/machinery/constants" +) + +// KubernetesController manages secrets.Kubernetes based on configuration. +type KubernetesController struct { +} + +// Name implements controller.Controller interface. +func (ctrl *KubernetesController) Name() string { + return "secrets.KubernetesController" +} + +// ManagedResources implements controller.Controller interface. +func (ctrl *KubernetesController) ManagedResources() (resource.Namespace, resource.Type) { + return secrets.NamespaceName, secrets.KubernetesType +} + +// Run implements controller.Controller interface. +// +//nolint: gocyclo +func (ctrl *KubernetesController) Run(ctx context.Context, r controller.Runtime, logger *log.Logger) error { + if err := r.UpdateDependencies([]controller.Dependency{ + { // TODO: should render config for kubernetes secrets controller + Namespace: config.NamespaceName, + Type: config.V1Alpha1Type, + ID: pointer.ToString(config.V1Alpha1ID), + Kind: controller.DependencyWeak, + }, + { + Namespace: v1alpha1.NamespaceName, + Type: v1alpha1.ServiceType, + ID: pointer.ToString("networkd"), + Kind: controller.DependencyWeak, + }, + { + Namespace: config.NamespaceName, + Type: config.MachineTypeType, + ID: pointer.ToString(config.MachineTypeID), + Kind: controller.DependencyWeak, + }, + }); err != nil { + return fmt.Errorf("error setting up dependencies: %w", err) + } + + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + cfg, err := r.Get(ctx, resource.NewMetadata(config.NamespaceName, config.V1Alpha1Type, config.V1Alpha1ID, resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + if err = ctrl.teardownAll(ctx, r); err != nil { + return fmt.Errorf("error destroying static pods: %w", err) + } + + continue + } + + return fmt.Errorf("error getting config: %w", err) + } + + cfgProvider := cfg.(*config.V1Alpha1).Config() + + machineTypeRes, err := r.Get(ctx, resource.NewMetadata(config.NamespaceName, config.MachineTypeType, config.MachineTypeID, resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return fmt.Errorf("error getting machine type: %w", err) + } + + machineType := machineTypeRes.(*config.MachineType).MachineType() + + if machineType != machine.TypeControlPlane && machineType != machine.TypeInit { + if err = ctrl.teardownAll(ctx, r); err != nil { + return fmt.Errorf("error destroying static pods: %w", err) + } + + continue + } + + // wait for networkd to be healthy as it might change IPs/hostname + networkdResource, err := r.Get(ctx, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, "networkd", resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return err + } + + if !networkdResource.(*v1alpha1.Service).Healthy() { + continue + } + + if err = r.Update(ctx, secrets.NewKubernetes(), func(r resource.Resource) error { + k8sSecrets := r.(*secrets.Kubernetes) //nolint: errcheck + + return ctrl.updateSecrets(cfgProvider, k8sSecrets) + }); err != nil { + return err + } + } +} + +//nolint: gocyclo +func (ctrl *KubernetesController) updateSecrets(cfgProvider talosconfig.Provider, k8sSecrets *secrets.Kubernetes) error { + k8sSecrets.Secrets().EtcdCA = cfgProvider.Cluster().Etcd().CA() + + if k8sSecrets.Secrets().EtcdCA == nil { + return fmt.Errorf("missing cluster.etcdCA secret") + } + + k8sSecrets.Secrets().AggregatorCA = cfgProvider.Cluster().AggregatorCA() + + if k8sSecrets.Secrets().AggregatorCA == nil { + return fmt.Errorf("missing cluster.aggregatorCA secret") + } + + k8sSecrets.Secrets().CA = cfgProvider.Cluster().CA() + + if k8sSecrets.Secrets().CA == nil { + return fmt.Errorf("missing cluster.CA secret") + } + + var err error + + k8sSecrets.Secrets().EtcdPeer, err = etcd.GeneratePeerCert(cfgProvider.Cluster().Etcd().CA()) + if err != nil { + return err + } + + urls := []string{cfgProvider.Cluster().Endpoint().Hostname()} + urls = append(urls, cfgProvider.Cluster().CertSANs()...) + altNames := altNamesFromURLs(urls) + + apiServiceIPs, err := cfgProvider.Cluster().Network().APIServerIPs() + if err != nil { + return fmt.Errorf("failed to calculate API service IP: %w", err) + } + + altNames.IPs = append(altNames.IPs, apiServiceIPs...) + + // Add kubernetes default svc with cluster domain to AltNames + altNames.DNSNames = append(altNames.DNSNames, + "kubernetes", + "kubernetes.default", + "kubernetes.default.svc", + "kubernetes.default.svc."+cfgProvider.Cluster().Network().DNSDomain(), + ) + + ca, err := x509.NewCertificateAuthorityFromCertificateAndKey(k8sSecrets.Secrets().CA, x509.RSA(true)) + if err != nil { + return fmt.Errorf("failed to parse CA certificate: %w", err) + } + + apiServer, err := x509.NewKeyPair(ca, + x509.RSA(true), + x509.IPAddresses(altNames.IPs), + x509.DNSNames(altNames.DNSNames), + x509.CommonName("kube-apiserver"), + x509.Organization("kube-master"), + x509.NotAfter(time.Now().Add(constants.KubernetesDefaultCertificateValidityDuration)), + ) + if err != nil { + return fmt.Errorf("failed to generate api-server cert: %w", err) + } + + k8sSecrets.Secrets().APIServer = x509.NewCertificateAndKeyFromKeyPair(apiServer) + + apiServerKubeletClient, err := x509.NewKeyPair(ca, + x509.RSA(true), + x509.CommonName(constants.KubernetesAdminCertCommonName), + x509.Organization(constants.KubernetesAdminCertOrganization), + x509.NotAfter(time.Now().Add(constants.KubernetesDefaultCertificateValidityDuration)), + ) + if err != nil { + return fmt.Errorf("failed to generate api-server cert: %w", err) + } + + k8sSecrets.Secrets().APIServerKubeletClient = x509.NewCertificateAndKeyFromKeyPair(apiServerKubeletClient) + + k8sSecrets.Secrets().ServiceAccount = cfgProvider.Cluster().ServiceAccount() + + aggregatorCA, err := x509.NewCertificateAuthorityFromCertificateAndKey(k8sSecrets.Secrets().AggregatorCA, x509.RSA(true)) + if err != nil { + return fmt.Errorf("failed to parse aggregator CA: %w", err) + } + + frontProxy, err := x509.NewKeyPair(aggregatorCA, + x509.RSA(true), + x509.CommonName("front-proxy-client"), + x509.NotAfter(time.Now().Add(constants.KubernetesDefaultCertificateValidityDuration)), + ) + if err != nil { + return fmt.Errorf("failed to generate aggregator cert: %w", err) + } + + k8sSecrets.Secrets().FrontProxy = x509.NewCertificateAndKeyFromKeyPair(frontProxy) + + k8sSecrets.Secrets().AESCBCEncryptionSecret = cfgProvider.Cluster().AESCBCEncryptionSecret() + + var buf bytes.Buffer + + if err = kubeconfig.GenerateAdmin(cfgProvider.Cluster(), &buf); err != nil { + return fmt.Errorf("failed to generate admin kubeconfig: %w", err) + } + + k8sSecrets.Secrets().AdminKubeconfig = buf.String() + + k8sSecrets.Secrets().BootstrapTokenID = cfgProvider.Cluster().Token().ID() + k8sSecrets.Secrets().BootstrapTokenSecret = cfgProvider.Cluster().Token().Secret() + + return nil +} + +func (ctrl *KubernetesController) teardownAll(ctx context.Context, r controller.Runtime) error { + list, err := r.List(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesType, "", resource.VersionUndefined)) + if err != nil { + return err + } + + // TODO: change this to proper teardown sequence + + for _, res := range list.Items { + if err = r.Destroy(ctx, res.Metadata()); err != nil { + return err + } + } + + return nil +} + +// AltNames defines certificate alternative names. +type AltNames struct { + IPs []net.IP + DNSNames []string +} + +func altNamesFromURLs(urls []string) *AltNames { + var an AltNames + + for _, u := range urls { + ip := net.ParseIP(u) + if ip != nil { + an.IPs = append(an.IPs, ip) + + continue + } + + an.DNSNames = append(an.DNSNames, u) + } + + return &an +} diff --git a/internal/app/machined/pkg/controllers/secrets/secrets.go b/internal/app/machined/pkg/controllers/secrets/secrets.go new file mode 100644 index 000000000..3149da152 --- /dev/null +++ b/internal/app/machined/pkg/controllers/secrets/secrets.go @@ -0,0 +1,6 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package secrets provides controllers which manage secret resources. +package secrets diff --git a/internal/app/machined/pkg/controllers/v1alpha1/boostrap_status.go b/internal/app/machined/pkg/controllers/v1alpha1/boostrap_status.go new file mode 100644 index 000000000..e15a6f1fb --- /dev/null +++ b/internal/app/machined/pkg/controllers/v1alpha1/boostrap_status.go @@ -0,0 +1,128 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package v1alpha1 + +import ( + "context" + "fmt" + "log" + + "github.com/AlekSi/pointer" + "github.com/talos-systems/os-runtime/pkg/controller" + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/state" + "go.etcd.io/etcd/clientv3" + + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/v1alpha1" + "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" + "github.com/talos-systems/talos/internal/pkg/etcd" + "github.com/talos-systems/talos/pkg/machinery/constants" +) + +// BootstrapStatusController manages v1alpha1.Service based on services subsystem state. +type BootstrapStatusController struct { + V1Alpha1Events runtime.Watcher +} + +// Name implements controller.Controller interface. +func (ctrl *BootstrapStatusController) Name() string { + return "v1alpha1.BootstrapStatusController" +} + +// ManagedResources implements controller.Controller interface. +func (ctrl *BootstrapStatusController) ManagedResources() (resource.Namespace, resource.Type) { + return v1alpha1.NamespaceName, v1alpha1.BootstrapStatusType +} + +// Run implements controller.Controller interface. +// +//nolint: gocyclo +func (ctrl *BootstrapStatusController) Run(ctx context.Context, r controller.Runtime, logger *log.Logger) error { + if err := r.UpdateDependencies([]controller.Dependency{ + { + Namespace: v1alpha1.NamespaceName, + Type: v1alpha1.ServiceType, + ID: pointer.ToString("etcd"), + Kind: controller.DependencyWeak, + }, + }); err != nil { + return fmt.Errorf("error setting up dependencies: %w", err) + } + + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + // wait for etcd to be healthy as controller reads the key + etcdResource, err := r.Get(ctx, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, "etcd", resource.VersionUndefined)) + if err != nil { + if state.IsNotFoundError(err) { + continue + } + + return err + } + + if !etcdResource.(*v1alpha1.Service).Healthy() { + continue + } + + if err = ctrl.readInitialized(ctx, r, logger); err != nil { + return err + } + } +} + +func (ctrl *BootstrapStatusController) readInitialized(ctx context.Context, r controller.Runtime, logger *log.Logger) error { + etcdClient, err := etcd.NewLocalClient() + if err != nil { + return fmt.Errorf("error creating etcd client: %w", err) + } + + defer etcdClient.Close() //nolint: errcheck + + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + ctx = clientv3.WithRequireLeader(ctx) + + // InitializedKey was created by Talos < 0.9 after successful bootstrap run (bootkube) + // this key can only be removed by Talos 0.9, so if key is not found, controller returns + + watchCh := etcdClient.Watch(ctx, constants.InitializedKey) + + resp, err := etcdClient.Get(ctx, constants.InitializedKey) + if err != nil { + return fmt.Errorf("error getting key: %w", err) + } + + if resp.Count == 0 || string(resp.Kvs[0].Value) != "true" { + logger.Printf("bootkube initialized status not found") + + return r.Update(ctx, v1alpha1.NewBootstrapStatus(), func(r resource.Resource) error { + r.(*v1alpha1.BootstrapStatus).Status().SelfHostedControlPlane = false + + return nil + }) + } + + logger.Printf("found bootkube initialized status in etcd") + + if err = r.Update(ctx, v1alpha1.NewBootstrapStatus(), func(r resource.Resource) error { + r.(*v1alpha1.BootstrapStatus).Status().SelfHostedControlPlane = true + + return nil + }); err != nil { + return err + } + + // wait for key change or any other event in etcd + <-watchCh + + return nil +} diff --git a/internal/app/machined/pkg/controllers/v1alpha1/service.go b/internal/app/machined/pkg/controllers/v1alpha1/service.go index e52f12216..36cd9e158 100644 --- a/internal/app/machined/pkg/controllers/v1alpha1/service.go +++ b/internal/app/machined/pkg/controllers/v1alpha1/service.go @@ -65,7 +65,10 @@ func (ctrl *ServiceController) Run(ctx context.Context, r controller.Runtime, lo switch msg.Action { //nolint: exhaustive case machine.ServiceStateEvent_RUNNING: if err := r.Update(ctx, service, func(r resource.Resource) error { - r.(*v1alpha1.Service).SetRunning(true) + svc := r.(*v1alpha1.Service) //nolint: errcheck + + svc.SetRunning(true) + svc.SetHealthy(msg.GetHealth().GetHealthy() && !msg.GetHealth().GetUnknown()) return nil }); err != nil { diff --git a/internal/app/machined/pkg/resources/config/k8s_control_plane.go b/internal/app/machined/pkg/resources/config/k8s_control_plane.go new file mode 100644 index 000000000..16a4e4192 --- /dev/null +++ b/internal/app/machined/pkg/resources/config/k8s_control_plane.go @@ -0,0 +1,238 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package config + +import ( + "fmt" + + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/resource/core" +) + +// K8sControlPlaneType is type of K8sControlPlane resource. +const K8sControlPlaneType = resource.Type("config/k8sControlPlane") + +// K8sControlPlaneAPIServerID is an ID of kube-apiserver config. +const K8sControlPlaneAPIServerID = resource.ID("kube-apiserver") + +// K8sControlPlaneControllerManagerID is an ID of kube-controller-manager config. +const K8sControlPlaneControllerManagerID = resource.ID("kube-controller-manager") + +// K8sControlPlaneSchedulerID is an ID of kube-scheduler config. +const K8sControlPlaneSchedulerID = resource.ID("kube-scheduler") + +// K8sManifestsID is an ID of manifests config. +const K8sManifestsID = resource.ID("manifests") + +// K8sExtraManifestsID is an ID of extra manifests config. +const K8sExtraManifestsID = resource.ID("extra-manifests") + +// K8sControlPlane describes machine type. +type K8sControlPlane struct { + md resource.Metadata + // spec stores values of different types depending on ID + spec interface{} +} + +// K8sControlPlaneAPIServerSpec is configuration for kube-apiserver. +type K8sControlPlaneAPIServerSpec struct { + Image string `yaml:"image"` + CloudProvider string `yaml:"cloudProvider"` + ControlPlaneEndpoint string `yaml:"controlPlaneEndpoint"` + EtcdServers []string `yaml:"etcdServers"` + LocalPort int `yaml:"localPort"` + ServiceCIDR string `yaml:"serviceCIDR"` + ExtraArgs map[string]string `yaml:"extraArgs"` +} + +// K8sControlPlaneControllerManagerSpec is configuration for kube-controller-manager. +type K8sControlPlaneControllerManagerSpec struct { + Image string `yaml:"image"` + CloudProvider string `yaml:"cloudProvider"` + PodCIDR string `yaml:"podCIDR"` + ServiceCIDR string `yaml:"serviceCIDR"` + ExtraArgs map[string]string `yaml:"extraArgs"` +} + +// K8sControlPlaneSchedulerSpec is configuration for kube-scheduler. +type K8sControlPlaneSchedulerSpec struct { + Image string `yaml:"image"` + ExtraArgs map[string]string `yaml:"extraArgs"` +} + +// K8sManifestsSpec is configuration for manifests. +type K8sManifestsSpec struct { + Server string `yaml:"string"` + ClusterDomain string `yaml:"clusterDomain"` + + PodCIDRs string `yaml:"podCIDRs"` + FirstPodCIDR string `yaml:"firstPodCIDR"` + + ProxyImage string `yaml:"proxyImage"` + ProxyMode string `yaml:"proxyMode"` + ProxyExtraArgs map[string]string `yaml:"proxyExtraArgs"` + + CoreDNSImage string `yaml:"coreDNSImage"` + + DNSServiceIP string `yaml:"dnsServiceIP"` + DNSServiceIPv6 string `yaml:"dnsServiceIPv6"` + + FlannelEnabled bool `yaml:"flannelEnabled"` + FlannelImage string `yaml:"flannelImage"` + FlannelCNIImage string `yaml:"flannelCNIImage"` +} + +// ExtraManifest defines a single extra manifest to download. +type ExtraManifest struct { + URL string `yaml:"url"` + Priority string `yaml:"priority"` + ExtraHeaders map[string]string `yaml:"extraHeaders"` +} + +// K8sExtraManifestsSpec is a configuration for extra manifests. +type K8sExtraManifestsSpec struct { + ExtraManifests []ExtraManifest `yaml:"extraManifests"` +} + +// NewK8sControlPlaneAPIServer initializes a K8sControlPlane resource. +func NewK8sControlPlaneAPIServer() *K8sControlPlane { + r := &K8sControlPlane{ + md: resource.NewMetadata(NamespaceName, K8sControlPlaneType, K8sControlPlaneAPIServerID, resource.VersionUndefined), + spec: K8sControlPlaneAPIServerSpec{}, + } + + r.md.BumpVersion() + + return r +} + +// NewK8sControlPlaneControllerManager initializes a K8sControlPlane resource. +func NewK8sControlPlaneControllerManager() *K8sControlPlane { + r := &K8sControlPlane{ + md: resource.NewMetadata(NamespaceName, K8sControlPlaneType, K8sControlPlaneControllerManagerID, resource.VersionUndefined), + spec: K8sControlPlaneControllerManagerSpec{}, + } + + r.md.BumpVersion() + + return r +} + +// NewK8sControlPlaneScheduler initializes a K8sControlPlane resource. +func NewK8sControlPlaneScheduler() *K8sControlPlane { + r := &K8sControlPlane{ + md: resource.NewMetadata(NamespaceName, K8sControlPlaneType, K8sControlPlaneSchedulerID, resource.VersionUndefined), + spec: K8sControlPlaneSchedulerSpec{}, + } + + r.md.BumpVersion() + + return r +} + +// NewK8sManifests initializes a K8sControlPlane resource. +func NewK8sManifests() *K8sControlPlane { + r := &K8sControlPlane{ + md: resource.NewMetadata(NamespaceName, K8sControlPlaneType, K8sManifestsID, resource.VersionUndefined), + spec: K8sManifestsSpec{}, + } + + r.md.BumpVersion() + + return r +} + +// NewK8sExtraManifests initializes a K8sControlPlane resource. +func NewK8sExtraManifests() *K8sControlPlane { + r := &K8sControlPlane{ + md: resource.NewMetadata(NamespaceName, K8sControlPlaneType, K8sExtraManifestsID, resource.VersionUndefined), + spec: K8sExtraManifestsSpec{}, + } + + r.md.BumpVersion() + + return r +} + +// Metadata implements resource.Resource. +func (r *K8sControlPlane) Metadata() *resource.Metadata { + return &r.md +} + +// Spec implements resource.Resource. +func (r *K8sControlPlane) Spec() interface{} { + return r.spec +} + +func (r *K8sControlPlane) String() string { + return fmt.Sprintf("config.K8sControlPlane(%q)", r.md.ID()) +} + +// DeepCopy implements resource.Resource. +func (r *K8sControlPlane) DeepCopy() resource.Resource { + return &K8sControlPlane{ + md: r.md, + spec: r.spec, + } +} + +// ResourceDefinition implements core.ResourceDefinitionProvider interface. +func (r *K8sControlPlane) ResourceDefinition() core.ResourceDefinitionSpec { + return core.ResourceDefinitionSpec{ + Type: K8sControlPlaneType, + Aliases: []resource.Type{"controlPlane"}, + DefaultNamespace: NamespaceName, + } +} + +// APIServer returns K8sControlPlaneApiServerSpec. +func (r *K8sControlPlane) APIServer() K8sControlPlaneAPIServerSpec { + return r.spec.(K8sControlPlaneAPIServerSpec) +} + +// SetAPIServer sets K8sControlPlaneApiServerSpec. +func (r *K8sControlPlane) SetAPIServer(spec K8sControlPlaneAPIServerSpec) { + r.spec = spec +} + +// ControllerManager returns K8sControlPlaneControllerManagerSpec. +func (r *K8sControlPlane) ControllerManager() K8sControlPlaneControllerManagerSpec { + return r.spec.(K8sControlPlaneControllerManagerSpec) +} + +// SetControllerManager sets K8sControlPlaneControllerManagerSpec. +func (r *K8sControlPlane) SetControllerManager(spec K8sControlPlaneControllerManagerSpec) { + r.spec = spec +} + +// Scheduler returns K8sControlPlaneSchedulerSpec. +func (r *K8sControlPlane) Scheduler() K8sControlPlaneSchedulerSpec { + return r.spec.(K8sControlPlaneSchedulerSpec) +} + +// SetScheduler sets K8sControlPlaneSchedulerSpec. +func (r *K8sControlPlane) SetScheduler(spec K8sControlPlaneSchedulerSpec) { + r.spec = spec +} + +// Manifests returns K8sManifestsSpec. +func (r *K8sControlPlane) Manifests() K8sManifestsSpec { + return r.spec.(K8sManifestsSpec) +} + +// SetManifests sets K8sManifestsSpec. +func (r *K8sControlPlane) SetManifests(spec K8sManifestsSpec) { + r.spec = spec +} + +// ExtraManifests returns K8sExtraManifestsSpec. +func (r *K8sControlPlane) ExtraManifests() K8sExtraManifestsSpec { + return r.spec.(K8sExtraManifestsSpec) +} + +// SetExtraManifests sets K8sManifestsSpec. +func (r *K8sControlPlane) SetExtraManifests(spec K8sExtraManifestsSpec) { + r.spec = spec +} diff --git a/internal/app/machined/pkg/resources/config/machine_type.go b/internal/app/machined/pkg/resources/config/machine_type.go new file mode 100644 index 000000000..82cccc1f9 --- /dev/null +++ b/internal/app/machined/pkg/resources/config/machine_type.go @@ -0,0 +1,87 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package config + +import ( + "fmt" + + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/resource/core" + + "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" +) + +// MachineTypeType is type of MachineType resource. +const MachineTypeType = resource.Type("config/machineType") + +// MachineTypeID is singleton resource ID. +const MachineTypeID = resource.ID("machine-type") + +// MachineType describes machine type. +type MachineType struct { + md resource.Metadata + spec machineTypeSpec +} + +type machineTypeSpec struct { + machine.Type +} + +func (spec machineTypeSpec) MarshalYAML() (interface{}, error) { + return spec.Type.String(), nil +} + +// NewMachineType initializes a MachineType resource. +func NewMachineType() *MachineType { + r := &MachineType{ + md: resource.NewMetadata(NamespaceName, MachineTypeType, MachineTypeID, resource.VersionUndefined), + spec: machineTypeSpec{}, + } + + r.md.BumpVersion() + + return r +} + +// Metadata implements resource.Resource. +func (r *MachineType) Metadata() *resource.Metadata { + return &r.md +} + +// Spec implements resource.Resource. +func (r *MachineType) Spec() interface{} { + return r.spec +} + +func (r *MachineType) String() string { + return fmt.Sprintf("config.MachineType(%q)", r.md.ID()) +} + +// DeepCopy implements resource.Resource. +func (r *MachineType) DeepCopy() resource.Resource { + return &MachineType{ + md: r.md, + spec: r.spec, + } +} + +// ResourceDefinition implements core.ResourceDefinitionProvider interface. +func (r *MachineType) ResourceDefinition() core.ResourceDefinitionSpec { + return core.ResourceDefinitionSpec{ + Type: MachineTypeType, + Aliases: []resource.Type{"machineType"}, + DefaultNamespace: NamespaceName, + } +} + +// MachineType returns machine.Type. +func (r *MachineType) MachineType() machine.Type { + return r.spec.Type +} + +// SetMachineType sets machine.Type. +func (r *MachineType) SetMachineType(typ machine.Type) { + r.spec.Type = typ +} diff --git a/internal/app/machined/pkg/resources/k8s/k8s.go b/internal/app/machined/pkg/resources/k8s/k8s.go new file mode 100644 index 000000000..44509f3e2 --- /dev/null +++ b/internal/app/machined/pkg/resources/k8s/k8s.go @@ -0,0 +1,14 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package k8s provides resources which interface with Kubernetes. +package k8s + +import "github.com/talos-systems/os-runtime/pkg/resource" + +// ControlPlaneNamespaceName contains resources supporting Kubernetes control plane. +const ControlPlaneNamespaceName resource.Namespace = "k8s/controlplane" + +// ExtraNamespaceName contains extra resources related to Kubernnetes configuration. +const ExtraNamespaceName resource.Namespace = "k8s/extra" diff --git a/internal/app/machined/pkg/resources/k8s/manifest.go b/internal/app/machined/pkg/resources/k8s/manifest.go new file mode 100644 index 000000000..a788e89bb --- /dev/null +++ b/internal/app/machined/pkg/resources/k8s/manifest.go @@ -0,0 +1,134 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "io" + + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/resource/core" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/util/yaml" +) + +// ManifestType is type of Manifest resource. +const ManifestType = resource.Type("k8s/manifest") + +// Manifest resource holds definition of kubelet static pod. +type Manifest struct { + md resource.Metadata + spec *manifestSpec +} + +type manifestSpec struct { + Items []*unstructured.Unstructured +} + +func (spec *manifestSpec) MarshalYAML() (interface{}, error) { + result := make([]map[string]interface{}, 0, len(spec.Items)) + + for _, obj := range spec.Items { + result = append(result, obj.Object) + } + + return result, nil +} + +// NewManifest initializes an empty Manifest resource. +func NewManifest(namespace resource.Namespace, id resource.ID) *Manifest { + r := &Manifest{ + md: resource.NewMetadata(namespace, ManifestType, id, resource.VersionUndefined), + spec: &manifestSpec{}, + } + + r.md.BumpVersion() + + return r +} + +// Metadata implements resource.Resource. +func (r *Manifest) Metadata() *resource.Metadata { + return &r.md +} + +// Spec implements resource.Resource. +func (r *Manifest) Spec() interface{} { + return r.spec +} + +func (r *Manifest) String() string { + return fmt.Sprintf("k8s.Manifest(%q)", r.md.ID()) +} + +// DeepCopy implements resource.Resource. +func (r *Manifest) DeepCopy() resource.Resource { + spec := &manifestSpec{ + Items: make([]*unstructured.Unstructured, len(r.spec.Items)), + } + + for i := range r.spec.Items { + spec.Items[i] = r.spec.Items[i].DeepCopy() + } + + return &Manifest{ + md: r.md, + spec: spec, + } +} + +// ResourceDefinition implements core.ResourceDefinitionProvider interface. +func (r *Manifest) ResourceDefinition() core.ResourceDefinitionSpec { + return core.ResourceDefinitionSpec{ + Type: ManifestType, + Aliases: []resource.Type{"manifest", "manifests"}, + DefaultNamespace: ControlPlaneNamespaceName, + } +} + +// SetYAML parses manifest from YAML. +func (r *Manifest) SetYAML(yamlBytes []byte) error { + reader := yaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(yamlBytes))) + + for { + yamlManifest, err := reader.Read() + if err != nil { + if err == io.EOF { + break + } + + return err + } + + yamlManifest = bytes.TrimSpace(yamlManifest) + + if len(yamlManifest) == 0 { + continue + } + + jsonManifest, err := yaml.ToJSON(yamlManifest) + if err != nil { + return fmt.Errorf("error converting manifest to JSON: %w", err) + } + + obj := new(unstructured.Unstructured) + + if err = json.Unmarshal(jsonManifest, obj); err != nil { + return fmt.Errorf("error loading JSON manifest into unstructured: %w", err) + } + + r.spec.Items = append(r.spec.Items, obj) + } + + return nil +} + +// Objects returns list of unstrustured object. +func (r *Manifest) Objects() []*unstructured.Unstructured { + return r.spec.Items +} diff --git a/internal/app/machined/pkg/resources/k8s/manifest_status.go b/internal/app/machined/pkg/resources/k8s/manifest_status.go new file mode 100644 index 000000000..9fa70f2a3 --- /dev/null +++ b/internal/app/machined/pkg/resources/k8s/manifest_status.go @@ -0,0 +1,77 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "fmt" + + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/resource/core" +) + +// ManifestStatusType is type of ManifestStatus resource. +const ManifestStatusType = resource.Type("k8s/manifestStatus") + +// ManifestStatusID is a singleton resource ID. +const ManifestStatusID = resource.ID("manifests") + +// ManifestStatus resource holds definition of kubelet static pod. +type ManifestStatus struct { + md resource.Metadata + spec ManifestStatusSpec +} + +// ManifestStatusSpec describes manifest application status. +type ManifestStatusSpec struct { + ManifestsApplied []string `yaml:"manifestsApplied"` +} + +// NewManifestStatus initializes an empty ManifestStatus resource. +func NewManifestStatus(namespace resource.Namespace) *ManifestStatus { + r := &ManifestStatus{ + md: resource.NewMetadata(namespace, ManifestStatusType, ManifestStatusID, resource.VersionUndefined), + spec: ManifestStatusSpec{}, + } + + r.md.BumpVersion() + + return r +} + +// Metadata implements resource.Resource. +func (r *ManifestStatus) Metadata() *resource.Metadata { + return &r.md +} + +// Spec implements resource.Resource. +func (r *ManifestStatus) Spec() interface{} { + return r.spec +} + +func (r *ManifestStatus) String() string { + return fmt.Sprintf("k8s.ManifestStatus(%q)", r.md.ID()) +} + +// DeepCopy implements resource.Resource. +func (r *ManifestStatus) DeepCopy() resource.Resource { + return &ManifestStatus{ + md: r.md, + spec: r.spec, + } +} + +// Status returns ManifestStatusSpec. +func (r *ManifestStatus) Status() *ManifestStatusSpec { + return &r.spec +} + +// ResourceDefinition implements core.ResourceDefinitionProvider interface. +func (r *ManifestStatus) ResourceDefinition() core.ResourceDefinitionSpec { + return core.ResourceDefinitionSpec{ + Type: ManifestStatusType, + Aliases: []resource.Type{"manifestStatus", "manifestStatuses"}, + DefaultNamespace: ControlPlaneNamespaceName, + } +} diff --git a/internal/app/machined/pkg/resources/k8s/secrets_status.go b/internal/app/machined/pkg/resources/k8s/secrets_status.go new file mode 100644 index 000000000..464b6c115 --- /dev/null +++ b/internal/app/machined/pkg/resources/k8s/secrets_status.go @@ -0,0 +1,78 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "fmt" + + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/resource/core" +) + +// SecretsStatusType is type of SecretsStatus resource. +const SecretsStatusType = resource.Type("k8s/secretsStatus") + +// StaticPodSecretsStaticPodID is resource ID for SecretStatus resource for static pods. +const StaticPodSecretsStaticPodID = resource.ID("staticPods") + +// SecretsStatus resource holds definition of rendered secrets. +type SecretsStatus struct { + md resource.Metadata + spec SecretsStatusSpec +} + +// SecretsStatusSpec describes status of rendered secrets. +type SecretsStatusSpec struct { + Ready bool `yaml:"ready"` + Version string `yaml:"version"` +} + +// NewSecretsStatus initializes a SecretsStatus resource. +func NewSecretsStatus(namespace resource.Namespace, id resource.ID) *SecretsStatus { + r := &SecretsStatus{ + md: resource.NewMetadata(namespace, SecretsStatusType, id, resource.VersionUndefined), + spec: SecretsStatusSpec{}, + } + + r.md.BumpVersion() + + return r +} + +// Metadata implements resource.Resource. +func (r *SecretsStatus) Metadata() *resource.Metadata { + return &r.md +} + +// Spec implements resource.Resource. +func (r *SecretsStatus) Spec() interface{} { + return r.spec +} + +func (r *SecretsStatus) String() string { + return fmt.Sprintf("k8s.SecretsStatus(%q)", r.md.ID()) +} + +// DeepCopy implements resource.Resource. +func (r *SecretsStatus) DeepCopy() resource.Resource { + return &SecretsStatus{ + md: r.md, + spec: r.spec, + } +} + +// ResourceDefinition implements core.ResourceDefinitionProvider interface. +func (r *SecretsStatus) ResourceDefinition() core.ResourceDefinitionSpec { + return core.ResourceDefinitionSpec{ + Type: SecretsStatusType, + Aliases: []resource.Type{"secretStatus"}, + DefaultNamespace: ControlPlaneNamespaceName, + } +} + +// Status sets pod status. +func (r *SecretsStatus) Status() *SecretsStatusSpec { + return &r.spec +} diff --git a/internal/app/machined/pkg/resources/k8s/static_pod.go b/internal/app/machined/pkg/resources/k8s/static_pod.go new file mode 100644 index 000000000..1a6ab8fed --- /dev/null +++ b/internal/app/machined/pkg/resources/k8s/static_pod.go @@ -0,0 +1,92 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "encoding/json" + "fmt" + + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/resource/core" + v1 "k8s.io/api/core/v1" +) + +// StaticPodType is type of StaticPod resource. +const StaticPodType = resource.Type("k8s/staticPod") + +// StaticPod resource holds definition of kubelet static pod. +type StaticPod struct { + md resource.Metadata + spec *staticPodSpec +} + +type staticPodSpec struct { + *v1.Pod +} + +func (spec *staticPodSpec) MarshalYAML() (interface{}, error) { + jsonSerialized, err := json.Marshal(spec.Pod) + if err != nil { + return nil, err + } + + var obj interface{} + + err = json.Unmarshal(jsonSerialized, &obj) + + return obj, err +} + +// NewStaticPod initializes a StaticPod resource. +func NewStaticPod(namespace resource.Namespace, id resource.ID, spec *v1.Pod) *StaticPod { + r := &StaticPod{ + md: resource.NewMetadata(namespace, StaticPodType, id, resource.VersionUndefined), + spec: &staticPodSpec{ + Pod: spec, + }, + } + + r.md.BumpVersion() + + return r +} + +// Metadata implements resource.Resource. +func (r *StaticPod) Metadata() *resource.Metadata { + return &r.md +} + +// Spec implements resource.Resource. +func (r *StaticPod) Spec() interface{} { + return r.spec +} + +func (r *StaticPod) String() string { + return fmt.Sprintf("k8s.StaticPod(%q)", r.md.ID()) +} + +// DeepCopy implements resource.Resource. +func (r *StaticPod) DeepCopy() resource.Resource { + return &StaticPod{ + md: r.md, + spec: &staticPodSpec{ + Pod: r.spec.Pod.DeepCopy(), + }, + } +} + +// ResourceDefinition implements core.ResourceDefinitionProvider interface. +func (r *StaticPod) ResourceDefinition() core.ResourceDefinitionSpec { + return core.ResourceDefinitionSpec{ + Type: StaticPodType, + Aliases: []resource.Type{"pod", "static-pod", "pods"}, + DefaultNamespace: ControlPlaneNamespaceName, + } +} + +// SetPod sets pod definition. +func (r *StaticPod) SetPod(podSpec *v1.Pod) { + r.spec.Pod = podSpec +} diff --git a/internal/app/machined/pkg/resources/k8s/static_pod_status.go b/internal/app/machined/pkg/resources/k8s/static_pod_status.go new file mode 100644 index 000000000..eaeea79e2 --- /dev/null +++ b/internal/app/machined/pkg/resources/k8s/static_pod_status.go @@ -0,0 +1,91 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package k8s + +import ( + "encoding/json" + "fmt" + + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/resource/core" + v1 "k8s.io/api/core/v1" +) + +// StaticPodStatusType is type of StaticPodStatus resource. +const StaticPodStatusType = resource.Type("k8s/staticPodStatus") + +// StaticPodStatus resource holds definition of kubelet static pod. +type StaticPodStatus struct { + md resource.Metadata + spec *staticPodStatusSpec +} + +// staticPodStatusSpec describes kubelet static pod status. +type staticPodStatusSpec struct { + *v1.PodStatus +} + +func (spec *staticPodStatusSpec) MarshalYAML() (interface{}, error) { + jsonSerialized, err := json.Marshal(spec.PodStatus) + if err != nil { + return nil, err + } + + var obj interface{} + + err = json.Unmarshal(jsonSerialized, &obj) + + return obj, err +} + +// NewStaticPodStatus initializes a StaticPodStatus resource. +func NewStaticPodStatus(namespace resource.Namespace, id resource.ID) *StaticPodStatus { + r := &StaticPodStatus{ + md: resource.NewMetadata(namespace, StaticPodStatusType, id, resource.VersionUndefined), + spec: &staticPodStatusSpec{}, + } + + r.md.BumpVersion() + + return r +} + +// Metadata implements resource.Resource. +func (r *StaticPodStatus) Metadata() *resource.Metadata { + return &r.md +} + +// Spec implements resource.Resource. +func (r *StaticPodStatus) Spec() interface{} { + return r.spec +} + +func (r *StaticPodStatus) String() string { + return fmt.Sprintf("k8s.StaticPodStatus(%q)", r.md.ID()) +} + +// DeepCopy implements resource.Resource. +func (r *StaticPodStatus) DeepCopy() resource.Resource { + return &StaticPodStatus{ + md: r.md, + spec: &staticPodStatusSpec{ + PodStatus: r.spec.PodStatus.DeepCopy(), + }, + } +} + +// ResourceDefinition implements core.ResourceDefinitionProvider interface. +func (r *StaticPodStatus) ResourceDefinition() core.ResourceDefinitionSpec { + return core.ResourceDefinitionSpec{ + Type: StaticPodStatusType, + Aliases: []resource.Type{"podStatus"}, + DefaultNamespace: ControlPlaneNamespaceName, + } +} + +// SetStatus sets pod status. +func (r *StaticPodStatus) SetStatus(status *v1.PodStatus) { + r.spec.PodStatus = status +} diff --git a/internal/app/machined/pkg/resources/secrets/kubernetes.go b/internal/app/machined/pkg/resources/secrets/kubernetes.go new file mode 100644 index 000000000..03ed53825 --- /dev/null +++ b/internal/app/machined/pkg/resources/secrets/kubernetes.go @@ -0,0 +1,93 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package secrets + +import ( + "fmt" + + "github.com/talos-systems/crypto/x509" + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/resource/core" +) + +// KubernetesType is type of Kubernetes resource. +const KubernetesType = resource.Type("secrets/kubernetes") + +// KubernetesID is ID of the singleton instance. +const KubernetesID = resource.ID("kubernetes") + +// Kubernetes contains K8s secrets. +type Kubernetes struct { + md resource.Metadata + spec KubernetesSpec +} + +// KubernetesSpec describes Kubernetes resources. +type KubernetesSpec struct { + EtcdCA *x509.PEMEncodedCertificateAndKey `yaml:"etcdCA"` + EtcdPeer *x509.PEMEncodedCertificateAndKey `yaml:"etcdPeer"` + + CA *x509.PEMEncodedCertificateAndKey `yaml:"ca"` + APIServer *x509.PEMEncodedCertificateAndKey `yaml:"apiServer"` + APIServerKubeletClient *x509.PEMEncodedCertificateAndKey `yaml:"apiServerKubeletClient"` + ServiceAccount *x509.PEMEncodedKey `yaml:"serviceAccount"` + AggregatorCA *x509.PEMEncodedCertificateAndKey `yaml:"aggregatorCA"` + FrontProxy *x509.PEMEncodedCertificateAndKey `yaml:"frontProxy"` + + AESCBCEncryptionSecret string `yaml:"aesCBCEncryptionSecret"` + + AdminKubeconfig string `yaml:"adminKubeconfig"` + + BootstrapTokenID string `yaml:"bootstrapTokenID"` + BootstrapTokenSecret string `yaml:"bootstrapTokenSecret"` +} + +// NewKubernetes initializes a Kubernetes resource. +func NewKubernetes() *Kubernetes { + r := &Kubernetes{ + md: resource.NewMetadata(NamespaceName, KubernetesType, KubernetesID, resource.VersionUndefined), + spec: KubernetesSpec{}, + } + + r.md.BumpVersion() + + return r +} + +// Metadata implements resource.Resource. +func (r *Kubernetes) Metadata() *resource.Metadata { + return &r.md +} + +// Spec implements resource.Resource. +func (r *Kubernetes) Spec() interface{} { + return r.spec +} + +func (r *Kubernetes) String() string { + return fmt.Sprintf("secrets.Kubernetes(%q)", r.md.ID()) +} + +// DeepCopy implements resource.Resource. +func (r *Kubernetes) DeepCopy() resource.Resource { + return &Kubernetes{ + md: r.md, + spec: r.spec, + } +} + +// ResourceDefinition implements core.ResourceDefinitionProvider interface. +func (r *Kubernetes) ResourceDefinition() core.ResourceDefinitionSpec { + return core.ResourceDefinitionSpec{ + Type: KubernetesType, + Aliases: []resource.Type{"secrets", "secret"}, + DefaultNamespace: NamespaceName, + } +} + +// Secrets returns .spec. +func (r *Kubernetes) Secrets() *KubernetesSpec { + return &r.spec +} diff --git a/internal/app/machined/pkg/resources/secrets/secrets.go b/internal/app/machined/pkg/resources/secrets/secrets.go new file mode 100644 index 000000000..491c70236 --- /dev/null +++ b/internal/app/machined/pkg/resources/secrets/secrets.go @@ -0,0 +1,11 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package secrets provides resources which store secrets. +package secrets + +import "github.com/talos-systems/os-runtime/pkg/resource" + +// NamespaceName contains resources containing secret material. +const NamespaceName resource.Namespace = "secrets" diff --git a/internal/app/machined/pkg/resources/v1alpha1/bootstrap_status.go b/internal/app/machined/pkg/resources/v1alpha1/bootstrap_status.go new file mode 100644 index 000000000..209de032c --- /dev/null +++ b/internal/app/machined/pkg/resources/v1alpha1/bootstrap_status.go @@ -0,0 +1,77 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package v1alpha1 + +import ( + "fmt" + + "github.com/talos-systems/os-runtime/pkg/resource" + "github.com/talos-systems/os-runtime/pkg/resource/core" +) + +// BootstrapStatusType is type of BootstrapStatus resource. +const BootstrapStatusType = resource.Type("v1alpha1/bootstrapStatus") + +// BootstrapStatusID is a singleton instance ID. +const BootstrapStatusID = resource.ID("bootstrapStatus") + +// BootstrapStatus describes v1alpha1 (bootkube) bootstrap status. +type BootstrapStatus struct { + md resource.Metadata + spec BootstrapStatusSpec +} + +// BootstrapStatusSpec describe service state. +type BootstrapStatusSpec struct { + SelfHostedControlPlane bool `yaml:"selfHostedControlPlane"` +} + +// NewBootstrapStatus initializes a BootstrapStatus resource. +func NewBootstrapStatus() *BootstrapStatus { + r := &BootstrapStatus{ + md: resource.NewMetadata(NamespaceName, BootstrapStatusType, BootstrapStatusID, resource.VersionUndefined), + spec: BootstrapStatusSpec{}, + } + + r.md.BumpVersion() + + return r +} + +// Metadata implements resource.Resource. +func (r *BootstrapStatus) Metadata() *resource.Metadata { + return &r.md +} + +// Spec implements resource.Resource. +func (r *BootstrapStatus) Spec() interface{} { + return r.spec +} + +func (r *BootstrapStatus) String() string { + return fmt.Sprintf("v1alpha1.BootstrapStatus(%q)", r.md.ID()) +} + +// DeepCopy implements resource.Resource. +func (r *BootstrapStatus) DeepCopy() resource.Resource { + return &BootstrapStatus{ + md: r.md, + spec: r.spec, + } +} + +// ResourceDefinition implements core.ResourceDefinitionProvider interface. +func (r *BootstrapStatus) ResourceDefinition() core.ResourceDefinitionSpec { + return core.ResourceDefinitionSpec{ + Type: BootstrapStatusType, + Aliases: []resource.Type{"bootstrapStatus"}, + DefaultNamespace: NamespaceName, + } +} + +// Status returns .spec. +func (r *BootstrapStatus) Status() *BootstrapStatusSpec { + return &r.spec +} diff --git a/internal/app/machined/pkg/resources/v1alpha1/service.go b/internal/app/machined/pkg/resources/v1alpha1/service.go index c15db1254..e40528095 100644 --- a/internal/app/machined/pkg/resources/v1alpha1/service.go +++ b/internal/app/machined/pkg/resources/v1alpha1/service.go @@ -73,3 +73,18 @@ func (r *Service) ResourceDefinition() core.ResourceDefinitionSpec { func (r *Service) SetRunning(running bool) { r.spec.Running = true } + +// SetHealthy changes .spec.healthy. +func (r *Service) SetHealthy(healthy bool) { + r.spec.Healthy = true +} + +// Running returns .spec.running. +func (r *Service) Running() bool { + return r.spec.Running +} + +// Healthy returns .spec.healthy. +func (r *Service) Healthy() bool { + return r.spec.Healthy +} diff --git a/internal/app/machined/pkg/runtime/controller.go b/internal/app/machined/pkg/runtime/controller.go index 51993bc0c..9274356d0 100644 --- a/internal/app/machined/pkg/runtime/controller.go +++ b/internal/app/machined/pkg/runtime/controller.go @@ -7,6 +7,8 @@ package runtime import ( "context" "log" + + "github.com/talos-systems/os-runtime/pkg/controller" ) // TaskSetupFunc defines the function that a task will execute for a specific runtime @@ -57,4 +59,5 @@ type Controller interface { // V1Alpha2Controller provides glue into v2alpha1 controller runtime. type V1Alpha2Controller interface { Run(context.Context) error + DependencyGraph() (*controller.DependencyGraph, error) } diff --git a/internal/app/machined/pkg/runtime/sequencer.go b/internal/app/machined/pkg/runtime/sequencer.go index 407cec82b..1ec61c097 100644 --- a/internal/app/machined/pkg/runtime/sequencer.go +++ b/internal/app/machined/pkg/runtime/sequencer.go @@ -34,8 +34,6 @@ const ( SequenceReset // SequenceReboot is the reboot sequence. SequenceReboot - // SequenceRecover is the recover sequence. - SequenceRecover // SequenceNoop is the noop sequence. SequenceNoop ) @@ -51,13 +49,12 @@ const ( stageUpgrade = "stageUpgrade" reset = "reset" reboot = "reboot" - recover = "recover" noop = "noop" ) // String returns the string representation of a `Sequence`. func (s Sequence) String() string { - return [...]string{applyConfiguration, boot, bootstrap, initialize, install, shutdown, upgrade, stageUpgrade, reset, reboot, recover, noop}[s] + return [...]string{applyConfiguration, boot, bootstrap, initialize, install, shutdown, upgrade, stageUpgrade, reset, reboot, noop}[s] } // ParseSequence returns a `Sequence` that matches the specified string. @@ -85,8 +82,6 @@ func ParseSequence(s string) (seq Sequence, err error) { seq = SequenceReset case reboot: seq = SequenceReboot - case recover: - seq = SequenceRecover case noop: seq = SequenceNoop default: @@ -118,7 +113,6 @@ type Sequencer interface { Initialize(Runtime) []Phase Install(Runtime) []Phase Reboot(Runtime) []Phase - Recover(Runtime, *machine.RecoverRequest) []Phase Reset(Runtime, ResetOptions) []Phase Shutdown(Runtime) []Phase StageUpgrade(Runtime, *machine.UpgradeRequest) []Phase diff --git a/internal/app/machined/pkg/runtime/sequencer_test.go b/internal/app/machined/pkg/runtime/sequencer_test.go index 572525b0a..c915481e7 100644 --- a/internal/app/machined/pkg/runtime/sequencer_test.go +++ b/internal/app/machined/pkg/runtime/sequencer_test.go @@ -52,11 +52,6 @@ func TestSequence_String(t *testing.T) { s: runtime.SequenceReset, want: "reset", }, - { - name: "recover", - s: runtime.SequenceRecover, - want: "recover", - }, } for _, tt := range tests { @@ -121,12 +116,6 @@ func TestParseSequence(t *testing.T) { wantSeq: runtime.SequenceReset, wantErr: false, }, - { - name: "recover", - args: args{"recover"}, - wantSeq: runtime.SequenceRecover, - wantErr: false, - }, { name: "invalid", args: args{"invalid"}, diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_controller.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_controller.go index b12c06307..879892f4f 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_controller.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_controller.go @@ -101,7 +101,7 @@ func (c *Controller) Run(seq runtime.Sequence, data interface{}, setters ...runt // Allow only one sequence to run at a time with the exception of bootstrap // and reset sequences. switch seq { //nolint: exhaustive - case runtime.SequenceBootstrap, runtime.SequenceReset, runtime.SequenceRecover: + case runtime.SequenceBootstrap, runtime.SequenceReset: // Do not attempt to lock. default: if opts.Force { @@ -373,17 +373,6 @@ func (c *Controller) phases(seq runtime.Sequence, data interface{}) ([]runtime.P phases = c.s.Shutdown(c.r) case runtime.SequenceReboot: phases = c.s.Reboot(c.r) - case runtime.SequenceRecover: - var ( - in *machine.RecoverRequest - ok bool - ) - - if in, ok = data.(*machine.RecoverRequest); !ok { - return nil, runtime.ErrInvalidSequenceData - } - - phases = c.s.Recover(c.r, in) case runtime.SequenceUpgrade: var ( in *machine.UpgradeRequest diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go index 482c795d3..c406136ee 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go @@ -266,12 +266,6 @@ func (*Sequencer) Bootstrap(r runtime.Runtime) []runtime.Phase { phases = phases.Append( "etcd", BootstrapEtcd, - ).Append( - "kubernetes", - BootstrapKubernetes, - ).Append( - "initStatus", - SetInitStatus, ) return phases @@ -285,15 +279,6 @@ func (*Sequencer) Reboot(r runtime.Runtime) []runtime.Phase { return phases } -// Recover is the recover sequence. -func (*Sequencer) Recover(r runtime.Runtime, in *machineapi.RecoverRequest) []runtime.Phase { - phases := PhaseList{} - - phases = phases.Append("recover", Recover) - - return phases -} - // Reset is the reset sequence. func (*Sequencer) Reset(r runtime.Runtime, in runtime.ResetOptions) []runtime.Phase { phases := PhaseList{} diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go index 1f9ed80a5..556022603 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go @@ -31,7 +31,6 @@ import ( "github.com/talos-systems/go-blockdevice/blockdevice/util" "github.com/talos-systems/go-procfs/procfs" "github.com/talos-systems/go-retry/retry" - "go.etcd.io/etcd/clientv3" "golang.org/x/sys/unix" runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" @@ -53,7 +52,6 @@ import ( "github.com/talos-systems/talos/internal/pkg/etcd" "github.com/talos-systems/talos/internal/pkg/kernel/kspp" "github.com/talos-systems/talos/internal/pkg/kmsg" - "github.com/talos-systems/talos/internal/pkg/kubeconfig" "github.com/talos-systems/talos/internal/pkg/mount" "github.com/talos-systems/talos/pkg/cmd" "github.com/talos-systems/talos/pkg/conditions" @@ -709,7 +707,6 @@ func StartAllServices(seq runtime.Sequence, data interface{}) (runtime.TaskExecu svcs.Load( &services.Trustd{}, &services.Etcd{Bootstrap: true}, - &services.Bootkube{}, ) case machine.TypeControlPlane: svcs.Load( @@ -732,8 +729,7 @@ func StartAllServices(seq runtime.Sequence, data interface{}) (runtime.TaskExecu all = append(all, cond) } - ctx, cancel := context.WithTimeout(ctx, constants.BootkubeRunTimeout) - + ctx, cancel := context.WithTimeout(ctx, constants.BootTimeout) defer cancel() return conditions.WaitForAll(all...).Wait(ctx) @@ -1662,56 +1658,6 @@ func Install(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, }, "install" } -// Recover attempts to recover the control plane. -// -// nolint: gocyclo -func Recover(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { - return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { - var ( - in *machineapi.RecoverRequest - ok bool - ) - - if in, ok = data.(*machineapi.RecoverRequest); !ok { - return runtime.ErrInvalidSequenceData - } - - var b bytes.Buffer - - if err = kubeconfig.GenerateAdmin(r.Config().Cluster(), &b); err != nil { - return err - } - - if err = ioutil.WriteFile(constants.RecoveryKubeconfig, b.Bytes(), 0o600); err != nil { - return fmt.Errorf("failed to create recovery kubeconfig: %w", err) - } - - // nolint: errcheck - defer os.Remove(constants.RecoveryKubeconfig) - - svc := &services.Bootkube{ - Recover: true, - Source: in.Source, - } - - // unload bootkube (if any instance ran before) - if err = system.Services(r).Unload(ctx, svc.ID(r)); err != nil { - return err - } - - system.Services(r).Load(svc) - - if err = system.Services(r).Start(svc.ID(r)); err != nil { - return fmt.Errorf("failed to start bootkube: %w", err) - } - - ctx, cancel := context.WithTimeout(ctx, 10*time.Minute) - defer cancel() - - return system.WaitForService(system.StateEventFinished, svc.ID(r)).Wait(ctx) - }, "recover" -} - // BootstrapEtcd represents the task for bootstrapping etcd. func BootstrapEtcd(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { @@ -1771,50 +1717,6 @@ func BootstrapEtcd(seq runtime.Sequence, data interface{}) (runtime.TaskExecutio }, "bootstrapEtcd" } -// BootstrapKubernetes represents the task for bootstrapping Kubernetes. -func BootstrapKubernetes(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { - return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { - svc := &services.Bootkube{} - - system.Services(r).LoadAndStart(svc) - - ctx, cancel := context.WithTimeout(ctx, constants.BootkubeRunTimeout) - defer cancel() - - return system.WaitForService(system.StateEventFinished, svc.ID(r)).Wait(ctx) - }, "bootstrapKubernetes" -} - -// SetInitStatus represents the task for setting the initialization status -// in etcd. -func SetInitStatus(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { - return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { - client, err := etcd.NewClient([]string{"127.0.0.1:2379"}) - if err != nil { - return err - } - - // nolint: errcheck - defer client.Close() - - err = retry.Exponential(15*time.Second, retry.WithUnits(50*time.Millisecond), retry.WithJitter(25*time.Millisecond)).Retry(func() error { - ctx := clientv3.WithRequireLeader(context.Background()) - if _, err = client.Put(ctx, constants.InitializedKey, "true"); err != nil { - return retry.ExpectedError(err) - } - - return nil - }) - if err != nil { - return fmt.Errorf("failed to put state into etcd: %w", err) - } - - logger.Println("updated initialization status in etcd") - - return nil - }, "SetInitStatus" -} - // ActivateLogicalVolumes represents the task for activating logical volumes. func ActivateLogicalVolumes(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { diff --git a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go index ead10799c..d3625e34b 100644 --- a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go +++ b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go @@ -11,6 +11,9 @@ import ( "github.com/talos-systems/os-runtime/pkg/controller" osruntime "github.com/talos-systems/os-runtime/pkg/controller/runtime" + "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/config" + "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/k8s" + "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/secrets" "github.com/talos-systems/talos/internal/app/machined/pkg/controllers/v1alpha1" "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" ) @@ -33,7 +36,7 @@ func NewController(v1alpha1Runtime runtime.Runtime, loggingManager runtime.Loggi return nil, err } - logger := log.New(logWriter, "controller-runtime: ", log.Flags()) + logger := log.New(logWriter, "", log.LstdFlags|log.Lmsgprefix) ctrl.controllerRuntime, err = osruntime.NewRuntime(v1alpha1Runtime.State().V1Alpha2().Resources(), logger) @@ -43,10 +46,20 @@ func NewController(v1alpha1Runtime runtime.Runtime, loggingManager runtime.Loggi // Run the controller runtime. func (ctrl *Controller) Run(ctx context.Context) error { for _, c := range []controller.Controller{ + &v1alpha1.BootstrapStatusController{}, &v1alpha1.ServiceController{ // V1Events V1Alpha1Events: ctrl.v1alpha1Runtime.Events(), }, + &config.MachineTypeController{}, + &config.K8sControlPlaneController{}, + &k8s.ControlPlaneStaticPodController{}, + &k8s.ExtraManifestController{}, + &k8s.KubeletStaticPodController{}, + &k8s.ManifestController{}, + &k8s.ManifestApplyController{}, + &k8s.RenderSecretsStaticPodController{}, + &secrets.KubernetesController{}, } { if err := ctrl.controllerRuntime.RegisterController(c); err != nil { return err @@ -55,3 +68,8 @@ func (ctrl *Controller) Run(ctx context.Context) error { return ctrl.controllerRuntime.Run(ctx) } + +// DependencyGraph returns controller-resources dependencies. +func (ctrl *Controller) DependencyGraph() (*controller.DependencyGraph, error) { + return ctrl.controllerRuntime.GetDependencyGraph() +} diff --git a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go index 17e1d9da1..7cef62fa0 100644 --- a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go +++ b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go @@ -14,6 +14,8 @@ import ( "github.com/talos-systems/os-runtime/pkg/state/registry" "github.com/talos-systems/talos/internal/app/machined/pkg/resources/config" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/k8s" + "github.com/talos-systems/talos/internal/app/machined/pkg/resources/secrets" "github.com/talos-systems/talos/internal/app/machined/pkg/resources/v1alpha1" talosconfig "github.com/talos-systems/talos/pkg/machinery/config" ) @@ -53,10 +55,31 @@ func NewState() (*State, error) { return nil, err } + if err := s.namespaceRegistry.Register(ctx, k8s.ControlPlaneNamespaceName, "Kubernetes control plane resources.", true); err != nil { + return nil, err + } + + if err := s.namespaceRegistry.Register(ctx, k8s.ExtraNamespaceName, "Kubernetes extra configuration resources.", true); err != nil { + return nil, err + } + + if err := s.namespaceRegistry.Register(ctx, secrets.NamespaceName, "Resources with secret material.", true); err != nil { + return nil, err + } + // register Talos resources for _, r := range []resource.Resource{ + &v1alpha1.BootstrapStatus{}, &v1alpha1.Service{}, &config.V1Alpha1{}, + &config.MachineType{}, + &config.K8sControlPlane{}, + &k8s.Manifest{}, + &k8s.ManifestStatus{}, + &k8s.StaticPod{}, + &k8s.StaticPodStatus{}, + &k8s.SecretsStatus{}, + &secrets.Kubernetes{}, } { if err := s.resourceRegistry.Register(ctx, r); err != nil { return nil, err diff --git a/internal/app/machined/pkg/system/events/events.go b/internal/app/machined/pkg/system/events/events.go index ffa67f108..65964bf80 100644 --- a/internal/app/machined/pkg/system/events/events.go +++ b/internal/app/machined/pkg/system/events/events.go @@ -9,6 +9,7 @@ import ( "github.com/golang/protobuf/ptypes" + "github.com/talos-systems/talos/internal/app/machined/pkg/system/health" machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine" ) @@ -57,6 +58,7 @@ func (state ServiceState) String() string { type ServiceEvent struct { Message string State ServiceState + Health health.Status Timestamp time.Time } @@ -66,6 +68,7 @@ func (event *ServiceEvent) AsProto(service string) *machineapi.ServiceStateEvent Service: service, Action: machineapi.ServiceStateEvent_Action(event.State), Message: event.Message, + Health: event.Health.AsProto(), } } diff --git a/internal/app/machined/pkg/system/health/status.go b/internal/app/machined/pkg/system/health/status.go index f8c8327c6..7ff736903 100644 --- a/internal/app/machined/pkg/system/health/status.go +++ b/internal/app/machined/pkg/system/health/status.go @@ -20,6 +20,19 @@ type Status struct { LastMessage string } +// AsProto returns protobuf-ready health state. +func (status *Status) AsProto() *machineapi.ServiceHealth { + // nolint: errcheck + tspb, _ := ptypes.TimestampProto(status.LastChange) + + return &machineapi.ServiceHealth{ + Unknown: status.Healthy == nil, + Healthy: status.Healthy != nil && *status.Healthy, + LastMessage: status.LastMessage, + LastChange: tspb, + } +} + // StateChange is used to notify about status changes. type StateChange struct { Old Status @@ -114,13 +127,5 @@ func (state *State) Get() Status { func (state *State) AsProto() *machineapi.ServiceHealth { status := state.Get() - // nolint: errcheck - tspb, _ := ptypes.TimestampProto(status.LastChange) - - return &machineapi.ServiceHealth{ - Unknown: status.Healthy == nil, - Healthy: status.Healthy != nil && *status.Healthy, - LastMessage: status.LastMessage, - LastChange: tspb, - } + return status.AsProto() } diff --git a/internal/app/machined/pkg/system/service_runner.go b/internal/app/machined/pkg/system/service_runner.go index 59c4c0964..4f4fb2ff4 100644 --- a/internal/app/machined/pkg/system/service_runner.go +++ b/internal/app/machined/pkg/system/service_runner.go @@ -125,6 +125,7 @@ func (svcrunner *ServiceRunner) healthUpdate(change health.StateChange) { event := events.ServiceEvent{ Message: message, State: svcrunner.state, + Health: change.New, Timestamp: time.Now(), } svcrunner.events.Push(event) @@ -137,6 +138,10 @@ func (svcrunner *ServiceRunner) healthUpdate(change health.StateChange) { if isUp { svcrunner.notifyEvent(StateEventUp) } + + if svcrunner.runtime != nil { + svcrunner.runtime.Events().Publish(event.AsProto(svcrunner.id)) + } } // GetEventHistory returns history of events for this service. diff --git a/internal/app/machined/pkg/system/services/bootkube.go b/internal/app/machined/pkg/system/services/bootkube.go deleted file mode 100644 index d19d87f4d..000000000 --- a/internal/app/machined/pkg/system/services/bootkube.go +++ /dev/null @@ -1,198 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package services - -import ( - "bytes" - "context" - "errors" - "fmt" - "log" - "strconv" - "time" - - "github.com/containerd/containerd/oci" - specs "github.com/opencontainers/runtime-spec/specs-go" - "github.com/talos-systems/go-retry/retry" - "go.etcd.io/etcd/clientv3" - "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes" - - "github.com/talos-systems/talos/internal/app/machined/pkg/runtime" - "github.com/talos-systems/talos/internal/app/machined/pkg/system/events" - "github.com/talos-systems/talos/internal/app/machined/pkg/system/runner" - "github.com/talos-systems/talos/internal/app/machined/pkg/system/runner/containerd" - "github.com/talos-systems/talos/internal/pkg/containers/image" - "github.com/talos-systems/talos/internal/pkg/etcd" - "github.com/talos-systems/talos/pkg/conditions" - machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine" - "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" - "github.com/talos-systems/talos/pkg/machinery/constants" -) - -// Bootkube implements the Service interface. It serves as the concrete type with -// the required methods. -type Bootkube struct { - Source machineapi.RecoverRequest_Source - Recover bool - - provisioned bool -} - -// ID implements the Service interface. -func (b *Bootkube) ID(r runtime.Runtime) string { - return "bootkube" -} - -// PreFunc implements the Service interface. -func (b *Bootkube) PreFunc(ctx context.Context, r runtime.Runtime) (err error) { - if !b.Recover { - client, err := etcd.NewClient([]string{"127.0.0.1:2379"}) - if err != nil { - return err - } - - // nolint: errcheck - defer client.Close() - - err = retry.Exponential(3*time.Minute, retry.WithUnits(50*time.Millisecond), retry.WithJitter(25*time.Millisecond)).Retry(func() error { - var resp *clientv3.GetResponse - - // limit single attempt to 15 seconds to allow for 12 attempts at least - attemptCtx, attemptCtxCancel := context.WithTimeout(ctx, 15*time.Second) - defer attemptCtxCancel() - - if resp, err = client.Get(clientv3.WithRequireLeader(attemptCtx), constants.InitializedKey); err != nil { - if errors.Is(err, rpctypes.ErrGRPCKeyNotFound) { - // no key set yet, treat as not provisioned yet - return nil - } - - return retry.ExpectedError(err) - } - - if len(resp.Kvs) == 0 { - // no key/values in the range, treat as not provisioned yet - return nil - } - - if string(resp.Kvs[0].Value) == "true" { - b.provisioned = true - } - - return nil - }) - - if err != nil { - return fmt.Errorf("error querying cluster provisioned state in etcd: %w", err) - } - - if b.provisioned { - return nil - } - } - - return image.Import(ctx, "/usr/images/bootkube.tar", "talos/bootkube") -} - -// PostFunc implements the Service interface. -// -// This is temorary and should be removed once we remove the init node type. -func (b *Bootkube) PostFunc(r runtime.Runtime, state events.ServiceState) (err error) { - if r.Config().Machine().Type() != machine.TypeInit { - return nil - } - - if state != events.StateFinished { - log.Println("bootkube run did not complete successfully. skipping etcd update") - - return nil - } - - client, err := etcd.NewClient([]string{"127.0.0.1:2379"}) - if err != nil { - return err - } - - // nolint: errcheck - defer client.Close() - - err = retry.Exponential(15*time.Second, retry.WithUnits(50*time.Millisecond), retry.WithJitter(25*time.Millisecond)).Retry(func() error { - ctx := clientv3.WithRequireLeader(context.Background()) - if _, err = client.Put(ctx, constants.InitializedKey, "true"); err != nil { - return retry.ExpectedError(err) - } - - return nil - }) - if err != nil { - return fmt.Errorf("failed to put state into etcd: %w", err) - } - - log.Println("updated initialization status in etcd") - - return nil -} - -// DependsOn implements the Service interface. -func (b *Bootkube) DependsOn(r runtime.Runtime) []string { - return []string{"etcd", "kubelet"} -} - -// Condition implements the Service interface. -func (b *Bootkube) Condition(r runtime.Runtime) conditions.Condition { - return nil -} - -// Runner implements the Service interface. -func (b *Bootkube) Runner(r runtime.Runtime) (runner.Runner, error) { - if b.provisioned { - return nil, nil - } - - image := "talos/bootkube" - - // Set the process arguments. - args := runner.Args{ - ID: b.ID(r), - ProcessArgs: []string{ - "/bootkube", - "--strict=" + strconv.FormatBool(!b.Recover), - "--recover=" + strconv.FormatBool(b.Recover), - "--recover-source=" + b.Source.String(), - }, - } - - env := []string{} - for key, val := range r.Config().Machine().Env() { - env = append(env, fmt.Sprintf("%s=%s", key, val)) - } - - // Set the required kubelet mounts. - mounts := []specs.Mount{ - {Type: "bind", Destination: "/etc/ssl", Source: "/etc/ssl", Options: []string{"bind", "ro"}}, - {Type: "bind", Destination: "/etc/kubernetes", Source: "/etc/kubernetes", Options: []string{"bind", "rshared", "rw"}}, - } - - bb, err := r.Config().Bytes() - if err != nil { - return nil, err - } - - stdin := bytes.NewReader(bb) - - return containerd.NewRunner( - r.Config().Debug(), - &args, - runner.WithStdin(stdin), - runner.WithLoggingManager(r.Logging()), - runner.WithContainerdAddress(constants.SystemContainerdAddress), - runner.WithContainerImage(image), - runner.WithEnv(env), - runner.WithOCISpecOpts( - oci.WithHostNamespace(specs.NetworkNamespace), - oci.WithMounts(mounts), - ), - ), nil -} diff --git a/internal/app/machined/pkg/system/services/etcd.go b/internal/app/machined/pkg/system/services/etcd.go index 8f28228f6..7785928ed 100644 --- a/internal/app/machined/pkg/system/services/etcd.go +++ b/internal/app/machined/pkg/system/services/etcd.go @@ -6,13 +6,10 @@ package services import ( "context" - stdlibx509 "crypto/x509" - "encoding/pem" "errors" "fmt" "io" "io/ioutil" - stdlibnet "net" "os" goruntime "runtime" "strings" @@ -22,7 +19,6 @@ import ( "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/oci" specs "github.com/opencontainers/runtime-spec/specs-go" - "github.com/talos-systems/crypto/x509" "github.com/talos-systems/go-retry/retry" "github.com/talos-systems/net" "go.etcd.io/etcd/clientv3" @@ -186,7 +182,6 @@ func (e *Etcd) HealthSettings(runtime.Runtime) *health.Settings { } } -// nolint: gocyclo func generatePKI(r runtime.Runtime) (err error) { if err = os.MkdirAll(constants.EtcdPKIPath, 0o644); err != nil { return err @@ -200,96 +195,16 @@ func generatePKI(r runtime.Runtime) (err error) { return fmt.Errorf("failed to write CA key: %w", err) } - ips, err := net.IPAddrs() + certAndKey, err := etcd.GeneratePeerCert(r.Config().Cluster().Etcd().CA()) if err != nil { - return fmt.Errorf("failed to discover IP addresses: %w", err) - } - - ips = append(ips, stdlibnet.ParseIP("127.0.0.1")) - if net.IsIPv6(ips...) { - ips = append(ips, stdlibnet.ParseIP("::1")) - } - - hostname, err := os.Hostname() - if err != nil { - return fmt.Errorf("failed to get hostname: %w", err) - } - - dnsNames, err := net.DNSNames() - if err != nil { - return fmt.Errorf("failed to get host DNS names: %w", err) - } - - dnsNames = append(dnsNames, "localhost") - - opts := []x509.Option{ - x509.CommonName(hostname), - x509.DNSNames(dnsNames), - x509.RSA(true), - x509.IPAddresses(ips), - x509.NotAfter(time.Now().Add(87600 * time.Hour)), - } - - peerKey, err := x509.NewRSAKey() - if err != nil { - return fmt.Errorf("failled to create RSA key: %w", err) - } - - pemBlock, _ := pem.Decode(peerKey.KeyPEM) - if pemBlock == nil { - return errors.New("failed to decode peer key pem") - } - - peerKeyRSA, err := stdlibx509.ParsePKCS1PrivateKey(pemBlock.Bytes) - if err != nil { - return fmt.Errorf("failled to parse private key: %w", err) - } - - csr, err := x509.NewCertificateSigningRequest(peerKeyRSA, opts...) - if err != nil { - return fmt.Errorf("failed to create CSR: %w", err) - } - - csrPemBlock, _ := pem.Decode(csr.X509CertificateRequestPEM) - if csrPemBlock == nil { - return errors.New("failed to decode csr pem") - } - - ccsr, err := stdlibx509.ParseCertificateRequest(csrPemBlock.Bytes) - if err != nil { - return fmt.Errorf("failled to parse certificate request: %w", err) - } - - caPemBlock, _ := pem.Decode(r.Config().Cluster().Etcd().CA().Crt) - if caPemBlock == nil { - return errors.New("failed to decode ca cert pem") - } - - caCrt, err := stdlibx509.ParseCertificate(caPemBlock.Bytes) - if err != nil { - return fmt.Errorf("failed to parse CA: %w", err) - } - - caKeyPemBlock, _ := pem.Decode(r.Config().Cluster().Etcd().CA().Key) - if caKeyPemBlock == nil { - return errors.New("failed to decode ca key pem") - } - - caKey, err := stdlibx509.ParsePKCS1PrivateKey(caKeyPemBlock.Bytes) - if err != nil { - return fmt.Errorf("failed to parse CA private key: %w", err) - } - - peer, err := x509.NewCertificateFromCSR(caCrt, caKey, ccsr, opts...) - if err != nil { - return fmt.Errorf("failled to create peer certificate: %w", err) - } - - if err := ioutil.WriteFile(constants.KubernetesEtcdPeerKey, peerKey.KeyPEM, 0o500); err != nil { return err } - if err := ioutil.WriteFile(constants.KubernetesEtcdPeerCert, peer.X509CertificatePEM, 0o500); err != nil { + if err := ioutil.WriteFile(constants.KubernetesEtcdPeerKey, certAndKey.Key, 0o500); err != nil { + return err + } + + if err := ioutil.WriteFile(constants.KubernetesEtcdPeerCert, certAndKey.Crt, 0o500); err != nil { return err } diff --git a/internal/app/machined/pkg/system/services/kubelet.go b/internal/app/machined/pkg/system/services/kubelet.go index a15f01cd4..eca7d1e0c 100644 --- a/internal/app/machined/pkg/system/services/kubelet.go +++ b/internal/app/machined/pkg/system/services/kubelet.go @@ -10,11 +10,9 @@ import ( "encoding/base64" "fmt" "io/ioutil" - "net" "net/http" "os" "path/filepath" - "strings" "text/template" "time" @@ -24,7 +22,6 @@ import ( criconstants "github.com/containerd/cri/pkg/constants" cni "github.com/containerd/go-cni" specs "github.com/opencontainers/runtime-spec/specs-go" - tnet "github.com/talos-systems/net" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/serializer/json" kubeletconfig "k8s.io/kubelet/config/v1beta1" @@ -244,9 +241,9 @@ func newKubeletConfiguration(clusterDNS []string, dnsDomain string) *kubeletconf APIVersion: "kubelet.config.k8s.io/v1beta1", Kind: "KubeletConfiguration", }, - StaticPodPath: "/etc/kubernetes/manifests", + StaticPodPath: constants.ManifestsDirectory, Address: "0.0.0.0", - Port: 10250, + Port: constants.KubeletPort, RotateCertificates: true, Authentication: kubeletconfig.KubeletAuthentication{ X509: kubeletconfig.KubeletX509Authentication{ @@ -278,7 +275,7 @@ func (k *Kubelet) args(r runtime.Runtime) ([]string, error) { "config": "/etc/kubernetes/kubelet.yaml", "dynamic-config-dir": "/etc/kubernetes/kubelet", - "cert-dir": "/var/lib/kubelet/pki", + "cert-dir": constants.KubeletPKIDir, "cni-conf-dir": cni.DefaultNetDir, } @@ -294,23 +291,18 @@ func (k *Kubelet) args(r runtime.Runtime) ([]string, error) { } func writeKubeletConfig(r runtime.Runtime) error { - dnsServiceIPs := []string{} - - for _, cidr := range strings.Split(r.Config().Cluster().Network().ServiceCIDR(), ",") { - _, svcCIDR, err := net.ParseCIDR(cidr) - if err != nil { - return fmt.Errorf("failed to parse service CIDR %s: %v", cidr, err) - } - - dnsIP, err := tnet.NthIPInNetwork(svcCIDR, 10) - if err != nil { - return fmt.Errorf("failed to calculate Nth IP in CIDR %s: %v", svcCIDR, err) - } - - dnsServiceIPs = append(dnsServiceIPs, dnsIP.String()) + dnsServiceIPs, err := r.Config().Cluster().Network().DNSServiceIPs() + if err != nil { + return fmt.Errorf("failed to get DNS service IPs: %w", err) } - kubeletConfiguration := newKubeletConfiguration(dnsServiceIPs, r.Config().Cluster().Network().DNSDomain()) + dnsServiceIPsString := make([]string, 0, len(dnsServiceIPs)) + + for _, dnsIP := range dnsServiceIPs { + dnsServiceIPsString = append(dnsServiceIPsString, dnsIP.String()) + } + + kubeletConfiguration := newKubeletConfiguration(dnsServiceIPsString, r.Config().Cluster().Network().DNSDomain()) serializer := json.NewSerializerWithOptions( json.DefaultMetaFactory, diff --git a/internal/app/routerd/main.go b/internal/app/routerd/main.go index d946a7aff..3a358e7b1 100644 --- a/internal/app/routerd/main.go +++ b/internal/app/routerd/main.go @@ -31,6 +31,7 @@ func main() { router.RegisterLocalBackend("os.OSService", machinedBackend) router.RegisterLocalBackend("machine.MachineService", machinedBackend) router.RegisterLocalBackend("resource.ResourceService", machinedBackend) + router.RegisterLocalBackend("inspect.InspectService", machinedBackend) router.RegisterLocalBackend("time.TimeService", backend.NewLocal("timed", constants.TimeSocketPath)) router.RegisterLocalBackend("network.NetworkService", backend.NewLocal("networkd", constants.NetworkSocketPath)) router.RegisterLocalBackend("cluster.ClusterService", machinedBackend) diff --git a/internal/integration/api/recover.go b/internal/integration/api/recover.go deleted file mode 100644 index b84531de3..000000000 --- a/internal/integration/api/recover.go +++ /dev/null @@ -1,147 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -// +build integration_api - -package api - -import ( - "context" - "sort" - "testing" - "time" - - "golang.org/x/sync/errgroup" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/talos-systems/talos/internal/integration/base" - machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine" - "github.com/talos-systems/talos/pkg/machinery/client" - "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" -) - -// RecoverSuite ... -type RecoverSuite struct { - base.K8sSuite - - ctx context.Context - ctxCancel context.CancelFunc -} - -// SuiteName ... -func (suite *RecoverSuite) SuiteName() string { - return "api.RecoverSuite" -} - -// SetupTest ... -func (suite *RecoverSuite) SetupTest() { - if testing.Short() { - suite.T().Skip("skipping in short mode") - } - - // make sure we abort at some point in time, but give enough room for Recovers - suite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Minute) -} - -// TearDownTest ... -func (suite *RecoverSuite) TearDownTest() { - if suite.ctxCancel != nil { - suite.ctxCancel() - } -} - -// TestRecoverControlPlane removes the control plane components and attempts to recover them with the recover API. -func (suite *RecoverSuite) TestRecoverControlPlane() { - suite.T().Skip("with checkpoints enabled for kube-scheduler and kube-controller-manager this test no longer makes sense") - - if !suite.Capabilities().SupportsRecover { - suite.T().Skip("cluster doesn't support recovery") - } - - if suite.Cluster == nil { - suite.T().Skip("without full cluster state recover test is not reliable (can't wait for cluster readiness)") - } - - for _, source := range []machineapi.RecoverRequest_Source{ - machineapi.RecoverRequest_APISERVER, - machineapi.RecoverRequest_ETCD, - } { - source := source - - suite.Run(source.String(), func() { - pods, err := suite.Clientset.CoreV1().Pods("kube-system").List(suite.ctx, metav1.ListOptions{ - LabelSelector: "k8s-app in (kube-scheduler,kube-controller-manager)", - }) - - suite.Assert().NoError(err) - - deletedPods := make(map[string]struct{}) - - var eg errgroup.Group - - for _, pod := range pods.Items { - pod := pod - - eg.Go(func() error { - suite.T().Logf("Deleting %s", pod.GetName()) - - deletedPods[pod.GetName()] = struct{}{} - - return suite.Clientset.CoreV1().Pods(pod.GetNamespace()).Delete(suite.ctx, pod.GetName(), metav1.DeleteOptions{}) - }) - } - - suite.Assert().NoError(eg.Wait()) - - suite.T().Logf("Waiting for the pods to be deleted") - - for len(pods.Items) > 0 { - pods, err = suite.Clientset.CoreV1().Pods("kube-system").List(suite.ctx, metav1.ListOptions{ - LabelSelector: "k8s-app in (kube-scheduler,kube-controller-manager)", - }) - - suite.Assert().NoError(err) - - for _, pod := range pods.Items { - if _, ok := deletedPods[pod.GetName()]; !ok { - suite.T().Logf("Deleting %s", pod.GetName()) - - deletedPods[pod.GetName()] = struct{}{} - - suite.Require().NoError(suite.Clientset.CoreV1().Pods(pod.GetNamespace()).Delete(suite.ctx, pod.GetName(), metav1.DeleteOptions{})) - } - } - } - - nodes := suite.DiscoverNodes().NodesByType(machine.TypeControlPlane) - suite.Require().NotEmpty(nodes) - - sort.Strings(nodes) - - node := nodes[0] - - suite.T().Log("Recovering control plane") - - ctx, ctxCancel := context.WithTimeout(suite.ctx, 5*time.Minute) - defer ctxCancel() - - nodeCtx := client.WithNodes(ctx, node) - - in := &machineapi.RecoverRequest{ - Source: source, - } - - _, err = suite.Client.MachineClient.Recover(nodeCtx, in) - - suite.Assert().NoError(err) - - // NB: using `ctx` here to have client talking to init node by default - suite.AssertClusterHealthy(ctx) - }) - } -} - -func init() { - allSuites = append(allSuites, new(RecoverSuite)) -} diff --git a/internal/integration/provision/upgrade.go b/internal/integration/provision/upgrade.go index 13ca2ee71..7ba1fbc1c 100644 --- a/internal/integration/provision/upgrade.go +++ b/internal/integration/provision/upgrade.go @@ -153,7 +153,7 @@ func upgradeSingeNodePreserve() upgradeSpec { // upgradeSingeNodeStage upgrade last release of Talos to the current version of Talos for single-node cluster with preserve and stage. func upgradeSingeNodeStage() upgradeSpec { return upgradeSpec{ - ShortName: fmt.Sprintf("preserve-stage-%s-%s", DefaultSettings.CurrentVersion, DefaultSettings.CurrentVersion), + ShortName: fmt.Sprintf("preserve-stage-%s-%s", stableRelease, DefaultSettings.CurrentVersion), SourceKernelPath: helpers.ArtifactPath(filepath.Join(trimVersion(stableRelease), constants.KernelAsset)), SourceInitramfsPath: helpers.ArtifactPath(filepath.Join(trimVersion(stableRelease), constants.InitramfsAsset)), diff --git a/internal/pkg/etcd/certs.go b/internal/pkg/etcd/certs.go new file mode 100644 index 000000000..5d0e2eee5 --- /dev/null +++ b/internal/pkg/etcd/certs.go @@ -0,0 +1,60 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package etcd + +import ( + "fmt" + stdlibnet "net" + "os" + "time" + + "github.com/talos-systems/crypto/x509" + "github.com/talos-systems/net" +) + +// GeneratePeerCert generates etcd peer certificate and key from etcd CA. +func GeneratePeerCert(etcdCA *x509.PEMEncodedCertificateAndKey) (*x509.PEMEncodedCertificateAndKey, error) { + ips, err := net.IPAddrs() + if err != nil { + return nil, fmt.Errorf("failed to discover IP addresses: %w", err) + } + + ips = append(ips, stdlibnet.ParseIP("127.0.0.1")) + if net.IsIPv6(ips...) { + ips = append(ips, stdlibnet.ParseIP("::1")) + } + + hostname, err := os.Hostname() + if err != nil { + return nil, fmt.Errorf("failed to get hostname: %w", err) + } + + dnsNames, err := net.DNSNames() + if err != nil { + return nil, fmt.Errorf("failed to get host DNS names: %w", err) + } + + dnsNames = append(dnsNames, "localhost") + + opts := []x509.Option{ + x509.CommonName(hostname), + x509.DNSNames(dnsNames), + x509.RSA(true), + x509.IPAddresses(ips), + x509.NotAfter(time.Now().Add(87600 * time.Hour)), + } + + ca, err := x509.NewCertificateAuthorityFromCertificateAndKey(etcdCA, opts...) + if err != nil { + return nil, fmt.Errorf("failed loading CA from config: %w", err) + } + + keyPair, err := x509.NewKeyPair(ca, opts...) + if err != nil { + return nil, fmt.Errorf("failed generating peer key pair: %w", err) + } + + return x509.NewCertificateAndKeyFromKeyPair(keyPair), nil +} diff --git a/internal/pkg/etcd/etcd.go b/internal/pkg/etcd/etcd.go index 0986f93a3..cba8b9153 100644 --- a/internal/pkg/etcd/etcd.go +++ b/internal/pkg/etcd/etcd.go @@ -36,7 +36,7 @@ type Client struct { } // NewClient initializes and returns an etcd client configured to talk to -// a local endpoint. +// a list of endpoints. func NewClient(endpoints []string) (client *Client, err error) { tlsInfo := transport.TLSInfo{ CertFile: constants.KubernetesEtcdPeerCert, @@ -62,6 +62,11 @@ func NewClient(endpoints []string) (client *Client, err error) { return &Client{Client: c}, nil } +// NewLocalClient initializes and returns etcd client configured to talk to localhost endpoint. +func NewLocalClient() (client *Client, err error) { + return NewClient([]string{"127.0.0.1:2379"}) +} + // NewClientFromControlPlaneIPs initializes and returns an etcd client // configured to talk to all members. func NewClientFromControlPlaneIPs(ctx context.Context, creds *x509.PEMEncodedCertificateAndKey, endpoint *url.URL) (client *Client, err error) { diff --git a/pkg/cluster/apply-config.go b/pkg/cluster/apply-config.go index f7ee6c3d6..412d0df7b 100644 --- a/pkg/cluster/apply-config.go +++ b/pkg/cluster/apply-config.go @@ -24,7 +24,7 @@ type ApplyConfigClient struct { } // ApplyConfig on the node via the API using insecure mode. -func (s *APIBoostrapper) ApplyConfig(ctx context.Context, nodes []provision.NodeRequest, out io.Writer) error { +func (s *APIBootstrapper) ApplyConfig(ctx context.Context, nodes []provision.NodeRequest, out io.Writer) error { for _, node := range nodes { n := node diff --git a/pkg/cluster/bootstrap.go b/pkg/cluster/bootstrap.go index d9983e25d..2f465d3de 100644 --- a/pkg/cluster/bootstrap.go +++ b/pkg/cluster/bootstrap.go @@ -19,8 +19,8 @@ import ( "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" ) -// APIBoostrapper bootstraps cluster via Talos API. -type APIBoostrapper struct { +// APIBootstrapper bootstraps cluster via Talos API. +type APIBootstrapper struct { ClientProvider Info } @@ -28,7 +28,7 @@ type APIBoostrapper struct { // Bootstrap the cluster via the API. // // Bootstrap implements Bootstrapper interface. -func (s *APIBoostrapper) Bootstrap(ctx context.Context, out io.Writer) error { +func (s *APIBootstrapper) Bootstrap(ctx context.Context, out io.Writer) error { cli, err := s.Client() if err != nil { return err diff --git a/pkg/cluster/check/kubernetes.go b/pkg/cluster/check/kubernetes.go index a0364bbad..2fe71cdf0 100644 --- a/pkg/cluster/check/kubernetes.go +++ b/pkg/cluster/check/kubernetes.go @@ -98,6 +98,7 @@ func K8sFullControlPlaneAssertion(ctx context.Context, cluster ClusterInfo) erro // ensure that all control plane nodes have been labeled with the master // label. + // daemonset check only there for pre-0.9 clusters with self-hosted control plane daemonsets, err := clientset.AppsV1().DaemonSets("kube-system").List(ctx, metav1.ListOptions{ LabelSelector: "k8s-app in (kube-apiserver,kube-scheduler,kube-controller-manager)", }) @@ -117,13 +118,15 @@ func K8sFullControlPlaneAssertion(ctx context.Context, cluster ClusterInfo) erro if ds.Status.NumberReady != ds.Status.DesiredNumberScheduled { return fmt.Errorf("expected number ready for %s to be %d, got %d", ds.GetName(), ds.Status.DesiredNumberScheduled, ds.Status.NumberReady) } + } + for _, k8sApp := range []string{"kube-apiserver", "kube-scheduler", "kube-controller-manager"} { // list pods to verify that daemonset status is updated properly pods, err := clientset.CoreV1().Pods("kube-system").List(ctx, metav1.ListOptions{ - LabelSelector: fmt.Sprintf("k8s-app = %s", ds.Labels["k8s-app"]), + LabelSelector: fmt.Sprintf("k8s-app = %s", k8sApp), }) if err != nil { - return fmt.Errorf("error listing pods for daemonset %s: %w", ds.GetName(), err) + return fmt.Errorf("error listing pods for app %s: %w", k8sApp, err) } // filter out pod checkpoints @@ -138,8 +141,8 @@ func K8sFullControlPlaneAssertion(ctx context.Context, cluster ClusterInfo) erro pods.Items = pods.Items[:n] - if int32(len(pods.Items)) != ds.Status.DesiredNumberScheduled { - return fmt.Errorf("expected number of pods for %s to be %d, got %d", ds.GetName(), ds.Status.DesiredNumberScheduled, len(pods.Items)) + if len(pods.Items) != len(actualNodes) { + return fmt.Errorf("expected number of pods for %s to be %d, got %d", k8sApp, len(actualNodes), len(pods.Items)) } var notReadyPods []string @@ -157,7 +160,7 @@ func K8sFullControlPlaneAssertion(ctx context.Context, cluster ClusterInfo) erro } if len(notReadyPods) > 0 { - return fmt.Errorf("some pods are not ready for %s: %v", ds.GetName(), notReadyPods) + return fmt.Errorf("some pods are not ready for %s: %v", k8sApp, notReadyPods) } } diff --git a/internal/app/bootkube/images/images.go b/pkg/images/list.go similarity index 60% rename from internal/app/bootkube/images/images.go rename to pkg/images/list.go index 703cb2378..8891bc43a 100644 --- a/internal/app/bootkube/images/images.go +++ b/pkg/images/list.go @@ -8,33 +8,47 @@ import ( "fmt" "runtime" - "github.com/talos-systems/bootkube-plugin/pkg/asset" + criconfig "github.com/containerd/cri/pkg/config" "github.com/talos-systems/talos/pkg/machinery/config" "github.com/talos-systems/talos/pkg/version" ) -// List returns a list of images used. -func List(config config.Provider) asset.ImageVersions { - images := asset.DefaultImages +// Versions holds all the images (and their versions) that are used in Talos. +type Versions struct { + Etcd string + Flannel string + FlannelCNI string + CoreDNS string - // Override all kube-related images with default val or specified image locations + Kubelet string + KubeAPIServer string + KubeControllerManager string + KubeProxy string + KubeScheduler string + + Installer string + + Pause string +} + +// List returns default image versions. +func List(config config.Provider) Versions { + var images Versions + + images.Etcd = config.Cluster().Etcd().Image() + images.CoreDNS = config.Cluster().CoreDNS().Image() images.Flannel = fmt.Sprintf("quay.io/coreos/flannel:v0.12.0-%s", runtime.GOARCH) images.FlannelCNI = fmt.Sprintf("ghcr.io/talos-systems/install-cni:%s", version.ExtrasVersion) - images.PodCheckpointer = fmt.Sprintf("ghcr.io/talos-systems/pod-checkpointer:%s", version.ExtrasVersion) images.Kubelet = config.Machine().Kubelet().Image() images.KubeAPIServer = config.Cluster().APIServer().Image() images.KubeControllerManager = config.Cluster().ControllerManager().Image() images.KubeProxy = config.Cluster().Proxy().Image() images.KubeScheduler = config.Cluster().Scheduler().Image() - images.Etcd = config.Cluster().Etcd().Image() - // Allow for overriding by users via config data - images.CoreDNS = config.Cluster().CoreDNS().Image() + images.Installer = DefaultInstallerImage - if config.Cluster().PodCheckpointer().Image() != "" { - images.PodCheckpointer = config.Cluster().PodCheckpointer().Image() - } + images.Pause = criconfig.DefaultConfig().SandboxImage return images } diff --git a/pkg/kubernetes/kubelet/kubelet.go b/pkg/kubernetes/kubelet/kubelet.go new file mode 100644 index 000000000..a6c86b152 --- /dev/null +++ b/pkg/kubernetes/kubelet/kubelet.go @@ -0,0 +1,93 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package kubelet provides minimal client for the kubelet API. +package kubelet + +import ( + "context" + "crypto/tls" + stdx509 "crypto/x509" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + "path/filepath" + + v1 "k8s.io/api/core/v1" + + "github.com/talos-systems/talos/pkg/machinery/constants" +) + +// Client is a kubelet API client. +// +// Client can only talk to the local kubelet on the same node. +type Client struct { + httpClient *http.Client + hostname string +} + +// NewClient creates new kubelet API client. +func NewClient(clientCert tls.Certificate) (*Client, error) { + rootCAs := stdx509.NewCertPool() + + kubeletCert, err := ioutil.ReadFile(filepath.Join(constants.KubeletPKIDir, "kubelet.crt")) + if err != nil { + return nil, fmt.Errorf("error reading kubelet certificate: %w", err) + } + + rootCAs.AppendCertsFromPEM(kubeletCert) + + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{clientCert}, + RootCAs: rootCAs, + } + + client := &Client{ + httpClient: &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: tlsConfig, + }, + }, + } + + client.hostname, err = os.Hostname() + if err != nil { + return nil, err + } + + return client, nil +} + +// Pods returns list of pods running on the kubelet. +func (c *Client) Pods(ctx context.Context) (*v1.PodList, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://%s:%d/pods", c.hostname, constants.KubeletPort), nil) + if err != nil { + return nil, fmt.Errorf("error building request: %w", err) + } + + resp, err := c.httpClient.Do(req) + if err != nil { + return nil, fmt.Errorf("error performing request: %w", err) + } + + defer func() { + io.Copy(ioutil.Discard, resp.Body) //nolint: errcheck + resp.Body.Close() //nolint: errcheck + }() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status response %d", resp.StatusCode) + } + + var podList v1.PodList + + if err = json.NewDecoder(resp.Body).Decode(&podList); err != nil { + return nil, fmt.Errorf("error decoding JSON response: %w", err) + } + + return &podList, nil +} diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index ebea56e25..e7ee54dd2 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -386,6 +386,12 @@ func (h *Client) Drain(node string) error { return } + + if ref.Kind == "Node" { + log.Printf("skipping StaticPod pod %s\n", p.GetName()) + + return + } } if err := h.evict(p, int64(60)); err != nil { diff --git a/pkg/machinery/api/inspect/inspect.pb.go b/pkg/machinery/api/inspect/inspect.pb.go new file mode 100644 index 000000000..ee3be9318 --- /dev/null +++ b/pkg/machinery/api/inspect/inspect.pb.go @@ -0,0 +1,508 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.14.0 +// source: inspect/inspect.proto + +package inspect + +import ( + context "context" + reflect "reflect" + sync "sync" + + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + + common "github.com/talos-systems/talos/pkg/machinery/api/common" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type DependencyEdgeType int32 + +const ( + DependencyEdgeType_MANAGES DependencyEdgeType = 0 + DependencyEdgeType_STRONG DependencyEdgeType = 1 + DependencyEdgeType_WEAK DependencyEdgeType = 2 +) + +// Enum value maps for DependencyEdgeType. +var ( + DependencyEdgeType_name = map[int32]string{ + 0: "MANAGES", + 1: "STRONG", + 2: "WEAK", + } + DependencyEdgeType_value = map[string]int32{ + "MANAGES": 0, + "STRONG": 1, + "WEAK": 2, + } +) + +func (x DependencyEdgeType) Enum() *DependencyEdgeType { + p := new(DependencyEdgeType) + *p = x + return p +} + +func (x DependencyEdgeType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (DependencyEdgeType) Descriptor() protoreflect.EnumDescriptor { + return file_inspect_inspect_proto_enumTypes[0].Descriptor() +} + +func (DependencyEdgeType) Type() protoreflect.EnumType { + return &file_inspect_inspect_proto_enumTypes[0] +} + +func (x DependencyEdgeType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use DependencyEdgeType.Descriptor instead. +func (DependencyEdgeType) EnumDescriptor() ([]byte, []int) { + return file_inspect_inspect_proto_rawDescGZIP(), []int{0} +} + +// The ControllerRuntimeDependency message contains the graph of controller-resource dependencies. +type ControllerRuntimeDependency struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Metadata *common.Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + Edges []*ControllerDependencyEdge `protobuf:"bytes,2,rep,name=edges,proto3" json:"edges,omitempty"` +} + +func (x *ControllerRuntimeDependency) Reset() { + *x = ControllerRuntimeDependency{} + if protoimpl.UnsafeEnabled { + mi := &file_inspect_inspect_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ControllerRuntimeDependency) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ControllerRuntimeDependency) ProtoMessage() {} + +func (x *ControllerRuntimeDependency) ProtoReflect() protoreflect.Message { + mi := &file_inspect_inspect_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ControllerRuntimeDependency.ProtoReflect.Descriptor instead. +func (*ControllerRuntimeDependency) Descriptor() ([]byte, []int) { + return file_inspect_inspect_proto_rawDescGZIP(), []int{0} +} + +func (x *ControllerRuntimeDependency) GetMetadata() *common.Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *ControllerRuntimeDependency) GetEdges() []*ControllerDependencyEdge { + if x != nil { + return x.Edges + } + return nil +} + +type ControllerRuntimeDependenciesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Messages []*ControllerRuntimeDependency `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` +} + +func (x *ControllerRuntimeDependenciesResponse) Reset() { + *x = ControllerRuntimeDependenciesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_inspect_inspect_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ControllerRuntimeDependenciesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ControllerRuntimeDependenciesResponse) ProtoMessage() {} + +func (x *ControllerRuntimeDependenciesResponse) ProtoReflect() protoreflect.Message { + mi := &file_inspect_inspect_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ControllerRuntimeDependenciesResponse.ProtoReflect.Descriptor instead. +func (*ControllerRuntimeDependenciesResponse) Descriptor() ([]byte, []int) { + return file_inspect_inspect_proto_rawDescGZIP(), []int{1} +} + +func (x *ControllerRuntimeDependenciesResponse) GetMessages() []*ControllerRuntimeDependency { + if x != nil { + return x.Messages + } + return nil +} + +type ControllerDependencyEdge struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ControllerName string `protobuf:"bytes,1,opt,name=controller_name,json=controllerName,proto3" json:"controller_name,omitempty"` + EdgeType DependencyEdgeType `protobuf:"varint,2,opt,name=edge_type,json=edgeType,proto3,enum=inspect.DependencyEdgeType" json:"edge_type,omitempty"` + ResourceNamespace string `protobuf:"bytes,3,opt,name=resource_namespace,json=resourceNamespace,proto3" json:"resource_namespace,omitempty"` + ResourceType string `protobuf:"bytes,4,opt,name=resource_type,json=resourceType,proto3" json:"resource_type,omitempty"` + ResourceId string `protobuf:"bytes,5,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` +} + +func (x *ControllerDependencyEdge) Reset() { + *x = ControllerDependencyEdge{} + if protoimpl.UnsafeEnabled { + mi := &file_inspect_inspect_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ControllerDependencyEdge) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ControllerDependencyEdge) ProtoMessage() {} + +func (x *ControllerDependencyEdge) ProtoReflect() protoreflect.Message { + mi := &file_inspect_inspect_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ControllerDependencyEdge.ProtoReflect.Descriptor instead. +func (*ControllerDependencyEdge) Descriptor() ([]byte, []int) { + return file_inspect_inspect_proto_rawDescGZIP(), []int{2} +} + +func (x *ControllerDependencyEdge) GetControllerName() string { + if x != nil { + return x.ControllerName + } + return "" +} + +func (x *ControllerDependencyEdge) GetEdgeType() DependencyEdgeType { + if x != nil { + return x.EdgeType + } + return DependencyEdgeType_MANAGES +} + +func (x *ControllerDependencyEdge) GetResourceNamespace() string { + if x != nil { + return x.ResourceNamespace + } + return "" +} + +func (x *ControllerDependencyEdge) GetResourceType() string { + if x != nil { + return x.ResourceType + } + return "" +} + +func (x *ControllerDependencyEdge) GetResourceId() string { + if x != nil { + return x.ResourceId + } + return "" +} + +var File_inspect_inspect_proto protoreflect.FileDescriptor + +var file_inspect_inspect_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2f, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, + 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, + 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0x84, 0x01, 0x0a, 0x1b, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, + 0x63, 0x79, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x37, 0x0a, 0x05, 0x65, 0x64, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x21, 0x2e, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x72, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x45, 0x64, + 0x67, 0x65, 0x52, 0x05, 0x65, 0x64, 0x67, 0x65, 0x73, 0x22, 0x69, 0x0a, 0x25, 0x43, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x44, 0x65, + 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x40, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2e, 0x43, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x22, 0xf2, 0x01, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x45, 0x64, 0x67, + 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x65, 0x64, + 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, + 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, + 0x63, 0x79, 0x45, 0x64, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x65, 0x64, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x2a, 0x37, 0x0a, 0x12, 0x44, 0x65, 0x70, + 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x45, 0x64, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x0b, 0x0a, 0x07, 0x4d, 0x41, 0x4e, 0x41, 0x47, 0x45, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, + 0x53, 0x54, 0x52, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x45, 0x41, 0x4b, + 0x10, 0x02, 0x32, 0x79, 0x0a, 0x0e, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x67, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, + 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x2e, 0x2e, + 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, + 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x59, 0x0a, + 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x2e, 0x61, 0x70, 0x69, + 0x42, 0x0a, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x41, 0x70, 0x69, 0x50, 0x01, 0x5a, 0x38, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, + 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, + 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x69, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_inspect_inspect_proto_rawDescOnce sync.Once + file_inspect_inspect_proto_rawDescData = file_inspect_inspect_proto_rawDesc +) + +func file_inspect_inspect_proto_rawDescGZIP() []byte { + file_inspect_inspect_proto_rawDescOnce.Do(func() { + file_inspect_inspect_proto_rawDescData = protoimpl.X.CompressGZIP(file_inspect_inspect_proto_rawDescData) + }) + return file_inspect_inspect_proto_rawDescData +} + +var ( + file_inspect_inspect_proto_enumTypes = make([]protoimpl.EnumInfo, 1) + file_inspect_inspect_proto_msgTypes = make([]protoimpl.MessageInfo, 3) + file_inspect_inspect_proto_goTypes = []interface{}{ + (DependencyEdgeType)(0), // 0: inspect.DependencyEdgeType + (*ControllerRuntimeDependency)(nil), // 1: inspect.ControllerRuntimeDependency + (*ControllerRuntimeDependenciesResponse)(nil), // 2: inspect.ControllerRuntimeDependenciesResponse + (*ControllerDependencyEdge)(nil), // 3: inspect.ControllerDependencyEdge + (*common.Metadata)(nil), // 4: common.Metadata + (*emptypb.Empty)(nil), // 5: google.protobuf.Empty + } +) + +var file_inspect_inspect_proto_depIdxs = []int32{ + 4, // 0: inspect.ControllerRuntimeDependency.metadata:type_name -> common.Metadata + 3, // 1: inspect.ControllerRuntimeDependency.edges:type_name -> inspect.ControllerDependencyEdge + 1, // 2: inspect.ControllerRuntimeDependenciesResponse.messages:type_name -> inspect.ControllerRuntimeDependency + 0, // 3: inspect.ControllerDependencyEdge.edge_type:type_name -> inspect.DependencyEdgeType + 5, // 4: inspect.InspectService.ControllerRuntimeDependencies:input_type -> google.protobuf.Empty + 2, // 5: inspect.InspectService.ControllerRuntimeDependencies:output_type -> inspect.ControllerRuntimeDependenciesResponse + 5, // [5:6] is the sub-list for method output_type + 4, // [4:5] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_inspect_inspect_proto_init() } +func file_inspect_inspect_proto_init() { + if File_inspect_inspect_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_inspect_inspect_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ControllerRuntimeDependency); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_inspect_inspect_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ControllerRuntimeDependenciesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_inspect_inspect_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ControllerDependencyEdge); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_inspect_inspect_proto_rawDesc, + NumEnums: 1, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_inspect_inspect_proto_goTypes, + DependencyIndexes: file_inspect_inspect_proto_depIdxs, + EnumInfos: file_inspect_inspect_proto_enumTypes, + MessageInfos: file_inspect_inspect_proto_msgTypes, + }.Build() + File_inspect_inspect_proto = out.File + file_inspect_inspect_proto_rawDesc = nil + file_inspect_inspect_proto_goTypes = nil + file_inspect_inspect_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ context.Context + _ grpc.ClientConnInterface +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// InspectServiceClient is the client API for InspectService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type InspectServiceClient interface { + ControllerRuntimeDependencies(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ControllerRuntimeDependenciesResponse, error) +} + +type inspectServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewInspectServiceClient(cc grpc.ClientConnInterface) InspectServiceClient { + return &inspectServiceClient{cc} +} + +func (c *inspectServiceClient) ControllerRuntimeDependencies(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ControllerRuntimeDependenciesResponse, error) { + out := new(ControllerRuntimeDependenciesResponse) + err := c.cc.Invoke(ctx, "/inspect.InspectService/ControllerRuntimeDependencies", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// InspectServiceServer is the server API for InspectService service. +type InspectServiceServer interface { + ControllerRuntimeDependencies(context.Context, *emptypb.Empty) (*ControllerRuntimeDependenciesResponse, error) +} + +// UnimplementedInspectServiceServer can be embedded to have forward compatible implementations. +type UnimplementedInspectServiceServer struct { +} + +func (*UnimplementedInspectServiceServer) ControllerRuntimeDependencies(context.Context, *emptypb.Empty) (*ControllerRuntimeDependenciesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ControllerRuntimeDependencies not implemented") +} + +func RegisterInspectServiceServer(s *grpc.Server, srv InspectServiceServer) { + s.RegisterService(&_InspectService_serviceDesc, srv) +} + +func _InspectService_ControllerRuntimeDependencies_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InspectServiceServer).ControllerRuntimeDependencies(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/inspect.InspectService/ControllerRuntimeDependencies", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InspectServiceServer).ControllerRuntimeDependencies(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +var _InspectService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "inspect.InspectService", + HandlerType: (*InspectServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ControllerRuntimeDependencies", + Handler: _InspectService_ControllerRuntimeDependencies_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "inspect/inspect.proto", +} diff --git a/pkg/machinery/api/machine/machine.pb.go b/pkg/machinery/api/machine/machine.pb.go index 0d0f740bd..3f5ae8d71 100644 --- a/pkg/machinery/api/machine/machine.pb.go +++ b/pkg/machinery/api/machine/machine.pb.go @@ -956,6 +956,7 @@ type ServiceStateEvent struct { Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` Action ServiceStateEvent_Action `protobuf:"varint,2,opt,name=action,proto3,enum=machine.ServiceStateEvent_Action" json:"action,omitempty"` Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` + Health *ServiceHealth `protobuf:"bytes,4,opt,name=health,proto3" json:"health,omitempty"` } func (x *ServiceStateEvent) Reset() { @@ -1011,6 +1012,13 @@ func (x *ServiceStateEvent) GetMessage() string { return "" } +func (x *ServiceStateEvent) GetHealth() *ServiceHealth { + if x != nil { + return x.Health + } + return nil +} + type EventsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -8155,7 +8163,7 @@ var file_machine_machine_proto_rawDesc = []byte{ 0x74, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1d, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, 0x22, - 0xfb, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, + 0xab, 0x02, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x39, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, @@ -8163,7 +8171,10 @@ var file_machine_machine_proto_rawDesc = []byte{ 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0x77, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0f, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2e, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x06, 0x68, 0x65, + 0x61, 0x6c, 0x74, 0x68, 0x22, 0x77, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x52, 0x45, 0x50, 0x41, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x52, @@ -9376,180 +9387,181 @@ var file_machine_machine_proto_depIdxs = []int32{ 1, // 8: machine.PhaseEvent.action:type_name -> machine.PhaseEvent.Action 2, // 9: machine.TaskEvent.action:type_name -> machine.TaskEvent.Action 3, // 10: machine.ServiceStateEvent.action:type_name -> machine.ServiceStateEvent.Action - 126, // 11: machine.Event.metadata:type_name -> common.Metadata - 128, // 12: machine.Event.data:type_name -> google.protobuf.Any - 21, // 13: machine.ResetRequest.system_partitions_to_wipe:type_name -> machine.ResetPartitionSpec - 126, // 14: machine.Reset.metadata:type_name -> common.Metadata - 23, // 15: machine.ResetResponse.messages:type_name -> machine.Reset - 4, // 16: machine.RecoverRequest.source:type_name -> machine.RecoverRequest.Source - 126, // 17: machine.Recover.metadata:type_name -> common.Metadata - 26, // 18: machine.RecoverResponse.messages:type_name -> machine.Recover - 126, // 19: machine.Shutdown.metadata:type_name -> common.Metadata - 28, // 20: machine.ShutdownResponse.messages:type_name -> machine.Shutdown - 126, // 21: machine.Upgrade.metadata:type_name -> common.Metadata - 31, // 22: machine.UpgradeResponse.messages:type_name -> machine.Upgrade - 126, // 23: machine.ServiceList.metadata:type_name -> common.Metadata - 35, // 24: machine.ServiceList.services:type_name -> machine.ServiceInfo - 33, // 25: machine.ServiceListResponse.messages:type_name -> machine.ServiceList - 36, // 26: machine.ServiceInfo.events:type_name -> machine.ServiceEvents - 38, // 27: machine.ServiceInfo.health:type_name -> machine.ServiceHealth - 37, // 28: machine.ServiceEvents.events:type_name -> machine.ServiceEvent - 129, // 29: machine.ServiceEvent.ts:type_name -> google.protobuf.Timestamp - 129, // 30: machine.ServiceHealth.last_change:type_name -> google.protobuf.Timestamp - 126, // 31: machine.ServiceStart.metadata:type_name -> common.Metadata - 40, // 32: machine.ServiceStartResponse.messages:type_name -> machine.ServiceStart - 126, // 33: machine.ServiceStop.metadata:type_name -> common.Metadata - 43, // 34: machine.ServiceStopResponse.messages:type_name -> machine.ServiceStop - 126, // 35: machine.ServiceRestart.metadata:type_name -> common.Metadata - 46, // 36: machine.ServiceRestartResponse.messages:type_name -> machine.ServiceRestart - 5, // 37: machine.ListRequest.types:type_name -> machine.ListRequest.Type - 126, // 38: machine.FileInfo.metadata:type_name -> common.Metadata - 126, // 39: machine.DiskUsageInfo.metadata:type_name -> common.Metadata - 126, // 40: machine.Mounts.metadata:type_name -> common.Metadata - 59, // 41: machine.Mounts.stats:type_name -> machine.MountStat - 57, // 42: machine.MountsResponse.messages:type_name -> machine.Mounts - 126, // 43: machine.Version.metadata:type_name -> common.Metadata - 62, // 44: machine.Version.version:type_name -> machine.VersionInfo - 63, // 45: machine.Version.platform:type_name -> machine.PlatformInfo - 60, // 46: machine.VersionResponse.messages:type_name -> machine.Version - 130, // 47: machine.LogsRequest.driver:type_name -> common.ContainerDriver - 126, // 48: machine.Rollback.metadata:type_name -> common.Metadata - 67, // 49: machine.RollbackResponse.messages:type_name -> machine.Rollback - 130, // 50: machine.ContainersRequest.driver:type_name -> common.ContainerDriver - 126, // 51: machine.Container.metadata:type_name -> common.Metadata - 70, // 52: machine.Container.containers:type_name -> machine.ContainerInfo - 71, // 53: machine.ContainersResponse.messages:type_name -> machine.Container - 76, // 54: machine.ProcessesResponse.messages:type_name -> machine.Process - 126, // 55: machine.Process.metadata:type_name -> common.Metadata - 77, // 56: machine.Process.processes:type_name -> machine.ProcessInfo - 130, // 57: machine.RestartRequest.driver:type_name -> common.ContainerDriver - 126, // 58: machine.Restart.metadata:type_name -> common.Metadata - 79, // 59: machine.RestartResponse.messages:type_name -> machine.Restart - 130, // 60: machine.StatsRequest.driver:type_name -> common.ContainerDriver - 126, // 61: machine.Stats.metadata:type_name -> common.Metadata - 84, // 62: machine.Stats.stats:type_name -> machine.Stat - 82, // 63: machine.StatsResponse.messages:type_name -> machine.Stats - 126, // 64: machine.Memory.metadata:type_name -> common.Metadata - 87, // 65: machine.Memory.meminfo:type_name -> machine.MemInfo - 85, // 66: machine.MemoryResponse.messages:type_name -> machine.Memory - 89, // 67: machine.HostnameResponse.messages:type_name -> machine.Hostname - 126, // 68: machine.Hostname.metadata:type_name -> common.Metadata - 91, // 69: machine.LoadAvgResponse.messages:type_name -> machine.LoadAvg - 126, // 70: machine.LoadAvg.metadata:type_name -> common.Metadata - 93, // 71: machine.SystemStatResponse.messages:type_name -> machine.SystemStat - 126, // 72: machine.SystemStat.metadata:type_name -> common.Metadata - 94, // 73: machine.SystemStat.cpu_total:type_name -> machine.CPUStat - 94, // 74: machine.SystemStat.cpu:type_name -> machine.CPUStat - 95, // 75: machine.SystemStat.soft_irq:type_name -> machine.SoftIRQStat - 97, // 76: machine.CPUInfoResponse.messages:type_name -> machine.CPUsInfo - 126, // 77: machine.CPUsInfo.metadata:type_name -> common.Metadata - 98, // 78: machine.CPUsInfo.cpu_info:type_name -> machine.CPUInfo - 100, // 79: machine.NetworkDeviceStatsResponse.messages:type_name -> machine.NetworkDeviceStats - 126, // 80: machine.NetworkDeviceStats.metadata:type_name -> common.Metadata - 101, // 81: machine.NetworkDeviceStats.total:type_name -> machine.NetDev - 101, // 82: machine.NetworkDeviceStats.devices:type_name -> machine.NetDev - 103, // 83: machine.DiskStatsResponse.messages:type_name -> machine.DiskStats - 126, // 84: machine.DiskStats.metadata:type_name -> common.Metadata - 104, // 85: machine.DiskStats.total:type_name -> machine.DiskStat - 104, // 86: machine.DiskStats.devices:type_name -> machine.DiskStat - 126, // 87: machine.EtcdLeaveCluster.metadata:type_name -> common.Metadata - 106, // 88: machine.EtcdLeaveClusterResponse.messages:type_name -> machine.EtcdLeaveCluster - 126, // 89: machine.EtcdForfeitLeadership.metadata:type_name -> common.Metadata - 109, // 90: machine.EtcdForfeitLeadershipResponse.messages:type_name -> machine.EtcdForfeitLeadership - 126, // 91: machine.EtcdMemberList.metadata:type_name -> common.Metadata - 112, // 92: machine.EtcdMemberListResponse.messages:type_name -> machine.EtcdMemberList - 115, // 93: machine.NetworkDeviceConfig.dhcp_options:type_name -> machine.DHCPOptionsConfig - 114, // 94: machine.NetworkDeviceConfig.routes:type_name -> machine.RouteConfig - 116, // 95: machine.NetworkConfig.interfaces:type_name -> machine.NetworkDeviceConfig - 6, // 96: machine.MachineConfig.type:type_name -> machine.MachineConfig.MachineType - 118, // 97: machine.MachineConfig.install_config:type_name -> machine.InstallConfig - 117, // 98: machine.MachineConfig.network_config:type_name -> machine.NetworkConfig - 121, // 99: machine.ClusterNetworkConfig.cni_config:type_name -> machine.CNIConfig - 120, // 100: machine.ClusterConfig.control_plane:type_name -> machine.ControlPlaneConfig - 122, // 101: machine.ClusterConfig.cluster_network:type_name -> machine.ClusterNetworkConfig - 123, // 102: machine.GenerateConfigurationRequest.cluster_config:type_name -> machine.ClusterConfig - 119, // 103: machine.GenerateConfigurationRequest.machine_config:type_name -> machine.MachineConfig - 129, // 104: machine.GenerateConfigurationRequest.override_time:type_name -> google.protobuf.Timestamp - 126, // 105: machine.GenerateConfigurationResponse.metadata:type_name -> common.Metadata - 7, // 106: machine.MachineService.ApplyConfiguration:input_type -> machine.ApplyConfigurationRequest - 12, // 107: machine.MachineService.Bootstrap:input_type -> machine.BootstrapRequest - 69, // 108: machine.MachineService.Containers:input_type -> machine.ContainersRequest - 52, // 109: machine.MachineService.Copy:input_type -> machine.CopyRequest - 131, // 110: machine.MachineService.CPUInfo:input_type -> google.protobuf.Empty - 131, // 111: machine.MachineService.DiskStats:input_type -> google.protobuf.Empty - 73, // 112: machine.MachineService.Dmesg:input_type -> machine.DmesgRequest - 19, // 113: machine.MachineService.Events:input_type -> machine.EventsRequest - 111, // 114: machine.MachineService.EtcdMemberList:input_type -> machine.EtcdMemberListRequest - 105, // 115: machine.MachineService.EtcdLeaveCluster:input_type -> machine.EtcdLeaveClusterRequest - 108, // 116: machine.MachineService.EtcdForfeitLeadership:input_type -> machine.EtcdForfeitLeadershipRequest - 124, // 117: machine.MachineService.GenerateConfiguration:input_type -> machine.GenerateConfigurationRequest - 131, // 118: machine.MachineService.Hostname:input_type -> google.protobuf.Empty - 131, // 119: machine.MachineService.Kubeconfig:input_type -> google.protobuf.Empty - 53, // 120: machine.MachineService.List:input_type -> machine.ListRequest - 54, // 121: machine.MachineService.DiskUsage:input_type -> machine.DiskUsageRequest - 131, // 122: machine.MachineService.LoadAvg:input_type -> google.protobuf.Empty - 64, // 123: machine.MachineService.Logs:input_type -> machine.LogsRequest - 131, // 124: machine.MachineService.Memory:input_type -> google.protobuf.Empty - 131, // 125: machine.MachineService.Mounts:input_type -> google.protobuf.Empty - 131, // 126: machine.MachineService.NetworkDeviceStats:input_type -> google.protobuf.Empty - 131, // 127: machine.MachineService.Processes:input_type -> google.protobuf.Empty - 65, // 128: machine.MachineService.Read:input_type -> machine.ReadRequest - 131, // 129: machine.MachineService.Reboot:input_type -> google.protobuf.Empty - 78, // 130: machine.MachineService.Restart:input_type -> machine.RestartRequest - 66, // 131: machine.MachineService.Rollback:input_type -> machine.RollbackRequest - 22, // 132: machine.MachineService.Reset:input_type -> machine.ResetRequest - 25, // 133: machine.MachineService.Recover:input_type -> machine.RecoverRequest - 131, // 134: machine.MachineService.ServiceList:input_type -> google.protobuf.Empty - 45, // 135: machine.MachineService.ServiceRestart:input_type -> machine.ServiceRestartRequest - 39, // 136: machine.MachineService.ServiceStart:input_type -> machine.ServiceStartRequest - 42, // 137: machine.MachineService.ServiceStop:input_type -> machine.ServiceStopRequest - 131, // 138: machine.MachineService.Shutdown:input_type -> google.protobuf.Empty - 81, // 139: machine.MachineService.Stats:input_type -> machine.StatsRequest - 131, // 140: machine.MachineService.SystemStat:input_type -> google.protobuf.Empty - 30, // 141: machine.MachineService.Upgrade:input_type -> machine.UpgradeRequest - 131, // 142: machine.MachineService.Version:input_type -> google.protobuf.Empty - 9, // 143: machine.MachineService.ApplyConfiguration:output_type -> machine.ApplyConfigurationResponse - 14, // 144: machine.MachineService.Bootstrap:output_type -> machine.BootstrapResponse - 72, // 145: machine.MachineService.Containers:output_type -> machine.ContainersResponse - 132, // 146: machine.MachineService.Copy:output_type -> common.Data - 96, // 147: machine.MachineService.CPUInfo:output_type -> machine.CPUInfoResponse - 102, // 148: machine.MachineService.DiskStats:output_type -> machine.DiskStatsResponse - 132, // 149: machine.MachineService.Dmesg:output_type -> common.Data - 20, // 150: machine.MachineService.Events:output_type -> machine.Event - 113, // 151: machine.MachineService.EtcdMemberList:output_type -> machine.EtcdMemberListResponse - 107, // 152: machine.MachineService.EtcdLeaveCluster:output_type -> machine.EtcdLeaveClusterResponse - 110, // 153: machine.MachineService.EtcdForfeitLeadership:output_type -> machine.EtcdForfeitLeadershipResponse - 125, // 154: machine.MachineService.GenerateConfiguration:output_type -> machine.GenerateConfigurationResponse - 88, // 155: machine.MachineService.Hostname:output_type -> machine.HostnameResponse - 132, // 156: machine.MachineService.Kubeconfig:output_type -> common.Data - 55, // 157: machine.MachineService.List:output_type -> machine.FileInfo - 56, // 158: machine.MachineService.DiskUsage:output_type -> machine.DiskUsageInfo - 90, // 159: machine.MachineService.LoadAvg:output_type -> machine.LoadAvgResponse - 132, // 160: machine.MachineService.Logs:output_type -> common.Data - 86, // 161: machine.MachineService.Memory:output_type -> machine.MemoryResponse - 58, // 162: machine.MachineService.Mounts:output_type -> machine.MountsResponse - 99, // 163: machine.MachineService.NetworkDeviceStats:output_type -> machine.NetworkDeviceStatsResponse - 75, // 164: machine.MachineService.Processes:output_type -> machine.ProcessesResponse - 132, // 165: machine.MachineService.Read:output_type -> common.Data - 11, // 166: machine.MachineService.Reboot:output_type -> machine.RebootResponse - 80, // 167: machine.MachineService.Restart:output_type -> machine.RestartResponse - 68, // 168: machine.MachineService.Rollback:output_type -> machine.RollbackResponse - 24, // 169: machine.MachineService.Reset:output_type -> machine.ResetResponse - 27, // 170: machine.MachineService.Recover:output_type -> machine.RecoverResponse - 34, // 171: machine.MachineService.ServiceList:output_type -> machine.ServiceListResponse - 47, // 172: machine.MachineService.ServiceRestart:output_type -> machine.ServiceRestartResponse - 41, // 173: machine.MachineService.ServiceStart:output_type -> machine.ServiceStartResponse - 44, // 174: machine.MachineService.ServiceStop:output_type -> machine.ServiceStopResponse - 29, // 175: machine.MachineService.Shutdown:output_type -> machine.ShutdownResponse - 83, // 176: machine.MachineService.Stats:output_type -> machine.StatsResponse - 92, // 177: machine.MachineService.SystemStat:output_type -> machine.SystemStatResponse - 32, // 178: machine.MachineService.Upgrade:output_type -> machine.UpgradeResponse - 61, // 179: machine.MachineService.Version:output_type -> machine.VersionResponse - 143, // [143:180] is the sub-list for method output_type - 106, // [106:143] is the sub-list for method input_type - 106, // [106:106] is the sub-list for extension type_name - 106, // [106:106] is the sub-list for extension extendee - 0, // [0:106] is the sub-list for field type_name + 38, // 11: machine.ServiceStateEvent.health:type_name -> machine.ServiceHealth + 126, // 12: machine.Event.metadata:type_name -> common.Metadata + 128, // 13: machine.Event.data:type_name -> google.protobuf.Any + 21, // 14: machine.ResetRequest.system_partitions_to_wipe:type_name -> machine.ResetPartitionSpec + 126, // 15: machine.Reset.metadata:type_name -> common.Metadata + 23, // 16: machine.ResetResponse.messages:type_name -> machine.Reset + 4, // 17: machine.RecoverRequest.source:type_name -> machine.RecoverRequest.Source + 126, // 18: machine.Recover.metadata:type_name -> common.Metadata + 26, // 19: machine.RecoverResponse.messages:type_name -> machine.Recover + 126, // 20: machine.Shutdown.metadata:type_name -> common.Metadata + 28, // 21: machine.ShutdownResponse.messages:type_name -> machine.Shutdown + 126, // 22: machine.Upgrade.metadata:type_name -> common.Metadata + 31, // 23: machine.UpgradeResponse.messages:type_name -> machine.Upgrade + 126, // 24: machine.ServiceList.metadata:type_name -> common.Metadata + 35, // 25: machine.ServiceList.services:type_name -> machine.ServiceInfo + 33, // 26: machine.ServiceListResponse.messages:type_name -> machine.ServiceList + 36, // 27: machine.ServiceInfo.events:type_name -> machine.ServiceEvents + 38, // 28: machine.ServiceInfo.health:type_name -> machine.ServiceHealth + 37, // 29: machine.ServiceEvents.events:type_name -> machine.ServiceEvent + 129, // 30: machine.ServiceEvent.ts:type_name -> google.protobuf.Timestamp + 129, // 31: machine.ServiceHealth.last_change:type_name -> google.protobuf.Timestamp + 126, // 32: machine.ServiceStart.metadata:type_name -> common.Metadata + 40, // 33: machine.ServiceStartResponse.messages:type_name -> machine.ServiceStart + 126, // 34: machine.ServiceStop.metadata:type_name -> common.Metadata + 43, // 35: machine.ServiceStopResponse.messages:type_name -> machine.ServiceStop + 126, // 36: machine.ServiceRestart.metadata:type_name -> common.Metadata + 46, // 37: machine.ServiceRestartResponse.messages:type_name -> machine.ServiceRestart + 5, // 38: machine.ListRequest.types:type_name -> machine.ListRequest.Type + 126, // 39: machine.FileInfo.metadata:type_name -> common.Metadata + 126, // 40: machine.DiskUsageInfo.metadata:type_name -> common.Metadata + 126, // 41: machine.Mounts.metadata:type_name -> common.Metadata + 59, // 42: machine.Mounts.stats:type_name -> machine.MountStat + 57, // 43: machine.MountsResponse.messages:type_name -> machine.Mounts + 126, // 44: machine.Version.metadata:type_name -> common.Metadata + 62, // 45: machine.Version.version:type_name -> machine.VersionInfo + 63, // 46: machine.Version.platform:type_name -> machine.PlatformInfo + 60, // 47: machine.VersionResponse.messages:type_name -> machine.Version + 130, // 48: machine.LogsRequest.driver:type_name -> common.ContainerDriver + 126, // 49: machine.Rollback.metadata:type_name -> common.Metadata + 67, // 50: machine.RollbackResponse.messages:type_name -> machine.Rollback + 130, // 51: machine.ContainersRequest.driver:type_name -> common.ContainerDriver + 126, // 52: machine.Container.metadata:type_name -> common.Metadata + 70, // 53: machine.Container.containers:type_name -> machine.ContainerInfo + 71, // 54: machine.ContainersResponse.messages:type_name -> machine.Container + 76, // 55: machine.ProcessesResponse.messages:type_name -> machine.Process + 126, // 56: machine.Process.metadata:type_name -> common.Metadata + 77, // 57: machine.Process.processes:type_name -> machine.ProcessInfo + 130, // 58: machine.RestartRequest.driver:type_name -> common.ContainerDriver + 126, // 59: machine.Restart.metadata:type_name -> common.Metadata + 79, // 60: machine.RestartResponse.messages:type_name -> machine.Restart + 130, // 61: machine.StatsRequest.driver:type_name -> common.ContainerDriver + 126, // 62: machine.Stats.metadata:type_name -> common.Metadata + 84, // 63: machine.Stats.stats:type_name -> machine.Stat + 82, // 64: machine.StatsResponse.messages:type_name -> machine.Stats + 126, // 65: machine.Memory.metadata:type_name -> common.Metadata + 87, // 66: machine.Memory.meminfo:type_name -> machine.MemInfo + 85, // 67: machine.MemoryResponse.messages:type_name -> machine.Memory + 89, // 68: machine.HostnameResponse.messages:type_name -> machine.Hostname + 126, // 69: machine.Hostname.metadata:type_name -> common.Metadata + 91, // 70: machine.LoadAvgResponse.messages:type_name -> machine.LoadAvg + 126, // 71: machine.LoadAvg.metadata:type_name -> common.Metadata + 93, // 72: machine.SystemStatResponse.messages:type_name -> machine.SystemStat + 126, // 73: machine.SystemStat.metadata:type_name -> common.Metadata + 94, // 74: machine.SystemStat.cpu_total:type_name -> machine.CPUStat + 94, // 75: machine.SystemStat.cpu:type_name -> machine.CPUStat + 95, // 76: machine.SystemStat.soft_irq:type_name -> machine.SoftIRQStat + 97, // 77: machine.CPUInfoResponse.messages:type_name -> machine.CPUsInfo + 126, // 78: machine.CPUsInfo.metadata:type_name -> common.Metadata + 98, // 79: machine.CPUsInfo.cpu_info:type_name -> machine.CPUInfo + 100, // 80: machine.NetworkDeviceStatsResponse.messages:type_name -> machine.NetworkDeviceStats + 126, // 81: machine.NetworkDeviceStats.metadata:type_name -> common.Metadata + 101, // 82: machine.NetworkDeviceStats.total:type_name -> machine.NetDev + 101, // 83: machine.NetworkDeviceStats.devices:type_name -> machine.NetDev + 103, // 84: machine.DiskStatsResponse.messages:type_name -> machine.DiskStats + 126, // 85: machine.DiskStats.metadata:type_name -> common.Metadata + 104, // 86: machine.DiskStats.total:type_name -> machine.DiskStat + 104, // 87: machine.DiskStats.devices:type_name -> machine.DiskStat + 126, // 88: machine.EtcdLeaveCluster.metadata:type_name -> common.Metadata + 106, // 89: machine.EtcdLeaveClusterResponse.messages:type_name -> machine.EtcdLeaveCluster + 126, // 90: machine.EtcdForfeitLeadership.metadata:type_name -> common.Metadata + 109, // 91: machine.EtcdForfeitLeadershipResponse.messages:type_name -> machine.EtcdForfeitLeadership + 126, // 92: machine.EtcdMemberList.metadata:type_name -> common.Metadata + 112, // 93: machine.EtcdMemberListResponse.messages:type_name -> machine.EtcdMemberList + 115, // 94: machine.NetworkDeviceConfig.dhcp_options:type_name -> machine.DHCPOptionsConfig + 114, // 95: machine.NetworkDeviceConfig.routes:type_name -> machine.RouteConfig + 116, // 96: machine.NetworkConfig.interfaces:type_name -> machine.NetworkDeviceConfig + 6, // 97: machine.MachineConfig.type:type_name -> machine.MachineConfig.MachineType + 118, // 98: machine.MachineConfig.install_config:type_name -> machine.InstallConfig + 117, // 99: machine.MachineConfig.network_config:type_name -> machine.NetworkConfig + 121, // 100: machine.ClusterNetworkConfig.cni_config:type_name -> machine.CNIConfig + 120, // 101: machine.ClusterConfig.control_plane:type_name -> machine.ControlPlaneConfig + 122, // 102: machine.ClusterConfig.cluster_network:type_name -> machine.ClusterNetworkConfig + 123, // 103: machine.GenerateConfigurationRequest.cluster_config:type_name -> machine.ClusterConfig + 119, // 104: machine.GenerateConfigurationRequest.machine_config:type_name -> machine.MachineConfig + 129, // 105: machine.GenerateConfigurationRequest.override_time:type_name -> google.protobuf.Timestamp + 126, // 106: machine.GenerateConfigurationResponse.metadata:type_name -> common.Metadata + 7, // 107: machine.MachineService.ApplyConfiguration:input_type -> machine.ApplyConfigurationRequest + 12, // 108: machine.MachineService.Bootstrap:input_type -> machine.BootstrapRequest + 69, // 109: machine.MachineService.Containers:input_type -> machine.ContainersRequest + 52, // 110: machine.MachineService.Copy:input_type -> machine.CopyRequest + 131, // 111: machine.MachineService.CPUInfo:input_type -> google.protobuf.Empty + 131, // 112: machine.MachineService.DiskStats:input_type -> google.protobuf.Empty + 73, // 113: machine.MachineService.Dmesg:input_type -> machine.DmesgRequest + 19, // 114: machine.MachineService.Events:input_type -> machine.EventsRequest + 111, // 115: machine.MachineService.EtcdMemberList:input_type -> machine.EtcdMemberListRequest + 105, // 116: machine.MachineService.EtcdLeaveCluster:input_type -> machine.EtcdLeaveClusterRequest + 108, // 117: machine.MachineService.EtcdForfeitLeadership:input_type -> machine.EtcdForfeitLeadershipRequest + 124, // 118: machine.MachineService.GenerateConfiguration:input_type -> machine.GenerateConfigurationRequest + 131, // 119: machine.MachineService.Hostname:input_type -> google.protobuf.Empty + 131, // 120: machine.MachineService.Kubeconfig:input_type -> google.protobuf.Empty + 53, // 121: machine.MachineService.List:input_type -> machine.ListRequest + 54, // 122: machine.MachineService.DiskUsage:input_type -> machine.DiskUsageRequest + 131, // 123: machine.MachineService.LoadAvg:input_type -> google.protobuf.Empty + 64, // 124: machine.MachineService.Logs:input_type -> machine.LogsRequest + 131, // 125: machine.MachineService.Memory:input_type -> google.protobuf.Empty + 131, // 126: machine.MachineService.Mounts:input_type -> google.protobuf.Empty + 131, // 127: machine.MachineService.NetworkDeviceStats:input_type -> google.protobuf.Empty + 131, // 128: machine.MachineService.Processes:input_type -> google.protobuf.Empty + 65, // 129: machine.MachineService.Read:input_type -> machine.ReadRequest + 131, // 130: machine.MachineService.Reboot:input_type -> google.protobuf.Empty + 78, // 131: machine.MachineService.Restart:input_type -> machine.RestartRequest + 66, // 132: machine.MachineService.Rollback:input_type -> machine.RollbackRequest + 22, // 133: machine.MachineService.Reset:input_type -> machine.ResetRequest + 25, // 134: machine.MachineService.Recover:input_type -> machine.RecoverRequest + 131, // 135: machine.MachineService.ServiceList:input_type -> google.protobuf.Empty + 45, // 136: machine.MachineService.ServiceRestart:input_type -> machine.ServiceRestartRequest + 39, // 137: machine.MachineService.ServiceStart:input_type -> machine.ServiceStartRequest + 42, // 138: machine.MachineService.ServiceStop:input_type -> machine.ServiceStopRequest + 131, // 139: machine.MachineService.Shutdown:input_type -> google.protobuf.Empty + 81, // 140: machine.MachineService.Stats:input_type -> machine.StatsRequest + 131, // 141: machine.MachineService.SystemStat:input_type -> google.protobuf.Empty + 30, // 142: machine.MachineService.Upgrade:input_type -> machine.UpgradeRequest + 131, // 143: machine.MachineService.Version:input_type -> google.protobuf.Empty + 9, // 144: machine.MachineService.ApplyConfiguration:output_type -> machine.ApplyConfigurationResponse + 14, // 145: machine.MachineService.Bootstrap:output_type -> machine.BootstrapResponse + 72, // 146: machine.MachineService.Containers:output_type -> machine.ContainersResponse + 132, // 147: machine.MachineService.Copy:output_type -> common.Data + 96, // 148: machine.MachineService.CPUInfo:output_type -> machine.CPUInfoResponse + 102, // 149: machine.MachineService.DiskStats:output_type -> machine.DiskStatsResponse + 132, // 150: machine.MachineService.Dmesg:output_type -> common.Data + 20, // 151: machine.MachineService.Events:output_type -> machine.Event + 113, // 152: machine.MachineService.EtcdMemberList:output_type -> machine.EtcdMemberListResponse + 107, // 153: machine.MachineService.EtcdLeaveCluster:output_type -> machine.EtcdLeaveClusterResponse + 110, // 154: machine.MachineService.EtcdForfeitLeadership:output_type -> machine.EtcdForfeitLeadershipResponse + 125, // 155: machine.MachineService.GenerateConfiguration:output_type -> machine.GenerateConfigurationResponse + 88, // 156: machine.MachineService.Hostname:output_type -> machine.HostnameResponse + 132, // 157: machine.MachineService.Kubeconfig:output_type -> common.Data + 55, // 158: machine.MachineService.List:output_type -> machine.FileInfo + 56, // 159: machine.MachineService.DiskUsage:output_type -> machine.DiskUsageInfo + 90, // 160: machine.MachineService.LoadAvg:output_type -> machine.LoadAvgResponse + 132, // 161: machine.MachineService.Logs:output_type -> common.Data + 86, // 162: machine.MachineService.Memory:output_type -> machine.MemoryResponse + 58, // 163: machine.MachineService.Mounts:output_type -> machine.MountsResponse + 99, // 164: machine.MachineService.NetworkDeviceStats:output_type -> machine.NetworkDeviceStatsResponse + 75, // 165: machine.MachineService.Processes:output_type -> machine.ProcessesResponse + 132, // 166: machine.MachineService.Read:output_type -> common.Data + 11, // 167: machine.MachineService.Reboot:output_type -> machine.RebootResponse + 80, // 168: machine.MachineService.Restart:output_type -> machine.RestartResponse + 68, // 169: machine.MachineService.Rollback:output_type -> machine.RollbackResponse + 24, // 170: machine.MachineService.Reset:output_type -> machine.ResetResponse + 27, // 171: machine.MachineService.Recover:output_type -> machine.RecoverResponse + 34, // 172: machine.MachineService.ServiceList:output_type -> machine.ServiceListResponse + 47, // 173: machine.MachineService.ServiceRestart:output_type -> machine.ServiceRestartResponse + 41, // 174: machine.MachineService.ServiceStart:output_type -> machine.ServiceStartResponse + 44, // 175: machine.MachineService.ServiceStop:output_type -> machine.ServiceStopResponse + 29, // 176: machine.MachineService.Shutdown:output_type -> machine.ShutdownResponse + 83, // 177: machine.MachineService.Stats:output_type -> machine.StatsResponse + 92, // 178: machine.MachineService.SystemStat:output_type -> machine.SystemStatResponse + 32, // 179: machine.MachineService.Upgrade:output_type -> machine.UpgradeResponse + 61, // 180: machine.MachineService.Version:output_type -> machine.VersionResponse + 144, // [144:181] is the sub-list for method output_type + 107, // [107:144] is the sub-list for method input_type + 107, // [107:107] is the sub-list for extension type_name + 107, // [107:107] is the sub-list for extension extendee + 0, // [0:107] is the sub-list for field type_name } func init() { file_machine_machine_proto_init() } diff --git a/pkg/machinery/client/client.go b/pkg/machinery/client/client.go index 9e252f078..e799d8b65 100644 --- a/pkg/machinery/client/client.go +++ b/pkg/machinery/client/client.go @@ -29,6 +29,7 @@ import ( clusterapi "github.com/talos-systems/talos/pkg/machinery/api/cluster" "github.com/talos-systems/talos/pkg/machinery/api/common" + inspectapi "github.com/talos-systems/talos/pkg/machinery/api/inspect" machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine" networkapi "github.com/talos-systems/talos/pkg/machinery/api/network" resourceapi "github.com/talos-systems/talos/pkg/machinery/api/resource" @@ -57,8 +58,10 @@ type Client struct { ClusterClient clusterapi.ClusterServiceClient StorageClient storageapi.StorageServiceClient ResourceClient resourceapi.ResourceServiceClient + InspectClient inspectapi.InspectServiceClient Resources *ResourcesClient + Inspect *InspectClient } func (c *Client) resolveConfigContext() error { @@ -155,8 +158,10 @@ func New(ctx context.Context, opts ...OptionFunc) (c *Client, err error) { c.ClusterClient = clusterapi.NewClusterServiceClient(c.conn) c.StorageClient = storageapi.NewStorageServiceClient(c.conn) c.ResourceClient = resourceapi.NewResourceServiceClient(c.conn) + c.InspectClient = inspectapi.NewInspectServiceClient(c.conn) c.Resources = &ResourcesClient{c.ResourceClient} + c.Inspect = &InspectClient{c.InspectClient} return c, nil } diff --git a/pkg/machinery/client/inspect.go b/pkg/machinery/client/inspect.go new file mode 100644 index 000000000..a7440679b --- /dev/null +++ b/pkg/machinery/client/inspect.go @@ -0,0 +1,30 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package client + +import ( + "context" + + "github.com/golang/protobuf/ptypes/empty" + "google.golang.org/grpc" + + inspectapi "github.com/talos-systems/talos/pkg/machinery/api/inspect" +) + +// InspectClient provides access to inspect API. +type InspectClient struct { + client inspectapi.InspectServiceClient +} + +// ControllerRuntimeDependencies returns graph describing dependencies between controllers. +func (c *InspectClient) ControllerRuntimeDependencies(ctx context.Context, callOptions ...grpc.CallOption) (*inspectapi.ControllerRuntimeDependenciesResponse, error) { + resp, err := c.client.ControllerRuntimeDependencies(ctx, &empty.Empty{}, callOptions...) + + var filtered interface{} + filtered, err = FilterMessages(resp, err) + resp, _ = filtered.(*inspectapi.ControllerRuntimeDependenciesResponse) //nolint: errcheck + + return resp, err +} diff --git a/pkg/machinery/config/provider.go b/pkg/machinery/config/provider.go index e7258b9c0..2a7f39fe1 100644 --- a/pkg/machinery/config/provider.go +++ b/pkg/machinery/config/provider.go @@ -7,6 +7,7 @@ package config import ( "context" "crypto/tls" + "net" "net/url" "os" "time" @@ -248,12 +249,13 @@ type ClusterConfig interface { Token() Token CertSANs() []string CA() *x509.PEMEncodedCertificateAndKey + AggregatorCA() *x509.PEMEncodedCertificateAndKey + ServiceAccount() *x509.PEMEncodedKey AESCBCEncryptionSecret() string Config(machine.Type) (string, error) Etcd() Etcd Network() ClusterNetwork LocalAPIServerPort() int - PodCheckpointer() PodCheckpointer CoreDNS() CoreDNS ExtraManifestURLs() []string ExtraManifestHeaderMap() map[string]string @@ -268,6 +270,8 @@ type ClusterNetwork interface { PodCIDR() string ServiceCIDR() string DNSDomain() string + APIServerIPs() ([]net.IP, error) + DNSServiceIPs() ([]net.IP, error) } // CNI defines the requirements for a config that pertains to Kubernetes @@ -325,13 +329,7 @@ type Token interface { Secret() string } -// PodCheckpointer defines the requirements for a config that pertains to bootkube -// pod-checkpointer options. -type PodCheckpointer interface { - Image() string -} - -// CoreDNS defines the requirements for a config that pertains to bootkube +// CoreDNS defines the requirements for a config that pertains to CoreDNS // coredns options. type CoreDNS interface { Image() string diff --git a/pkg/machinery/config/types/v1alpha1/generate/generate.go b/pkg/machinery/config/types/v1alpha1/generate/generate.go index 845134656..90b24fdc9 100644 --- a/pkg/machinery/config/types/v1alpha1/generate/generate.go +++ b/pkg/machinery/config/types/v1alpha1/generate/generate.go @@ -129,10 +129,12 @@ func (i *Input) GetAPIServerSANs() []string { // Certs holds the base64 encoded keys and certificates. type Certs struct { - Admin *x509.PEMEncodedCertificateAndKey - Etcd *x509.PEMEncodedCertificateAndKey - K8s *x509.PEMEncodedCertificateAndKey - OS *x509.PEMEncodedCertificateAndKey + Admin *x509.PEMEncodedCertificateAndKey + Etcd *x509.PEMEncodedCertificateAndKey + K8s *x509.PEMEncodedCertificateAndKey + K8sAggregator *x509.PEMEncodedCertificateAndKey + K8sServiceAccount *x509.PEMEncodedKey + OS *x509.PEMEncodedCertificateAndKey } // Secrets holds the sensitive kubeadm data. @@ -186,12 +188,14 @@ func (c *SystemClock) SetFixedTimestamp(t time.Time) { // NewSecretsBundle creates secrets bundle generating all secrets. func NewSecretsBundle(clock Clock) (*SecretsBundle, error) { var ( - etcd *x509.CertificateAuthority - kubernetesCA *x509.CertificateAuthority - talosCA *x509.CertificateAuthority - trustdInfo *TrustdInfo - kubeadmTokens *Secrets - err error + etcd *x509.CertificateAuthority + kubernetesCA *x509.CertificateAuthority + aggregatorCA *x509.CertificateAuthority + serviceAccount *x509.RSAKey + talosCA *x509.CertificateAuthority + trustdInfo *TrustdInfo + kubeadmTokens *Secrets + err error ) etcd, err = NewEtcdCA(clock.Now()) @@ -204,11 +208,17 @@ func NewSecretsBundle(clock Clock) (*SecretsBundle, error) { return nil, err } - talosCA, err = NewTalosCA(clock.Now()) + aggregatorCA, err = NewAggregatorCA(clock.Now()) if err != nil { return nil, err } + serviceAccount, err = x509.NewRSAKey() + if err != nil { + return nil, err + } + + talosCA, err = NewTalosCA(clock.Now()) if err != nil { return nil, err } @@ -247,6 +257,13 @@ func NewSecretsBundle(clock Clock) (*SecretsBundle, error) { Crt: kubernetesCA.CrtPEM, Key: kubernetesCA.KeyPEM, }, + K8sAggregator: &x509.PEMEncodedCertificateAndKey{ + Crt: aggregatorCA.CrtPEM, + Key: aggregatorCA.KeyPEM, + }, + K8sServiceAccount: &x509.PEMEncodedKey{ + Key: serviceAccount.KeyPEM, + }, OS: &x509.PEMEncodedCertificateAndKey{ Crt: talosCA.CrtPEM, Key: talosCA.KeyPEM, @@ -258,9 +275,11 @@ func NewSecretsBundle(clock Clock) (*SecretsBundle, error) { // NewSecretsBundleFromConfig creates secrets bundle using existing config. func NewSecretsBundleFromConfig(clock Clock, c config.Provider) *SecretsBundle { certs := &Certs{ - K8s: c.Cluster().CA(), - Etcd: c.Cluster().Etcd().CA(), - OS: c.Machine().Security().CA(), + K8s: c.Cluster().CA(), + K8sAggregator: c.Cluster().AggregatorCA(), + K8sServiceAccount: c.Cluster().ServiceAccount(), + Etcd: c.Cluster().Etcd().CA(), + OS: c.Machine().Security().CA(), } trustd := &TrustdInfo{ @@ -310,6 +329,18 @@ func NewKubernetesCA(currentTime time.Time) (ca *x509.CertificateAuthority, err return x509.NewSelfSignedCertificateAuthority(opts...) } +// NewAggregatorCA generates a CA for the Kubernetes aggregator/front-proxy. +func NewAggregatorCA(currentTime time.Time) (ca *x509.CertificateAuthority, err error) { + opts := []x509.Option{ + x509.RSA(true), + x509.CommonName("front-proxy"), + x509.NotAfter(currentTime.Add(87600 * time.Hour)), + x509.NotBefore(currentTime), + } + + return x509.NewSelfSignedCertificateAuthority(opts...) +} + // NewTalosCA generates a CA for the Talos PKI. func NewTalosCA(currentTime time.Time) (ca *x509.CertificateAuthority, err error) { opts := []x509.Option{ diff --git a/pkg/machinery/config/types/v1alpha1/generate/init.go b/pkg/machinery/config/types/v1alpha1/generate/init.go index 90274e3fa..6a2e74337 100644 --- a/pkg/machinery/config/types/v1alpha1/generate/init.go +++ b/pkg/machinery/config/types/v1alpha1/generate/init.go @@ -76,6 +76,8 @@ func initUd(in *Input) (*v1alpha1.Config, error) { CNI: in.CNIConfig, }, ClusterCA: in.Certs.K8s, + ClusterAggregatorCA: in.Certs.K8sAggregator, + ClusterServiceAccount: in.Certs.K8sServiceAccount, BootstrapToken: in.Secrets.BootstrapToken, ClusterAESCBCEncryptionSecret: in.Secrets.AESCBCEncryptionSecret, } diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go index 2b86ce905..e1c93052d 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go @@ -10,6 +10,7 @@ import ( stdx509 "crypto/x509" "fmt" "log" + "net" "net/url" "os" goruntime "runtime" @@ -18,6 +19,7 @@ import ( specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/talos-systems/crypto/x509" + talosnet "github.com/talos-systems/net" "github.com/talos-systems/talos/pkg/machinery/config" "github.com/talos-systems/talos/pkg/machinery/config/encoder" @@ -289,6 +291,16 @@ func (c *ClusterConfig) CA() *x509.PEMEncodedCertificateAndKey { return c.ClusterCA } +// AggregatorCA implements the config.Provider interface. +func (c *ClusterConfig) AggregatorCA() *x509.PEMEncodedCertificateAndKey { + return c.ClusterAggregatorCA +} + +// ServiceAccount implements the config.Provider interface. +func (c *ClusterConfig) ServiceAccount() *x509.PEMEncodedKey { + return c.ClusterServiceAccount +} + // AESCBCEncryptionSecret implements the config.Provider interface. func (c *ClusterConfig) AESCBCEncryptionSecret() string { return c.ClusterAESCBCEncryptionSecret @@ -631,6 +643,26 @@ func (c *ClusterConfig) ServiceCIDR() string { return strings.Join(c.ClusterNetwork.ServiceSubnet, ",") } +// APIServerIPs returns kube-apiserver IPs in the ServiceCIDR. +func (c *ClusterConfig) APIServerIPs() ([]net.IP, error) { + serviceCIDRs, err := talosnet.SplitCIDRs(c.ServiceCIDR()) + if err != nil { + return nil, fmt.Errorf("failed to process Service CIDRs: %w", err) + } + + return talosnet.NthIPInCIDRSet(serviceCIDRs, 1) +} + +// DNSServiceIPs returns DNS service IPs in the ServiceCIDR. +func (c *ClusterConfig) DNSServiceIPs() ([]net.IP, error) { + serviceCIDRs, err := talosnet.SplitCIDRs(c.ServiceCIDR()) + if err != nil { + return nil, fmt.Errorf("failed to process Service CIDRs: %w", err) + } + + return talosnet.NthIPInCIDRSet(serviceCIDRs, 10) +} + // ExtraManifestURLs implements the config.Provider interface. func (c *ClusterConfig) ExtraManifestURLs() []string { return c.ExtraManifests @@ -641,15 +673,6 @@ func (c *ClusterConfig) ExtraManifestHeaderMap() map[string]string { return c.ExtraManifestHeaders } -// PodCheckpointer implements the config.Provider interface. -func (c *ClusterConfig) PodCheckpointer() config.PodCheckpointer { - if c.PodCheckpointerConfig == nil { - return &PodCheckpointer{} - } - - return c.PodCheckpointerConfig -} - // CoreDNS implements the config.Provider interface. func (c *ClusterConfig) CoreDNS() config.CoreDNS { if c.CoreDNSConfig == nil { @@ -1074,11 +1097,6 @@ func (c *CoreDNS) Image() string { return coreDNSImage } -// Image implements the config.Provider interface. -func (p *PodCheckpointer) Image() string { - return p.PodCheckpointerImage -} - // CertLifetime implements the config.Provider interface. func (a AdminKubeconfigConfig) CertLifetime() time.Duration { if a.AdminKubeconfigCertLifetime == 0 { diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go index 9500ed98b..e4801bd72 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go @@ -114,6 +114,10 @@ var ( Key: []byte("LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM..."), } + pemEncodedKeyExample *x509.PEMEncodedKey = &x509.PEMEncodedKey{ + Key: []byte("LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM..."), + } + machineKubeletExample = &KubeletConfig{ KubeletImage: (&KubeletConfig{}).Image(), KubeletExtraArgs: map[string]string{ @@ -570,6 +574,20 @@ type ClusterConfig struct { // value: pemEncodedCertificateExample ClusterCA *x509.PEMEncodedCertificateAndKey `yaml:"ca,omitempty"` // description: | + // The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation. + // + // This CA can be self-signed. + // examples: + // - name: AggregatorCA example. + // value: pemEncodedCertificateExample + ClusterAggregatorCA *x509.PEMEncodedCertificateAndKey `yaml:"aggregatorCA,omitempty"` + // description: | + // The base64 encoded private key for service account token generation. + // examples: + // - name: AggregatorCA example. + // value: pemEncodedKeyExample + ClusterServiceAccount *x509.PEMEncodedKey `yaml:"serviceAccount,omitempty"` + // description: | // API server specific configuration options. // examples: // - value: clusterAPIServerExample @@ -606,7 +624,7 @@ type ClusterConfig struct { CoreDNSConfig *CoreDNS `yaml:"coreDNS,omitempty"` // description: | // A list of urls that point to additional manifests. - // These will get automatically deployed by bootkube. + // These will get automatically deployed as part of the bootstrap. // examples: // - value: > // []string{ @@ -920,7 +938,7 @@ type ClusterNetworkConfig struct { // The "name" key only supports options of "flannel" or "custom". // URLs is only used if name is equal to "custom". // URLs should point to the set of YAML files to be deployed. - // An empty struct or any other name will default to bootkube's flannel. + // An empty struct or any other name will default to Flannel CNI. // examples: // - value: clusterCustomCNIExample CNI *CNIConfig `yaml:"cni,omitempty"` diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go index 1aaa342b2..b7b1ba22c 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go @@ -225,7 +225,7 @@ func init() { FieldName: "cluster", }, } - ClusterConfigDoc.Fields = make([]encoder.Doc, 17) + ClusterConfigDoc.Fields = make([]encoder.Doc, 19) ClusterConfigDoc.Fields[0].Name = "controlPlane" ClusterConfigDoc.Fields[0].Type = "ControlPlaneConfig" ClusterConfigDoc.Fields[0].Note = "" @@ -266,88 +266,102 @@ func init() { ClusterConfigDoc.Fields[5].Comments[encoder.LineComment] = "The base64 encoded root certificate authority used by Kubernetes." ClusterConfigDoc.Fields[5].AddExample("ClusterCA example.", pemEncodedCertificateExample) - ClusterConfigDoc.Fields[6].Name = "apiServer" - ClusterConfigDoc.Fields[6].Type = "APIServerConfig" + ClusterConfigDoc.Fields[6].Name = "aggregatorCA" + ClusterConfigDoc.Fields[6].Type = "PEMEncodedCertificateAndKey" ClusterConfigDoc.Fields[6].Note = "" - ClusterConfigDoc.Fields[6].Description = "API server specific configuration options." - ClusterConfigDoc.Fields[6].Comments[encoder.LineComment] = "API server specific configuration options." + ClusterConfigDoc.Fields[6].Description = "The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\n\nThis CA can be self-signed." + ClusterConfigDoc.Fields[6].Comments[encoder.LineComment] = "The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation." - ClusterConfigDoc.Fields[6].AddExample("", clusterAPIServerExample) - ClusterConfigDoc.Fields[7].Name = "controllerManager" - ClusterConfigDoc.Fields[7].Type = "ControllerManagerConfig" + ClusterConfigDoc.Fields[6].AddExample("AggregatorCA example.", pemEncodedCertificateExample) + ClusterConfigDoc.Fields[7].Name = "serviceAccount" + ClusterConfigDoc.Fields[7].Type = "PEMEncodedKey" ClusterConfigDoc.Fields[7].Note = "" - ClusterConfigDoc.Fields[7].Description = "Controller manager server specific configuration options." - ClusterConfigDoc.Fields[7].Comments[encoder.LineComment] = "Controller manager server specific configuration options." + ClusterConfigDoc.Fields[7].Description = "The base64 encoded private key for service account token generation." + ClusterConfigDoc.Fields[7].Comments[encoder.LineComment] = "The base64 encoded private key for service account token generation." - ClusterConfigDoc.Fields[7].AddExample("", clusterControllerManagerExample) - ClusterConfigDoc.Fields[8].Name = "proxy" - ClusterConfigDoc.Fields[8].Type = "ProxyConfig" + ClusterConfigDoc.Fields[7].AddExample("AggregatorCA example.", pemEncodedKeyExample) + ClusterConfigDoc.Fields[8].Name = "apiServer" + ClusterConfigDoc.Fields[8].Type = "APIServerConfig" ClusterConfigDoc.Fields[8].Note = "" - ClusterConfigDoc.Fields[8].Description = "Kube-proxy server-specific configuration options" - ClusterConfigDoc.Fields[8].Comments[encoder.LineComment] = "Kube-proxy server-specific configuration options" + ClusterConfigDoc.Fields[8].Description = "API server specific configuration options." + ClusterConfigDoc.Fields[8].Comments[encoder.LineComment] = "API server specific configuration options." - ClusterConfigDoc.Fields[8].AddExample("", clusterProxyExample) - ClusterConfigDoc.Fields[9].Name = "scheduler" - ClusterConfigDoc.Fields[9].Type = "SchedulerConfig" + ClusterConfigDoc.Fields[8].AddExample("", clusterAPIServerExample) + ClusterConfigDoc.Fields[9].Name = "controllerManager" + ClusterConfigDoc.Fields[9].Type = "ControllerManagerConfig" ClusterConfigDoc.Fields[9].Note = "" - ClusterConfigDoc.Fields[9].Description = "Scheduler server specific configuration options." - ClusterConfigDoc.Fields[9].Comments[encoder.LineComment] = "Scheduler server specific configuration options." + ClusterConfigDoc.Fields[9].Description = "Controller manager server specific configuration options." + ClusterConfigDoc.Fields[9].Comments[encoder.LineComment] = "Controller manager server specific configuration options." - ClusterConfigDoc.Fields[9].AddExample("", clusterSchedulerExample) - ClusterConfigDoc.Fields[10].Name = "etcd" - ClusterConfigDoc.Fields[10].Type = "EtcdConfig" + ClusterConfigDoc.Fields[9].AddExample("", clusterControllerManagerExample) + ClusterConfigDoc.Fields[10].Name = "proxy" + ClusterConfigDoc.Fields[10].Type = "ProxyConfig" ClusterConfigDoc.Fields[10].Note = "" - ClusterConfigDoc.Fields[10].Description = "Etcd specific configuration options." - ClusterConfigDoc.Fields[10].Comments[encoder.LineComment] = "Etcd specific configuration options." + ClusterConfigDoc.Fields[10].Description = "Kube-proxy server-specific configuration options" + ClusterConfigDoc.Fields[10].Comments[encoder.LineComment] = "Kube-proxy server-specific configuration options" - ClusterConfigDoc.Fields[10].AddExample("", clusterEtcdExample) - ClusterConfigDoc.Fields[11].Name = "podCheckpointer" - ClusterConfigDoc.Fields[11].Type = "PodCheckpointer" + ClusterConfigDoc.Fields[10].AddExample("", clusterProxyExample) + ClusterConfigDoc.Fields[11].Name = "scheduler" + ClusterConfigDoc.Fields[11].Type = "SchedulerConfig" ClusterConfigDoc.Fields[11].Note = "" - ClusterConfigDoc.Fields[11].Description = "Pod Checkpointer specific configuration options." - ClusterConfigDoc.Fields[11].Comments[encoder.LineComment] = "Pod Checkpointer specific configuration options." + ClusterConfigDoc.Fields[11].Description = "Scheduler server specific configuration options." + ClusterConfigDoc.Fields[11].Comments[encoder.LineComment] = "Scheduler server specific configuration options." - ClusterConfigDoc.Fields[11].AddExample("", clusterPodCheckpointerExample) - ClusterConfigDoc.Fields[12].Name = "coreDNS" - ClusterConfigDoc.Fields[12].Type = "CoreDNS" + ClusterConfigDoc.Fields[11].AddExample("", clusterSchedulerExample) + ClusterConfigDoc.Fields[12].Name = "etcd" + ClusterConfigDoc.Fields[12].Type = "EtcdConfig" ClusterConfigDoc.Fields[12].Note = "" - ClusterConfigDoc.Fields[12].Description = "Core DNS specific configuration options." - ClusterConfigDoc.Fields[12].Comments[encoder.LineComment] = "Core DNS specific configuration options." + ClusterConfigDoc.Fields[12].Description = "Etcd specific configuration options." + ClusterConfigDoc.Fields[12].Comments[encoder.LineComment] = "Etcd specific configuration options." - ClusterConfigDoc.Fields[12].AddExample("", clusterCoreDNSExample) - ClusterConfigDoc.Fields[13].Name = "extraManifests" - ClusterConfigDoc.Fields[13].Type = "[]string" + ClusterConfigDoc.Fields[12].AddExample("", clusterEtcdExample) + ClusterConfigDoc.Fields[13].Name = "podCheckpointer" + ClusterConfigDoc.Fields[13].Type = "PodCheckpointer" ClusterConfigDoc.Fields[13].Note = "" - ClusterConfigDoc.Fields[13].Description = "A list of urls that point to additional manifests.\nThese will get automatically deployed by bootkube." - ClusterConfigDoc.Fields[13].Comments[encoder.LineComment] = "A list of urls that point to additional manifests." + ClusterConfigDoc.Fields[13].Description = "Pod Checkpointer specific configuration options." + ClusterConfigDoc.Fields[13].Comments[encoder.LineComment] = "Pod Checkpointer specific configuration options." - ClusterConfigDoc.Fields[13].AddExample("", []string{ + ClusterConfigDoc.Fields[13].AddExample("", clusterPodCheckpointerExample) + ClusterConfigDoc.Fields[14].Name = "coreDNS" + ClusterConfigDoc.Fields[14].Type = "CoreDNS" + ClusterConfigDoc.Fields[14].Note = "" + ClusterConfigDoc.Fields[14].Description = "Core DNS specific configuration options." + ClusterConfigDoc.Fields[14].Comments[encoder.LineComment] = "Core DNS specific configuration options." + + ClusterConfigDoc.Fields[14].AddExample("", clusterCoreDNSExample) + ClusterConfigDoc.Fields[15].Name = "extraManifests" + ClusterConfigDoc.Fields[15].Type = "[]string" + ClusterConfigDoc.Fields[15].Note = "" + ClusterConfigDoc.Fields[15].Description = "A list of urls that point to additional manifests.\nThese will get automatically deployed as part of the bootstrap." + ClusterConfigDoc.Fields[15].Comments[encoder.LineComment] = "A list of urls that point to additional manifests." + + ClusterConfigDoc.Fields[15].AddExample("", []string{ "https://www.example.com/manifest1.yaml", "https://www.example.com/manifest2.yaml", }) - ClusterConfigDoc.Fields[14].Name = "extraManifestHeaders" - ClusterConfigDoc.Fields[14].Type = "map[string]string" - ClusterConfigDoc.Fields[14].Note = "" - ClusterConfigDoc.Fields[14].Description = "A map of key value pairs that will be added while fetching the ExtraManifests." - ClusterConfigDoc.Fields[14].Comments[encoder.LineComment] = "A map of key value pairs that will be added while fetching the ExtraManifests." + ClusterConfigDoc.Fields[16].Name = "extraManifestHeaders" + ClusterConfigDoc.Fields[16].Type = "map[string]string" + ClusterConfigDoc.Fields[16].Note = "" + ClusterConfigDoc.Fields[16].Description = "A map of key value pairs that will be added while fetching the ExtraManifests." + ClusterConfigDoc.Fields[16].Comments[encoder.LineComment] = "A map of key value pairs that will be added while fetching the ExtraManifests." - ClusterConfigDoc.Fields[14].AddExample("", map[string]string{ + ClusterConfigDoc.Fields[16].AddExample("", map[string]string{ "Token": "1234567", "X-ExtraInfo": "info", }) - ClusterConfigDoc.Fields[15].Name = "adminKubeconfig" - ClusterConfigDoc.Fields[15].Type = "AdminKubeconfigConfig" - ClusterConfigDoc.Fields[15].Note = "" - ClusterConfigDoc.Fields[15].Description = "Settings for admin kubeconfig generation.\nCertificate lifetime can be configured." - ClusterConfigDoc.Fields[15].Comments[encoder.LineComment] = "Settings for admin kubeconfig generation." + ClusterConfigDoc.Fields[17].Name = "adminKubeconfig" + ClusterConfigDoc.Fields[17].Type = "AdminKubeconfigConfig" + ClusterConfigDoc.Fields[17].Note = "" + ClusterConfigDoc.Fields[17].Description = "Settings for admin kubeconfig generation.\nCertificate lifetime can be configured." + ClusterConfigDoc.Fields[17].Comments[encoder.LineComment] = "Settings for admin kubeconfig generation." - ClusterConfigDoc.Fields[15].AddExample("", clusterAdminKubeconfigExample) - ClusterConfigDoc.Fields[16].Name = "allowSchedulingOnMasters" - ClusterConfigDoc.Fields[16].Type = "bool" - ClusterConfigDoc.Fields[16].Note = "" - ClusterConfigDoc.Fields[16].Description = "Allows running workload on master nodes." - ClusterConfigDoc.Fields[16].Comments[encoder.LineComment] = "Allows running workload on master nodes." - ClusterConfigDoc.Fields[16].Values = []string{ + ClusterConfigDoc.Fields[17].AddExample("", clusterAdminKubeconfigExample) + ClusterConfigDoc.Fields[18].Name = "allowSchedulingOnMasters" + ClusterConfigDoc.Fields[18].Type = "bool" + ClusterConfigDoc.Fields[18].Note = "" + ClusterConfigDoc.Fields[18].Description = "Allows running workload on master nodes." + ClusterConfigDoc.Fields[18].Comments[encoder.LineComment] = "Allows running workload on master nodes." + ClusterConfigDoc.Fields[18].Values = []string{ "true", "yes", "false", @@ -772,7 +786,7 @@ func init() { ClusterNetworkConfigDoc.Fields[0].Name = "cni" ClusterNetworkConfigDoc.Fields[0].Type = "CNIConfig" ClusterNetworkConfigDoc.Fields[0].Note = "" - ClusterNetworkConfigDoc.Fields[0].Description = "The CNI used.\nComposed of \"name\" and \"url\".\nThe \"name\" key only supports options of \"flannel\" or \"custom\".\nURLs is only used if name is equal to \"custom\".\nURLs should point to the set of YAML files to be deployed.\nAn empty struct or any other name will default to bootkube's flannel." + ClusterNetworkConfigDoc.Fields[0].Description = "The CNI used.\nComposed of \"name\" and \"url\".\nThe \"name\" key only supports options of \"flannel\" or \"custom\".\nURLs is only used if name is equal to \"custom\".\nURLs should point to the set of YAML files to be deployed.\nAn empty struct or any other name will default to Flannel CNI." ClusterNetworkConfigDoc.Fields[0].Comments[encoder.LineComment] = "The CNI used." ClusterNetworkConfigDoc.Fields[0].AddExample("", clusterCustomCNIExample) diff --git a/pkg/machinery/constants/constants.go b/pkg/machinery/constants/constants.go index d59617161..8799cfd83 100644 --- a/pkg/machinery/constants/constants.go +++ b/pkg/machinery/constants/constants.go @@ -123,6 +123,9 @@ const ( // PATH defines all locations where executables are stored. PATH = "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:" + cni.DefaultCNIDir + // KubernetesDefaultCertificateValidityDuration specifies default certificate duration for Kubernetes generated certificates. + KubernetesDefaultCertificateValidityDuration = time.Hour * 24 * 365 + // DefaultCertificatesDir is the path the the Kubernetes PKI directory. DefaultCertificatesDir = "/etc/kubernetes/pki" @@ -132,18 +135,6 @@ const ( // KubernetesCAKey is the path to the root CA private key. KubernetesCAKey = DefaultCertificatesDir + "/" + "ca.key" - // KubernetesSACert is the path to the SA certificate. - KubernetesSACert = DefaultCertificatesDir + "/" + "sa.crt" - - // KubernetesSAKey is the path to the SA private key. - KubernetesSAKey = DefaultCertificatesDir + "/" + "sa.key" - - // KubernetesFrontProxyCACert is the path to the front proxy CA certificate. - KubernetesFrontProxyCACert = DefaultCertificatesDir + "/" + "fp.crt" - - // KubernetesFrontProxyCAKey is the path to the front proxy CA private key. - KubernetesFrontProxyCAKey = DefaultCertificatesDir + "/" + "fp.key" - // KubernetesEtcdCACert is the path to the etcd CA certificate. KubernetesEtcdCACert = EtcdPKIPath + "/" + "ca.crt" @@ -156,21 +147,9 @@ const ( // KubernetesEtcdPeerKey is the path to the etcd CA private key. KubernetesEtcdPeerKey = EtcdPKIPath + "/" + "peer.key" - // KubernetesEtcdServerCert defines etcd's server certificate name. - KubernetesEtcdServerCert = EtcdPKIPath + "/" + "client.crt" - - // KubernetesEtcdServerKey defines etcd's server key name. - KubernetesEtcdServerKey = EtcdPKIPath + "/" + "client.key" - // KubernetesEtcdListenClientPort defines the port etcd listen on for client traffic. KubernetesEtcdListenClientPort = "2379" - // KubernetesAPIServerEtcdClientCert defines apiserver's etcd client certificate name. - KubernetesAPIServerEtcdClientCert = DefaultCertificatesDir + "/" + "apiserver-etcd-client.crt" - - // KubernetesAPIServerEtcdClientKey defines apiserver's etcd client key name. - KubernetesAPIServerEtcdClientKey = DefaultCertificatesDir + "/" + "apiserver-etcd-client.key" - // KubernetesAdminCertCommonName defines CN property of Kubernetes admin certificate. KubernetesAdminCertCommonName = "apiserver-kubelet-client" @@ -180,10 +159,31 @@ const ( // KubernetesAdminCertDefaultLifetime defines default lifetime for Kubernetes generated admin certificate. KubernetesAdminCertDefaultLifetime = 365 * 24 * time.Hour + // KubebernetesStaticSecretsDir defines ephemeral directory which contains rendered secrets for controlplane components. + KubebernetesStaticSecretsDir = "/system/secrets/kubernetes" + + // KubernetesAPIServerSecretsDir defines ephemeral directory with kube-apiserver secrets. + KubernetesAPIServerSecretsDir = KubebernetesStaticSecretsDir + "/" + "kube-apiserver" + + // KubernetesControllerManagerSecretsDir defines ephemeral directory with kube-controller-manager secrets. + KubernetesControllerManagerSecretsDir = KubebernetesStaticSecretsDir + "/" + "kube-controller-manager" + + // KubernetesSchedulerSecretsDir defines ephemeral directory with kube-scheduler secrets. + KubernetesSchedulerSecretsDir = KubebernetesStaticSecretsDir + "/" + "kube-scheduler" + + // KubernetesRunUser defines UID to run control plane components. + KubernetesRunUser = 65534 + // KubeletBootstrapKubeconfig is the path to the kubeconfig required to // bootstrap the kubelet. KubeletBootstrapKubeconfig = "/etc/kubernetes/bootstrap-kubeconfig" + // KubeletPort is the kubelet port for secure API. + KubeletPort = 10250 + + // KubeletPKIDir is the path to the directory where kubelet stores issues certificates and keys. + KubeletPKIDir = "/var/lib/kubelet/pki" + // DefaultKubernetesVersion is the default target version of the control plane. DefaultKubernetesVersion = "1.20.2" @@ -214,18 +214,12 @@ const ( // DefaultCoreDNSVersion is the default version for the CoreDNS. DefaultCoreDNSVersion = "1.7.0" - // RecoveryKubeconfig is the path to kubeconfig used temporarily while recovering control plane. - RecoveryKubeconfig = "/etc/kubernetes/kubeconfig" - // LabelNodeRoleMaster is the node label required by a control plane node. LabelNodeRoleMaster = "node-role.kubernetes.io/master" // LabelNodeRoleControlPlane is the node label required by a control plane node. LabelNodeRoleControlPlane = "node-role.kubernetes.io/control-plane" - // AssetsDirectory is the directory that contains all bootstrap assets. - AssetsDirectory = "/etc/kubernetes/assets" - // ManifestsDirectory is the directory that contains all static manifests. ManifestsDirectory = "/etc/kubernetes/manifests" @@ -241,6 +235,9 @@ const ( // EtcdTalosEtcdUpgradeMutex is the etcd mutex prefix to be used to set an etcd upgrade lock. EtcdTalosEtcdUpgradeMutex = EtcdRootTalosKey + ":etcdUpgradeMutex" + // EtcdTalosManifestApplyMutex is the etcd election . + EtcdTalosManifestApplyMutex = EtcdRootTalosKey + ":manifestApplyMutex" + // EtcdImage is the reposistory for the etcd image. EtcdImage = "gcr.io/etcd-development/etcd" @@ -378,15 +375,12 @@ const ( // initialized. InitializedKey = "initialized" - // BootkubeAssetTimeout is the constant in bootkube implementation. - BootkubeAssetTimeout = 20 * time.Minute - - // BootkubeRunTimeout is the timeout to run bootkube. - BootkubeRunTimeout = BootkubeAssetTimeout + 5*time.Minute + // BootTimeout is the timeout to run all services. + BootTimeout = 15 * time.Minute // NodeReadyTimeout is the timeout to wait for the node to be ready (CNI to be running). - // For bootstrap API, this includes time to run bootkube. - NodeReadyTimeout = BootkubeRunTimeout + // For bootstrap API, this includes time to run bootstrap. + NodeReadyTimeout = BootTimeout ) // See https://linux.die.net/man/3/klogctl diff --git a/pkg/machinery/go.mod b/pkg/machinery/go.mod index fb1e73c82..d213e9bed 100644 --- a/pkg/machinery/go.mod +++ b/pkg/machinery/go.mod @@ -15,10 +15,10 @@ require ( github.com/onsi/ginkgo v1.11.0 // indirect github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2 github.com/stretchr/objx v0.2.0 // indirect - github.com/stretchr/testify v1.6.1 - github.com/talos-systems/crypto v0.2.1-0.20201203131813-e0dd56ac4745 - github.com/talos-systems/net v0.2.0 - github.com/talos-systems/os-runtime v0.0.0-20210119124441-98acf0d2d332 + github.com/stretchr/testify v1.7.0 + github.com/talos-systems/crypto v0.2.1-0.20210125160556-cf75519cab82 + github.com/talos-systems/net v0.2.1-0.20210121122956-005a94f8b36b + github.com/talos-systems/os-runtime v0.0.0-20210126185717-734f1e1cee9e golang.org/x/net v0.0.0-20200707034311-ab3426394381 // indirect golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 // indirect golang.org/x/text v0.3.3 // indirect @@ -26,5 +26,5 @@ require ( google.golang.org/grpc v1.29.1 google.golang.org/protobuf v1.25.0 gopkg.in/yaml.v2 v2.2.8 // indirect - gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) diff --git a/pkg/machinery/go.sum b/pkg/machinery/go.sum index bf9e65563..aa52e55f8 100644 --- a/pkg/machinery/go.sum +++ b/pkg/machinery/go.sum @@ -4,6 +4,7 @@ github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj4 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -87,13 +88,15 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/talos-systems/crypto v0.2.1-0.20201203131813-e0dd56ac4745 h1:Smw6ebFiEiwrkaOD2hEYYb+xkIhQTMZNq3WVYKLszB8= -github.com/talos-systems/crypto v0.2.1-0.20201203131813-e0dd56ac4745/go.mod h1:KwqG+jANKU1FNQIapmioHQ5fkovY1DJkAqMenjYBGh0= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/talos-systems/crypto v0.2.1-0.20210125160556-cf75519cab82 h1:5TsM3o/yJJF6kakHyPee88D0yWNNDNKZJ2NCX9MFsKk= +github.com/talos-systems/crypto v0.2.1-0.20210125160556-cf75519cab82/go.mod h1:OXCK52Q0dzm88YRG4VdTBdidkPUtqrCxCyW7bUs4DAw= github.com/talos-systems/go-retry v0.2.0/go.mod h1:HiXQqyVStZ35uSY/MTLWVvQVmC3lIW2MS5VdDaMtoKM= -github.com/talos-systems/net v0.2.0 h1:QJ2ofYboG1Zjew9b+3RAjtLIfL0mIONGuc6/LyO68MM= -github.com/talos-systems/net v0.2.0/go.mod h1:VreSAyRmxMtqussAHSKMKkJQa1YwBTSVfkmE4Jydam4= -github.com/talos-systems/os-runtime v0.0.0-20210119124441-98acf0d2d332 h1:Ib5HAIpv8GjAfdKSzcPfvUPN2mbzYwsre61Sogjt/kk= -github.com/talos-systems/os-runtime v0.0.0-20210119124441-98acf0d2d332/go.mod h1:pQ8E1nmr8SODM9TD9HXH5HlzgyfyeCO8yug4x6fDKlQ= +github.com/talos-systems/net v0.2.1-0.20210121122956-005a94f8b36b h1:y3mBkTJdW7cUn+ff53TZN0yyWCpjS6XrVmlx+vx9pwA= +github.com/talos-systems/net v0.2.1-0.20210121122956-005a94f8b36b/go.mod h1:VreSAyRmxMtqussAHSKMKkJQa1YwBTSVfkmE4Jydam4= +github.com/talos-systems/os-runtime v0.0.0-20210126185717-734f1e1cee9e h1:HrAdgwnXhVr9LlWjpc+kejkLVUpTRKbNTAJe7H+kRXM= +github.com/talos-systems/os-runtime v0.0.0-20210126185717-734f1e1cee9e/go.mod h1:+E9CUVoYpReh0nhOEvFpy7pwLiyq0700WF03I06giyk= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= @@ -173,7 +176,7 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/provision/access/adapter.go b/pkg/provision/access/adapter.go index c431aa910..8c2dcb070 100644 --- a/pkg/provision/access/adapter.go +++ b/pkg/provision/access/adapter.go @@ -15,7 +15,7 @@ type Adapter struct { cluster.ConfigClientProvider cluster.KubernetesClient cluster.APICrashDumper - cluster.APIBoostrapper + cluster.APIBootstrapper cluster.Info cluster.ApplyConfigClient } @@ -73,7 +73,7 @@ func NewAdapter(clusterInfo provision.Cluster, opts ...provision.Option) *Adapte ClientProvider: &configProvider, Info: info, }, - APIBoostrapper: cluster.APIBoostrapper{ + APIBootstrapper: cluster.APIBootstrapper{ ClientProvider: &configProvider, Info: info, }, diff --git a/website/content/docs/v0.9/Reference/api.md b/website/content/docs/v0.9/Reference/api.md index 4d47149b2..c7d90f18f 100644 --- a/website/content/docs/v0.9/Reference/api.md +++ b/website/content/docs/v0.9/Reference/api.md @@ -28,6 +28,15 @@ description: Talos gRPC API reference. - [Health](#health.Health) +- [inspect/inspect.proto](#inspect/inspect.proto) + - [ControllerDependencyEdge](#inspect.ControllerDependencyEdge) + - [ControllerRuntimeDependenciesResponse](#inspect.ControllerRuntimeDependenciesResponse) + - [ControllerRuntimeDependency](#inspect.ControllerRuntimeDependency) + + - [DependencyEdgeType](#inspect.DependencyEdgeType) + + - [InspectService](#inspect.InspectService) + - [machine/machine.proto](#machine/machine.proto) - [ApplyConfiguration](#machine.ApplyConfiguration) - [ApplyConfigurationRequest](#machine.ApplyConfigurationRequest) @@ -480,6 +489,97 @@ Common metadata message nested in all reply message types + +

Top

+ +## inspect/inspect.proto + + + + + +### ControllerDependencyEdge + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| controller_name | [string](#string) | | | +| edge_type | [DependencyEdgeType](#inspect.DependencyEdgeType) | | | +| resource_namespace | [string](#string) | | | +| resource_type | [string](#string) | | | +| resource_id | [string](#string) | | | + + + + + + + + +### ControllerRuntimeDependenciesResponse + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| messages | [ControllerRuntimeDependency](#inspect.ControllerRuntimeDependency) | repeated | | + + + + + + + + +### ControllerRuntimeDependency +The ControllerRuntimeDependency message contains the graph of controller-resource dependencies. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| metadata | [common.Metadata](#common.Metadata) | | | +| edges | [ControllerDependencyEdge](#inspect.ControllerDependencyEdge) | repeated | | + + + + + + + + + + +### DependencyEdgeType + + +| Name | Number | Description | +| ---- | ------ | ----------- | +| MANAGES | 0 | | +| STRONG | 1 | | +| WEAK | 2 | | + + + + + + + + + +### InspectService +The inspect service definition. + +InspectService provides auxilary API to inspect OS internals. + +| Method Name | Request Type | Response Type | Description | +| ----------- | ------------ | ------------- | ------------| +| ControllerRuntimeDependencies | [.google.protobuf.Empty](#google.protobuf.Empty) | [ControllerRuntimeDependenciesResponse](#inspect.ControllerRuntimeDependenciesResponse) | | + + + + +

Top

@@ -2125,6 +2225,7 @@ rpc servicestart | service | [string](#string) | | | | action | [ServiceStateEvent.Action](#machine.ServiceStateEvent.Action) | | | | message | [string](#string) | | | +| health | [ServiceHealth](#machine.ServiceHealth) | | | diff --git a/website/content/docs/v0.9/Reference/cli.md b/website/content/docs/v0.9/Reference/cli.md index 4b32d3f16..1eabc7a4d 100644 --- a/website/content/docs/v0.9/Reference/cli.md +++ b/website/content/docs/v0.9/Reference/cli.md @@ -1105,6 +1105,68 @@ talosctl images [flags] * [talosctl](#talosctl) - A CLI for out-of-band management of Kubernetes nodes created by Talos +## talosctl inspect dependencies + +Inspect controller-resource dependencies as graphviz graph. + +### Synopsis + +Inspect controller-resource dependencies as graphviz graph. + +Pipe the output of the command through the "dot" program (part of graphviz package) +to render the graph: + + talosctl inspect dependencies | dot -Tpng > graph.png + + +``` +talosctl inspect dependencies [flags] +``` + +### Options + +``` + -h, --help help for dependencies + --with-resources display live resource information with dependencies +``` + +### Options inherited from parent commands + +``` + --context string Context to be used in command + -e, --endpoints strings override default endpoints in Talos configuration + -n, --nodes strings target the specified nodes + --talosconfig string The path to the Talos configuration file (default "/home/user/.talos/config") +``` + +### SEE ALSO + +* [talosctl inspect](#talosctl-inspect) - Inspect internals of Talos + +## talosctl inspect + +Inspect internals of Talos + +### Options + +``` + -h, --help help for inspect +``` + +### Options inherited from parent commands + +``` + --context string Context to be used in command + -e, --endpoints strings override default endpoints in Talos configuration + -n, --nodes strings target the specified nodes + --talosconfig string The path to the Talos configuration file (default "/home/user/.talos/config") +``` + +### SEE ALSO + +* [talosctl](#talosctl) - A CLI for out-of-band management of Kubernetes nodes created by Talos +* [talosctl inspect dependencies](#talosctl-inspect-dependencies) - Inspect controller-resource dependencies as graphviz graph. + ## talosctl interfaces List network interfaces @@ -1816,6 +1878,7 @@ A CLI for out-of-band management of Kubernetes nodes created by Talos * [talosctl get](#talosctl-get) - Get a specific resource or list of resources. * [talosctl health](#talosctl-health) - Check cluster health * [talosctl images](#talosctl-images) - List the default images used by Talos +* [talosctl inspect](#talosctl-inspect) - Inspect internals of Talos * [talosctl interfaces](#talosctl-interfaces) - List network interfaces * [talosctl kubeconfig](#talosctl-kubeconfig) - Download the admin kubeconfig from the node * [talosctl list](#talosctl-list) - Retrieve a directory listing diff --git a/website/content/docs/v0.9/Reference/configuration.md b/website/content/docs/v0.9/Reference/configuration.md index c7cbd3113..3d3244e03 100644 --- a/website/content/docs/v0.9/Reference/configuration.md +++ b/website/content/docs/v0.9/Reference/configuration.md @@ -831,6 +831,57 @@ ca: ``` + + +
+ +
+ +aggregatorCA PEMEncodedCertificateAndKey + +
+
+ +The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation. + +This CA can be self-signed. + + + +Examples: + + +``` yaml +aggregatorCA: + crt: TFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVSklla05DTUhGLi4u + key: TFMwdExTMUNSVWRKVGlCRlJESTFOVEU1SUZCU1NWWkJWRVVnUzBWWkxTMHRMUzBLVFVNLi4u +``` + + +
+ +
+ +
+ +serviceAccount PEMEncodedKey + +
+
+ +The base64 encoded private key for service account token generation. + + + +Examples: + + +``` yaml +serviceAccount: + key: TFMwdExTMUNSVWRKVGlCRlJESTFOVEU1SUZCU1NWWkJWRVVnUzBWWkxTMHRMUzBLVFVNLi4u +``` + +

@@ -1036,7 +1087,7 @@ coreDNS:
A list of urls that point to additional manifests. -These will get automatically deployed by bootkube. +These will get automatically deployed as part of the bootstrap. @@ -2327,7 +2378,7 @@ Composed of "name" and "url". The "name" key only supports options of "flannel" or "custom". URLs is only used if name is equal to "custom". URLs should point to the set of YAML files to be deployed. -An empty struct or any other name will default to bootkube's flannel. +An empty struct or any other name will default to Flannel CNI.