blob: f3dc4f7b6ca616eb7f0751bf9f67e592f5a7ccf1 [file] [log] [blame]
Lorenz Brun6e8f69c2019-11-18 10:44:24 +01001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package kubernetes
18
19import (
Lorenz Brun878f5f92020-05-12 16:15:39 +020020 "context"
21 "crypto/ed25519"
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010022 "errors"
23 "net"
24
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +020025 "go.etcd.io/etcd/clientv3"
26 "go.uber.org/zap"
Lorenz Brun878f5f92020-05-12 16:15:39 +020027 "google.golang.org/grpc/codes"
28 "google.golang.org/grpc/status"
29
30 schema "git.monogon.dev/source/nexantic.git/core/generated/api"
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +020031 "git.monogon.dev/source/nexantic.git/core/internal/common/supervisor"
Hendrik Hofstadt8efe51e2020-02-28 12:53:41 +010032 "git.monogon.dev/source/nexantic.git/core/internal/consensus"
Lorenz Brun0db90ba2020-04-06 14:04:52 +020033 "git.monogon.dev/source/nexantic.git/core/internal/storage"
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +020034 "git.monogon.dev/source/nexantic.git/core/pkg/logbuffer"
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010035)
36
37type Config struct {
38 AdvertiseAddress net.IP
39 ServiceIPRange net.IPNet
40 ClusterNet net.IPNet
41}
42
43type Service struct {
Lorenz Brun878f5f92020-05-12 16:15:39 +020044 consensusService *consensus.Service
Lorenz Brun0db90ba2020-04-06 14:04:52 +020045 storageService *storage.Manager
Lorenz Brun878f5f92020-05-12 16:15:39 +020046 logger *zap.Logger
47 apiserverLogs *logbuffer.LogBuffer
48 controllerManagerLogs *logbuffer.LogBuffer
49 schedulerLogs *logbuffer.LogBuffer
50 kubeletLogs *logbuffer.LogBuffer
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010051}
52
Lorenz Brun0db90ba2020-04-06 14:04:52 +020053func New(logger *zap.Logger, consensusService *consensus.Service, storageService *storage.Manager) *Service {
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010054 s := &Service{
Lorenz Brun878f5f92020-05-12 16:15:39 +020055 consensusService: consensusService,
Lorenz Brun0db90ba2020-04-06 14:04:52 +020056 storageService: storageService,
Lorenz Brun878f5f92020-05-12 16:15:39 +020057 logger: logger,
58 apiserverLogs: logbuffer.New(5000, 16384),
59 controllerManagerLogs: logbuffer.New(5000, 16384),
60 schedulerLogs: logbuffer.New(5000, 16384),
61 kubeletLogs: logbuffer.New(5000, 16384),
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010062 }
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010063 return s
64}
65
66func (s *Service) getKV() clientv3.KV {
67 return s.consensusService.GetStore("kubernetes", "")
68}
69
70func (s *Service) NewCluster() error {
71 return newCluster(s.getKV())
72}
73
Lorenz Brun878f5f92020-05-12 16:15:39 +020074// GetComponentLogs grabs logs from various Kubernetes binaries
75func (s *Service) GetComponentLogs(component string, n int) ([]string, error) {
76 switch component {
77 case "apiserver":
78 return s.apiserverLogs.ReadLinesTruncated(n, "..."), nil
79 case "controller-manager":
80 return s.controllerManagerLogs.ReadLinesTruncated(n, "..."), nil
81 case "scheduler":
82 return s.schedulerLogs.ReadLinesTruncated(n, "..."), nil
83 case "kubelet":
84 return s.kubeletLogs.ReadLinesTruncated(n, "..."), nil
85 default:
86 return []string{}, errors.New("component not available")
87 }
88}
89
90// GetDebugKubeconfig issues a kubeconfig for an arbitrary given identity. Useful for debugging and testing.
91func (s *Service) GetDebugKubeconfig(ctx context.Context, request *schema.GetDebugKubeconfigRequest) (*schema.GetDebugKubeconfigResponse, error) {
92 idCA, idKeyRaw, err := getCert(s.getKV(), "id-ca")
93 idKey := ed25519.PrivateKey(idKeyRaw)
94 if err != nil {
95 return nil, status.Errorf(codes.Unavailable, "Failed to load ID CA: %v", err)
96 }
97 debugCert, debugKey, err := issueCertificate(clientCertTemplate(request.Id, request.Groups), idCA, idKey)
98 if err != nil {
99 return nil, status.Errorf(codes.Unavailable, "Failed to issue certs for kubeconfig: %v\n", err)
100 }
101 debugKubeconfig, err := makeLocalKubeconfig(idCA, debugCert, debugKey)
102 if err != nil {
103 return nil, status.Errorf(codes.Unavailable, "Failed to generate kubeconfig: %v", err)
104 }
105 return &schema.GetDebugKubeconfigResponse{DebugKubeconfig: string(debugKubeconfig)}, nil
106}
107
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200108func (s *Service) Start() error {
109 // TODO(lorenz): This creates a new supervision tree, it should instead attach to the root one. But for that SmalltownNode needs
110 // to be ported to supervisor.
111 supervisor.New(context.TODO(), s.logger, s.Run())
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100112 return nil
113}
114
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200115func (s *Service) Run() supervisor.Runnable {
116 return func(ctx context.Context) error {
117 config := Config{
118 AdvertiseAddress: net.IP{10, 0, 2, 15}, // Depends on networking
119 ServiceIPRange: net.IPNet{ // TODO: Decide if configurable / final value
120 IP: net.IP{192, 168, 188, 0},
121 Mask: net.IPMask{0xff, 0xff, 0xff, 0x00}, // /24, but Go stores as a literal mask
122 },
123 ClusterNet: net.IPNet{
124 IP: net.IP{192, 168, 188, 0},
125 Mask: net.IPMask{0xff, 0xff, 0xfd, 0x00}, // /22
126 },
127 }
128 consensusKV := s.getKV()
129 apiserverConfig, err := getPKIApiserverConfig(consensusKV)
130 if err != nil {
131 return err
132 }
133 apiserverConfig.advertiseAddress = config.AdvertiseAddress
134 apiserverConfig.serviceIPRange = config.ServiceIPRange
135 controllerManagerConfig, err := getPKIControllerManagerConfig(consensusKV)
136 if err != nil {
137 return err
138 }
139 controllerManagerConfig.clusterNet = config.ClusterNet
140 schedulerConfig, err := getPKISchedulerConfig(consensusKV)
141 if err != nil {
142 return err
143 }
144
145 masterKubeconfig, err := getSingle(consensusKV, "master.kubeconfig")
146 if err != nil {
147 return err
148 }
149
150 if err := supervisor.Run(ctx, "apiserver", runAPIServer(*apiserverConfig, s.apiserverLogs)); err != nil {
151 return err
152 }
153 if err := supervisor.Run(ctx, "controller-manager", runControllerManager(*controllerManagerConfig, s.controllerManagerLogs)); err != nil {
154 return err
155 }
156 if err := supervisor.Run(ctx, "scheduler", runScheduler(*schedulerConfig, s.schedulerLogs)); err != nil {
157 return err
158 }
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200159 if err := supervisor.Run(ctx, "kubelet", runKubelet(&KubeletSpec{}, s.kubeletLogs)); err != nil {
160 return err
161 }
162 if err := supervisor.Run(ctx, "reconciler", runReconciler(masterKubeconfig)); err != nil {
163 return err
164 }
Lorenz Brun0db90ba2020-04-06 14:04:52 +0200165 if err := supervisor.Run(ctx, "csi-plugin", runCSIPlugin(s.storageService)); err != nil {
166 return err
167 }
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200168 supervisor.Signal(ctx, supervisor.SignalHealthy)
169 supervisor.Signal(ctx, supervisor.SignalDone)
170 return nil
171 }
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100172}