blob: 7ef6b1da1d863a817c15d882f64cc8c482f2f612 [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"
Lorenz Brunb15abad2020-04-16 11:17:12 +020024 "time"
25
26 "k8s.io/client-go/informers"
27 "k8s.io/client-go/tools/clientcmd"
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010028
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +020029 "go.etcd.io/etcd/clientv3"
30 "go.uber.org/zap"
Lorenz Brun878f5f92020-05-12 16:15:39 +020031 "google.golang.org/grpc/codes"
32 "google.golang.org/grpc/status"
Lorenz Brunb15abad2020-04-16 11:17:12 +020033 "k8s.io/client-go/kubernetes"
Lorenz Brun878f5f92020-05-12 16:15:39 +020034
35 schema "git.monogon.dev/source/nexantic.git/core/generated/api"
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +020036 "git.monogon.dev/source/nexantic.git/core/internal/common/supervisor"
Hendrik Hofstadt8efe51e2020-02-28 12:53:41 +010037 "git.monogon.dev/source/nexantic.git/core/internal/consensus"
Lorenz Brun0db90ba2020-04-06 14:04:52 +020038 "git.monogon.dev/source/nexantic.git/core/internal/storage"
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +020039 "git.monogon.dev/source/nexantic.git/core/pkg/logbuffer"
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010040)
41
42type Config struct {
43 AdvertiseAddress net.IP
44 ServiceIPRange net.IPNet
45 ClusterNet net.IPNet
46}
47
48type Service struct {
Lorenz Brun878f5f92020-05-12 16:15:39 +020049 consensusService *consensus.Service
Lorenz Brun0db90ba2020-04-06 14:04:52 +020050 storageService *storage.Manager
Lorenz Brun878f5f92020-05-12 16:15:39 +020051 logger *zap.Logger
52 apiserverLogs *logbuffer.LogBuffer
53 controllerManagerLogs *logbuffer.LogBuffer
54 schedulerLogs *logbuffer.LogBuffer
55 kubeletLogs *logbuffer.LogBuffer
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010056}
57
Lorenz Brun0db90ba2020-04-06 14:04:52 +020058func New(logger *zap.Logger, consensusService *consensus.Service, storageService *storage.Manager) *Service {
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010059 s := &Service{
Lorenz Brun878f5f92020-05-12 16:15:39 +020060 consensusService: consensusService,
Lorenz Brun0db90ba2020-04-06 14:04:52 +020061 storageService: storageService,
Lorenz Brun878f5f92020-05-12 16:15:39 +020062 logger: logger,
63 apiserverLogs: logbuffer.New(5000, 16384),
64 controllerManagerLogs: logbuffer.New(5000, 16384),
65 schedulerLogs: logbuffer.New(5000, 16384),
66 kubeletLogs: logbuffer.New(5000, 16384),
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010067 }
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010068 return s
69}
70
71func (s *Service) getKV() clientv3.KV {
72 return s.consensusService.GetStore("kubernetes", "")
73}
74
75func (s *Service) NewCluster() error {
76 return newCluster(s.getKV())
77}
78
Lorenz Brun878f5f92020-05-12 16:15:39 +020079// GetComponentLogs grabs logs from various Kubernetes binaries
80func (s *Service) GetComponentLogs(component string, n int) ([]string, error) {
81 switch component {
82 case "apiserver":
83 return s.apiserverLogs.ReadLinesTruncated(n, "..."), nil
84 case "controller-manager":
85 return s.controllerManagerLogs.ReadLinesTruncated(n, "..."), nil
86 case "scheduler":
87 return s.schedulerLogs.ReadLinesTruncated(n, "..."), nil
88 case "kubelet":
89 return s.kubeletLogs.ReadLinesTruncated(n, "..."), nil
90 default:
91 return []string{}, errors.New("component not available")
92 }
93}
94
95// GetDebugKubeconfig issues a kubeconfig for an arbitrary given identity. Useful for debugging and testing.
96func (s *Service) GetDebugKubeconfig(ctx context.Context, request *schema.GetDebugKubeconfigRequest) (*schema.GetDebugKubeconfigResponse, error) {
97 idCA, idKeyRaw, err := getCert(s.getKV(), "id-ca")
98 idKey := ed25519.PrivateKey(idKeyRaw)
99 if err != nil {
100 return nil, status.Errorf(codes.Unavailable, "Failed to load ID CA: %v", err)
101 }
102 debugCert, debugKey, err := issueCertificate(clientCertTemplate(request.Id, request.Groups), idCA, idKey)
103 if err != nil {
104 return nil, status.Errorf(codes.Unavailable, "Failed to issue certs for kubeconfig: %v\n", err)
105 }
106 debugKubeconfig, err := makeLocalKubeconfig(idCA, debugCert, debugKey)
107 if err != nil {
108 return nil, status.Errorf(codes.Unavailable, "Failed to generate kubeconfig: %v", err)
109 }
110 return &schema.GetDebugKubeconfigResponse{DebugKubeconfig: string(debugKubeconfig)}, nil
111}
112
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200113func (s *Service) Start() error {
114 // TODO(lorenz): This creates a new supervision tree, it should instead attach to the root one. But for that SmalltownNode needs
115 // to be ported to supervisor.
116 supervisor.New(context.TODO(), s.logger, s.Run())
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100117 return nil
118}
119
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200120func (s *Service) Run() supervisor.Runnable {
121 return func(ctx context.Context) error {
122 config := Config{
123 AdvertiseAddress: net.IP{10, 0, 2, 15}, // Depends on networking
124 ServiceIPRange: net.IPNet{ // TODO: Decide if configurable / final value
125 IP: net.IP{192, 168, 188, 0},
126 Mask: net.IPMask{0xff, 0xff, 0xff, 0x00}, // /24, but Go stores as a literal mask
127 },
128 ClusterNet: net.IPNet{
129 IP: net.IP{192, 168, 188, 0},
130 Mask: net.IPMask{0xff, 0xff, 0xfd, 0x00}, // /22
131 },
132 }
133 consensusKV := s.getKV()
134 apiserverConfig, err := getPKIApiserverConfig(consensusKV)
135 if err != nil {
136 return err
137 }
138 apiserverConfig.advertiseAddress = config.AdvertiseAddress
139 apiserverConfig.serviceIPRange = config.ServiceIPRange
140 controllerManagerConfig, err := getPKIControllerManagerConfig(consensusKV)
141 if err != nil {
142 return err
143 }
144 controllerManagerConfig.clusterNet = config.ClusterNet
145 schedulerConfig, err := getPKISchedulerConfig(consensusKV)
146 if err != nil {
147 return err
148 }
149
150 masterKubeconfig, err := getSingle(consensusKV, "master.kubeconfig")
151 if err != nil {
152 return err
153 }
154
Lorenz Brunb15abad2020-04-16 11:17:12 +0200155 rawClientConfig, err := clientcmd.NewClientConfigFromBytes(masterKubeconfig)
156 if err != nil {
157 return err
158 }
159
160 clientConfig, err := rawClientConfig.ClientConfig()
161 clientSet, err := kubernetes.NewForConfig(clientConfig)
162 if err != nil {
163 return err
164 }
165
166 informerFactory := informers.NewSharedInformerFactory(clientSet, 5*time.Minute)
167
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200168 if err := supervisor.Run(ctx, "apiserver", runAPIServer(*apiserverConfig, s.apiserverLogs)); err != nil {
169 return err
170 }
171 if err := supervisor.Run(ctx, "controller-manager", runControllerManager(*controllerManagerConfig, s.controllerManagerLogs)); err != nil {
172 return err
173 }
174 if err := supervisor.Run(ctx, "scheduler", runScheduler(*schedulerConfig, s.schedulerLogs)); err != nil {
175 return err
176 }
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200177 if err := supervisor.Run(ctx, "kubelet", runKubelet(&KubeletSpec{}, s.kubeletLogs)); err != nil {
178 return err
179 }
Lorenz Brunb15abad2020-04-16 11:17:12 +0200180 if err := supervisor.Run(ctx, "reconciler", runReconciler(clientSet)); err != nil {
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200181 return err
182 }
Lorenz Brun0db90ba2020-04-06 14:04:52 +0200183 if err := supervisor.Run(ctx, "csi-plugin", runCSIPlugin(s.storageService)); err != nil {
184 return err
185 }
Lorenz Brunb15abad2020-04-16 11:17:12 +0200186 if err := supervisor.Run(ctx, "pv-provisioner", runCSIProvisioner(s.storageService, clientSet, informerFactory)); err != nil {
187 return err
188 }
189
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200190 supervisor.Signal(ctx, supervisor.SignalHealthy)
191 supervisor.Signal(ctx, supervisor.SignalDone)
192 return nil
193 }
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100194}