blob: b8c3cf8fe07a31ff26159d4dcd9eea83321018f2 [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"
Serge Bazanski5a091422020-06-22 14:01:45 +020038 "git.monogon.dev/source/nexantic.git/core/internal/kubernetes/pki"
Serge Bazanskie6030f62020-06-03 17:52:59 +020039 "git.monogon.dev/source/nexantic.git/core/internal/kubernetes/reconciler"
Lorenz Brun0db90ba2020-04-06 14:04:52 +020040 "git.monogon.dev/source/nexantic.git/core/internal/storage"
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +020041 "git.monogon.dev/source/nexantic.git/core/pkg/logbuffer"
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010042)
43
44type Config struct {
45 AdvertiseAddress net.IP
46 ServiceIPRange net.IPNet
47 ClusterNet net.IPNet
48}
49
50type Service struct {
Lorenz Brun878f5f92020-05-12 16:15:39 +020051 consensusService *consensus.Service
Lorenz Brun0db90ba2020-04-06 14:04:52 +020052 storageService *storage.Manager
Lorenz Brun878f5f92020-05-12 16:15:39 +020053 logger *zap.Logger
54 apiserverLogs *logbuffer.LogBuffer
55 controllerManagerLogs *logbuffer.LogBuffer
56 schedulerLogs *logbuffer.LogBuffer
57 kubeletLogs *logbuffer.LogBuffer
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010058}
59
Lorenz Brun0db90ba2020-04-06 14:04:52 +020060func New(logger *zap.Logger, consensusService *consensus.Service, storageService *storage.Manager) *Service {
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010061 s := &Service{
Lorenz Brun878f5f92020-05-12 16:15:39 +020062 consensusService: consensusService,
Lorenz Brun0db90ba2020-04-06 14:04:52 +020063 storageService: storageService,
Lorenz Brun878f5f92020-05-12 16:15:39 +020064 logger: logger,
65 apiserverLogs: logbuffer.New(5000, 16384),
66 controllerManagerLogs: logbuffer.New(5000, 16384),
67 schedulerLogs: logbuffer.New(5000, 16384),
68 kubeletLogs: logbuffer.New(5000, 16384),
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010069 }
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010070 return s
71}
72
73func (s *Service) getKV() clientv3.KV {
74 return s.consensusService.GetStore("kubernetes", "")
75}
76
77func (s *Service) NewCluster() error {
Serge Bazanski5a091422020-06-22 14:01:45 +020078 return pki.NewCluster(s.getKV())
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010079}
80
Lorenz Brun878f5f92020-05-12 16:15:39 +020081// GetComponentLogs grabs logs from various Kubernetes binaries
82func (s *Service) GetComponentLogs(component string, n int) ([]string, error) {
83 switch component {
84 case "apiserver":
85 return s.apiserverLogs.ReadLinesTruncated(n, "..."), nil
86 case "controller-manager":
87 return s.controllerManagerLogs.ReadLinesTruncated(n, "..."), nil
88 case "scheduler":
89 return s.schedulerLogs.ReadLinesTruncated(n, "..."), nil
90 case "kubelet":
91 return s.kubeletLogs.ReadLinesTruncated(n, "..."), nil
92 default:
93 return []string{}, errors.New("component not available")
94 }
95}
96
97// GetDebugKubeconfig issues a kubeconfig for an arbitrary given identity. Useful for debugging and testing.
98func (s *Service) GetDebugKubeconfig(ctx context.Context, request *schema.GetDebugKubeconfigRequest) (*schema.GetDebugKubeconfigResponse, error) {
Lorenz Brunfc5dbc62020-05-28 12:18:07 +020099 if !s.consensusService.IsReady() {
100 return nil, status.Error(codes.Unavailable, "Consensus not ready yet")
101 }
Serge Bazanski5a091422020-06-22 14:01:45 +0200102 idCA, idKeyRaw, err := pki.GetCert(s.getKV(), "id-ca")
Lorenz Brun878f5f92020-05-12 16:15:39 +0200103 idKey := ed25519.PrivateKey(idKeyRaw)
104 if err != nil {
105 return nil, status.Errorf(codes.Unavailable, "Failed to load ID CA: %v", err)
106 }
Serge Bazanski5a091422020-06-22 14:01:45 +0200107 debugCert, debugKey, err := pki.IssueCertificate(pki.ClientCertTemplate(request.Id, request.Groups), idCA, idKey)
Lorenz Brun878f5f92020-05-12 16:15:39 +0200108 if err != nil {
109 return nil, status.Errorf(codes.Unavailable, "Failed to issue certs for kubeconfig: %v\n", err)
110 }
Serge Bazanski5a091422020-06-22 14:01:45 +0200111 debugKubeconfig, err := pki.MakeLocalKubeconfig(idCA, debugCert, debugKey)
Lorenz Brun878f5f92020-05-12 16:15:39 +0200112 if err != nil {
113 return nil, status.Errorf(codes.Unavailable, "Failed to generate kubeconfig: %v", err)
114 }
115 return &schema.GetDebugKubeconfigResponse{DebugKubeconfig: string(debugKubeconfig)}, nil
116}
117
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200118func (s *Service) Start() error {
119 // TODO(lorenz): This creates a new supervision tree, it should instead attach to the root one. But for that SmalltownNode needs
120 // to be ported to supervisor.
121 supervisor.New(context.TODO(), s.logger, s.Run())
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100122 return nil
123}
124
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200125func (s *Service) Run() supervisor.Runnable {
126 return func(ctx context.Context) error {
127 config := Config{
128 AdvertiseAddress: net.IP{10, 0, 2, 15}, // Depends on networking
129 ServiceIPRange: net.IPNet{ // TODO: Decide if configurable / final value
130 IP: net.IP{192, 168, 188, 0},
131 Mask: net.IPMask{0xff, 0xff, 0xff, 0x00}, // /24, but Go stores as a literal mask
132 },
133 ClusterNet: net.IPNet{
134 IP: net.IP{192, 168, 188, 0},
135 Mask: net.IPMask{0xff, 0xff, 0xfd, 0x00}, // /22
136 },
137 }
138 consensusKV := s.getKV()
139 apiserverConfig, err := getPKIApiserverConfig(consensusKV)
140 if err != nil {
141 return err
142 }
143 apiserverConfig.advertiseAddress = config.AdvertiseAddress
144 apiserverConfig.serviceIPRange = config.ServiceIPRange
145 controllerManagerConfig, err := getPKIControllerManagerConfig(consensusKV)
146 if err != nil {
147 return err
148 }
149 controllerManagerConfig.clusterNet = config.ClusterNet
150 schedulerConfig, err := getPKISchedulerConfig(consensusKV)
151 if err != nil {
152 return err
153 }
154
Serge Bazanski5a091422020-06-22 14:01:45 +0200155 masterKubeconfig, err := pki.GetSingle(consensusKV, "master.kubeconfig")
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200156 if err != nil {
157 return err
158 }
159
Lorenz Brunb15abad2020-04-16 11:17:12 +0200160 rawClientConfig, err := clientcmd.NewClientConfigFromBytes(masterKubeconfig)
161 if err != nil {
162 return err
163 }
164
165 clientConfig, err := rawClientConfig.ClientConfig()
166 clientSet, err := kubernetes.NewForConfig(clientConfig)
167 if err != nil {
168 return err
169 }
170
171 informerFactory := informers.NewSharedInformerFactory(clientSet, 5*time.Minute)
172
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200173 if err := supervisor.Run(ctx, "apiserver", runAPIServer(*apiserverConfig, s.apiserverLogs)); err != nil {
174 return err
175 }
176 if err := supervisor.Run(ctx, "controller-manager", runControllerManager(*controllerManagerConfig, s.controllerManagerLogs)); err != nil {
177 return err
178 }
179 if err := supervisor.Run(ctx, "scheduler", runScheduler(*schedulerConfig, s.schedulerLogs)); err != nil {
180 return err
181 }
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200182 if err := supervisor.Run(ctx, "kubelet", runKubelet(&KubeletSpec{}, s.kubeletLogs)); err != nil {
183 return err
184 }
Serge Bazanskie6030f62020-06-03 17:52:59 +0200185 if err := supervisor.Run(ctx, "reconciler", reconciler.Run(clientSet)); err != nil {
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200186 return err
187 }
Lorenz Brun0db90ba2020-04-06 14:04:52 +0200188 if err := supervisor.Run(ctx, "csi-plugin", runCSIPlugin(s.storageService)); err != nil {
189 return err
190 }
Lorenz Brunb15abad2020-04-16 11:17:12 +0200191 if err := supervisor.Run(ctx, "pv-provisioner", runCSIProvisioner(s.storageService, clientSet, informerFactory)); err != nil {
192 return err
193 }
194
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200195 supervisor.Signal(ctx, supervisor.SignalHealthy)
196 supervisor.Signal(ctx, supervisor.SignalDone)
197 return nil
198 }
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100199}