blob: f95f03e5f75f8bf39528d74021bf0a98dfc84b93 [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 Bazanskie6030f62020-06-03 17:52:59 +020038 "git.monogon.dev/source/nexantic.git/core/internal/kubernetes/reconciler"
Lorenz Brun0db90ba2020-04-06 14:04:52 +020039 "git.monogon.dev/source/nexantic.git/core/internal/storage"
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +020040 "git.monogon.dev/source/nexantic.git/core/pkg/logbuffer"
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010041)
42
43type Config struct {
44 AdvertiseAddress net.IP
45 ServiceIPRange net.IPNet
46 ClusterNet net.IPNet
47}
48
49type Service struct {
Lorenz Brun878f5f92020-05-12 16:15:39 +020050 consensusService *consensus.Service
Lorenz Brun0db90ba2020-04-06 14:04:52 +020051 storageService *storage.Manager
Lorenz Brun878f5f92020-05-12 16:15:39 +020052 logger *zap.Logger
53 apiserverLogs *logbuffer.LogBuffer
54 controllerManagerLogs *logbuffer.LogBuffer
55 schedulerLogs *logbuffer.LogBuffer
56 kubeletLogs *logbuffer.LogBuffer
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010057}
58
Lorenz Brun0db90ba2020-04-06 14:04:52 +020059func New(logger *zap.Logger, consensusService *consensus.Service, storageService *storage.Manager) *Service {
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010060 s := &Service{
Lorenz Brun878f5f92020-05-12 16:15:39 +020061 consensusService: consensusService,
Lorenz Brun0db90ba2020-04-06 14:04:52 +020062 storageService: storageService,
Lorenz Brun878f5f92020-05-12 16:15:39 +020063 logger: logger,
64 apiserverLogs: logbuffer.New(5000, 16384),
65 controllerManagerLogs: logbuffer.New(5000, 16384),
66 schedulerLogs: logbuffer.New(5000, 16384),
67 kubeletLogs: logbuffer.New(5000, 16384),
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010068 }
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010069 return s
70}
71
72func (s *Service) getKV() clientv3.KV {
73 return s.consensusService.GetStore("kubernetes", "")
74}
75
76func (s *Service) NewCluster() error {
77 return newCluster(s.getKV())
78}
79
Lorenz Brun878f5f92020-05-12 16:15:39 +020080// GetComponentLogs grabs logs from various Kubernetes binaries
81func (s *Service) GetComponentLogs(component string, n int) ([]string, error) {
82 switch component {
83 case "apiserver":
84 return s.apiserverLogs.ReadLinesTruncated(n, "..."), nil
85 case "controller-manager":
86 return s.controllerManagerLogs.ReadLinesTruncated(n, "..."), nil
87 case "scheduler":
88 return s.schedulerLogs.ReadLinesTruncated(n, "..."), nil
89 case "kubelet":
90 return s.kubeletLogs.ReadLinesTruncated(n, "..."), nil
91 default:
92 return []string{}, errors.New("component not available")
93 }
94}
95
96// GetDebugKubeconfig issues a kubeconfig for an arbitrary given identity. Useful for debugging and testing.
97func (s *Service) GetDebugKubeconfig(ctx context.Context, request *schema.GetDebugKubeconfigRequest) (*schema.GetDebugKubeconfigResponse, error) {
98 idCA, idKeyRaw, err := getCert(s.getKV(), "id-ca")
99 idKey := ed25519.PrivateKey(idKeyRaw)
100 if err != nil {
101 return nil, status.Errorf(codes.Unavailable, "Failed to load ID CA: %v", err)
102 }
103 debugCert, debugKey, err := issueCertificate(clientCertTemplate(request.Id, request.Groups), idCA, idKey)
104 if err != nil {
105 return nil, status.Errorf(codes.Unavailable, "Failed to issue certs for kubeconfig: %v\n", err)
106 }
107 debugKubeconfig, err := makeLocalKubeconfig(idCA, debugCert, debugKey)
108 if err != nil {
109 return nil, status.Errorf(codes.Unavailable, "Failed to generate kubeconfig: %v", err)
110 }
111 return &schema.GetDebugKubeconfigResponse{DebugKubeconfig: string(debugKubeconfig)}, nil
112}
113
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200114func (s *Service) Start() error {
115 // TODO(lorenz): This creates a new supervision tree, it should instead attach to the root one. But for that SmalltownNode needs
116 // to be ported to supervisor.
117 supervisor.New(context.TODO(), s.logger, s.Run())
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100118 return nil
119}
120
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200121func (s *Service) Run() supervisor.Runnable {
122 return func(ctx context.Context) error {
123 config := Config{
124 AdvertiseAddress: net.IP{10, 0, 2, 15}, // Depends on networking
125 ServiceIPRange: net.IPNet{ // TODO: Decide if configurable / final value
126 IP: net.IP{192, 168, 188, 0},
127 Mask: net.IPMask{0xff, 0xff, 0xff, 0x00}, // /24, but Go stores as a literal mask
128 },
129 ClusterNet: net.IPNet{
130 IP: net.IP{192, 168, 188, 0},
131 Mask: net.IPMask{0xff, 0xff, 0xfd, 0x00}, // /22
132 },
133 }
134 consensusKV := s.getKV()
135 apiserverConfig, err := getPKIApiserverConfig(consensusKV)
136 if err != nil {
137 return err
138 }
139 apiserverConfig.advertiseAddress = config.AdvertiseAddress
140 apiserverConfig.serviceIPRange = config.ServiceIPRange
141 controllerManagerConfig, err := getPKIControllerManagerConfig(consensusKV)
142 if err != nil {
143 return err
144 }
145 controllerManagerConfig.clusterNet = config.ClusterNet
146 schedulerConfig, err := getPKISchedulerConfig(consensusKV)
147 if err != nil {
148 return err
149 }
150
151 masterKubeconfig, err := getSingle(consensusKV, "master.kubeconfig")
152 if err != nil {
153 return err
154 }
155
Lorenz Brunb15abad2020-04-16 11:17:12 +0200156 rawClientConfig, err := clientcmd.NewClientConfigFromBytes(masterKubeconfig)
157 if err != nil {
158 return err
159 }
160
161 clientConfig, err := rawClientConfig.ClientConfig()
162 clientSet, err := kubernetes.NewForConfig(clientConfig)
163 if err != nil {
164 return err
165 }
166
167 informerFactory := informers.NewSharedInformerFactory(clientSet, 5*time.Minute)
168
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200169 if err := supervisor.Run(ctx, "apiserver", runAPIServer(*apiserverConfig, s.apiserverLogs)); err != nil {
170 return err
171 }
172 if err := supervisor.Run(ctx, "controller-manager", runControllerManager(*controllerManagerConfig, s.controllerManagerLogs)); err != nil {
173 return err
174 }
175 if err := supervisor.Run(ctx, "scheduler", runScheduler(*schedulerConfig, s.schedulerLogs)); err != nil {
176 return err
177 }
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200178 if err := supervisor.Run(ctx, "kubelet", runKubelet(&KubeletSpec{}, s.kubeletLogs)); err != nil {
179 return err
180 }
Serge Bazanskie6030f62020-06-03 17:52:59 +0200181 if err := supervisor.Run(ctx, "reconciler", reconciler.Run(clientSet)); err != nil {
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200182 return err
183 }
Lorenz Brun0db90ba2020-04-06 14:04:52 +0200184 if err := supervisor.Run(ctx, "csi-plugin", runCSIPlugin(s.storageService)); err != nil {
185 return err
186 }
Lorenz Brunb15abad2020-04-16 11:17:12 +0200187 if err := supervisor.Run(ctx, "pv-provisioner", runCSIProvisioner(s.storageService, clientSet, informerFactory)); err != nil {
188 return err
189 }
190
Lorenz Brun8e3b8fc2020-05-19 14:29:40 +0200191 supervisor.Signal(ctx, supervisor.SignalHealthy)
192 supervisor.Signal(ctx, supervisor.SignalDone)
193 return nil
194 }
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100195}