blob: 5e282921c651d324c3fe6f035442585000f65b65 [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"
Lorenz Brun878f5f92020-05-12 16:15:39 +020023 "fmt"
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010024 "net"
25
Lorenz Brun878f5f92020-05-12 16:15:39 +020026 "google.golang.org/grpc/codes"
27 "google.golang.org/grpc/status"
28
29 schema "git.monogon.dev/source/nexantic.git/core/generated/api"
30 "git.monogon.dev/source/nexantic.git/core/pkg/logbuffer"
31
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010032 "go.etcd.io/etcd/clientv3"
33 "go.uber.org/zap"
Hendrik Hofstadt8efe51e2020-02-28 12:53:41 +010034
35 "git.monogon.dev/source/nexantic.git/core/internal/common/service"
36 "git.monogon.dev/source/nexantic.git/core/internal/consensus"
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010037)
38
39type Config struct {
40 AdvertiseAddress net.IP
41 ServiceIPRange net.IPNet
42 ClusterNet net.IPNet
43}
44
45type Service struct {
46 *service.BaseService
Lorenz Brun878f5f92020-05-12 16:15:39 +020047 consensusService *consensus.Service
48 logger *zap.Logger
49 apiserverLogs *logbuffer.LogBuffer
50 controllerManagerLogs *logbuffer.LogBuffer
51 schedulerLogs *logbuffer.LogBuffer
52 kubeletLogs *logbuffer.LogBuffer
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010053}
54
55func New(logger *zap.Logger, consensusService *consensus.Service) *Service {
56 s := &Service{
Lorenz Brun878f5f92020-05-12 16:15:39 +020057 consensusService: consensusService,
58 logger: logger,
59 apiserverLogs: logbuffer.New(5000, 16384),
60 controllerManagerLogs: logbuffer.New(5000, 16384),
61 schedulerLogs: logbuffer.New(5000, 16384),
62 kubeletLogs: logbuffer.New(5000, 16384),
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010063 }
64 s.BaseService = service.NewBaseService("kubernetes", logger, s)
65 return s
66}
67
68func (s *Service) getKV() clientv3.KV {
69 return s.consensusService.GetStore("kubernetes", "")
70}
71
72func (s *Service) NewCluster() error {
73 return newCluster(s.getKV())
74}
75
Lorenz Brun878f5f92020-05-12 16:15:39 +020076// GetComponentLogs grabs logs from various Kubernetes binaries
77func (s *Service) GetComponentLogs(component string, n int) ([]string, error) {
78 switch component {
79 case "apiserver":
80 return s.apiserverLogs.ReadLinesTruncated(n, "..."), nil
81 case "controller-manager":
82 return s.controllerManagerLogs.ReadLinesTruncated(n, "..."), nil
83 case "scheduler":
84 return s.schedulerLogs.ReadLinesTruncated(n, "..."), nil
85 case "kubelet":
86 return s.kubeletLogs.ReadLinesTruncated(n, "..."), nil
87 default:
88 return []string{}, errors.New("component not available")
89 }
90}
91
92// GetDebugKubeconfig issues a kubeconfig for an arbitrary given identity. Useful for debugging and testing.
93func (s *Service) GetDebugKubeconfig(ctx context.Context, request *schema.GetDebugKubeconfigRequest) (*schema.GetDebugKubeconfigResponse, error) {
94 idCA, idKeyRaw, err := getCert(s.getKV(), "id-ca")
95 idKey := ed25519.PrivateKey(idKeyRaw)
96 if err != nil {
97 return nil, status.Errorf(codes.Unavailable, "Failed to load ID CA: %v", err)
98 }
99 debugCert, debugKey, err := issueCertificate(clientCertTemplate(request.Id, request.Groups), idCA, idKey)
100 if err != nil {
101 return nil, status.Errorf(codes.Unavailable, "Failed to issue certs for kubeconfig: %v\n", err)
102 }
103 debugKubeconfig, err := makeLocalKubeconfig(idCA, debugCert, debugKey)
104 if err != nil {
105 return nil, status.Errorf(codes.Unavailable, "Failed to generate kubeconfig: %v", err)
106 }
107 return &schema.GetDebugKubeconfigResponse{DebugKubeconfig: string(debugKubeconfig)}, nil
108}
109
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100110func (s *Service) OnStart() error {
111 config := Config{
112 AdvertiseAddress: net.IP{10, 0, 2, 15}, // Depends on networking
113 ServiceIPRange: net.IPNet{ // TODO: Decide if configurable / final value
114 IP: net.IP{192, 168, 188, 0},
115 Mask: net.IPMask{0xff, 0xff, 0xff, 0x00}, // /24, but Go stores as a literal mask
116 },
117 ClusterNet: net.IPNet{
118 IP: net.IP{192, 168, 188, 0},
119 Mask: net.IPMask{0xff, 0xff, 0xfd, 0x00}, // /22
120 },
121 }
122 consensusKV := s.getKV()
123 apiserverConfig, err := getPKIApiserverConfig(consensusKV)
124 if err != nil {
125 return err
126 }
127 apiserverConfig.advertiseAddress = config.AdvertiseAddress
128 apiserverConfig.serviceIPRange = config.ServiceIPRange
129 controllerManagerConfig, err := getPKIControllerManagerConfig(consensusKV)
130 if err != nil {
131 return err
132 }
133 controllerManagerConfig.clusterNet = config.ClusterNet
134 schedulerConfig, err := getPKISchedulerConfig(consensusKV)
135 if err != nil {
136 return err
137 }
138
Lorenz Brun878f5f92020-05-12 16:15:39 +0200139 masterKubeconfig, err := getSingle(consensusKV, "master.kubeconfig")
140 if err != nil {
141 return err
142 }
143
144 // TODO(lorenz): Once internal/node is part of the supervisor tree, these should all be supervisor runnables
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100145 go func() {
Lorenz Brun878f5f92020-05-12 16:15:39 +0200146 s.runAPIServer(context.TODO(), *apiserverConfig)
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100147 }()
148 go func() {
Lorenz Brun878f5f92020-05-12 16:15:39 +0200149 s.runControllerManager(context.TODO(), *controllerManagerConfig)
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100150 }()
151 go func() {
Lorenz Brun878f5f92020-05-12 16:15:39 +0200152 s.runScheduler(context.TODO(), *schedulerConfig)
153 }()
154
155 go func() {
156 if err := s.runKubelet(context.TODO(), &KubeletSpec{}); err != nil {
157 fmt.Printf("Failed to launch kubelet: %v\n", err)
158 }
159 }()
160
161 go func() {
162 go runReconciler(context.TODO(), masterKubeconfig, s.logger)
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100163 }()
164
165 return nil
166}
167
168func (s *Service) OnStop() error {
169 // Requires advanced process management and not necessary for MVP
170 return errors.New("Not implemented")
171}