blob: 2f9b18ea636070cbe9bc9a244161a1c761d9668c [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"
Serge Bazanskidbfc6382020-06-19 20:35:43 +020021 "fmt"
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010022 "net"
Serge Bazanskidbfc6382020-06-19 20:35:43 +020023 "os"
Lorenz Brunb15abad2020-04-16 11:17:12 +020024 "time"
25
Lorenz Brun878f5f92020-05-12 16:15:39 +020026 "google.golang.org/grpc/codes"
27 "google.golang.org/grpc/status"
Lorenz Brunf042e6f2020-06-24 16:46:09 +020028 "k8s.io/client-go/informers"
Lorenz Brunb15abad2020-04-16 11:17:12 +020029 "k8s.io/client-go/kubernetes"
Lorenz Brunf042e6f2020-06-24 16:46:09 +020030 "k8s.io/client-go/tools/clientcmd"
Lorenz Brun878f5f92020-05-12 16:15:39 +020031
Serge Bazanski31370b02021-01-07 16:31:14 +010032 "source.monogon.dev/metropolis/node/core/localstorage"
33 "source.monogon.dev/metropolis/node/core/network/dns"
34 "source.monogon.dev/metropolis/node/kubernetes/clusternet"
35 "source.monogon.dev/metropolis/node/kubernetes/nfproxy"
36 "source.monogon.dev/metropolis/node/kubernetes/pki"
37 "source.monogon.dev/metropolis/node/kubernetes/reconciler"
38 "source.monogon.dev/metropolis/pkg/supervisor"
39 apb "source.monogon.dev/metropolis/proto/api"
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010040)
41
42type Config struct {
43 AdvertiseAddress net.IP
44 ServiceIPRange net.IPNet
45 ClusterNet net.IPNet
Serge Bazanskic2c7ad92020-07-13 17:20:09 +020046
Lorenz Brunfa5c2fc2020-09-28 13:32:12 +020047 KPKI *pki.KubernetesPKI
48 Root *localstorage.Root
49 CorednsRegistrationChan chan *dns.ExtraDirective
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010050}
51
Serge Bazanskic2c7ad92020-07-13 17:20:09 +020052type Service struct {
Serge Bazanski967be212020-11-02 11:26:59 +010053 c Config
Serge Bazanskic2c7ad92020-07-13 17:20:09 +020054}
Serge Bazanskidbfc6382020-06-19 20:35:43 +020055
Serge Bazanskic2c7ad92020-07-13 17:20:09 +020056func New(c Config) *Service {
57 s := &Service{
58 c: c,
59 }
60 return s
61}
62
Serge Bazanskic2c7ad92020-07-13 17:20:09 +020063func (s *Service) Run(ctx context.Context) error {
Serge Bazanskic2c7ad92020-07-13 17:20:09 +020064 controllerManagerConfig, err := getPKIControllerManagerConfig(ctx, s.c.KPKI)
65 if err != nil {
66 return fmt.Errorf("could not generate controller manager pki config: %w", err)
67 }
68 controllerManagerConfig.clusterNet = s.c.ClusterNet
69 schedulerConfig, err := getPKISchedulerConfig(ctx, s.c.KPKI)
70 if err != nil {
71 return fmt.Errorf("could not generate scheduler pki config: %w", err)
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010072 }
Serge Bazanskidbfc6382020-06-19 20:35:43 +020073
Serge Bazanskic2c7ad92020-07-13 17:20:09 +020074 masterKubeconfig, err := s.c.KPKI.Kubeconfig(ctx, pki.Master)
75 if err != nil {
76 return fmt.Errorf("could not generate master kubeconfig: %w", err)
77 }
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010078
Serge Bazanskic2c7ad92020-07-13 17:20:09 +020079 rawClientConfig, err := clientcmd.NewClientConfigFromBytes(masterKubeconfig)
80 if err != nil {
81 return fmt.Errorf("could not generate kubernetes client config: %w", err)
82 }
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010083
Serge Bazanskic2c7ad92020-07-13 17:20:09 +020084 clientConfig, err := rawClientConfig.ClientConfig()
85 clientSet, err := kubernetes.NewForConfig(clientConfig)
86 if err != nil {
87 return fmt.Errorf("could not generate kubernetes client: %w", err)
88 }
89
90 informerFactory := informers.NewSharedInformerFactory(clientSet, 5*time.Minute)
91
92 hostname, err := os.Hostname()
93 if err != nil {
94 return fmt.Errorf("failed to get hostname: %w", err)
95 }
96
Lorenz Brun339582b2020-07-29 18:13:35 +020097 dnsHostIP := s.c.AdvertiseAddress // TODO: Which IP to use
98
Serge Bazanskic2c7ad92020-07-13 17:20:09 +020099 apiserver := &apiserverService{
100 KPKI: s.c.KPKI,
101 AdvertiseAddress: s.c.AdvertiseAddress,
102 ServiceIPRange: s.c.ServiceIPRange,
Serge Bazanskic2c7ad92020-07-13 17:20:09 +0200103 EphemeralConsensusDirectory: &s.c.Root.Ephemeral.Consensus,
104 }
105
106 kubelet := kubeletService{
107 NodeName: hostname,
Lorenz Brun339582b2020-07-29 18:13:35 +0200108 ClusterDNS: []net.IP{dnsHostIP},
Serge Bazanskic2c7ad92020-07-13 17:20:09 +0200109 KubeletDirectory: &s.c.Root.Data.Kubernetes.Kubelet,
110 EphemeralDirectory: &s.c.Root.Ephemeral,
Serge Bazanskic2c7ad92020-07-13 17:20:09 +0200111 KPKI: s.c.KPKI,
112 }
113
114 csiPlugin := csiPluginServer{
115 KubeletDirectory: &s.c.Root.Data.Kubernetes.Kubelet,
116 VolumesDirectory: &s.c.Root.Data.Volumes,
117 }
118
119 csiProvisioner := csiProvisionerServer{
120 NodeName: hostname,
121 Kubernetes: clientSet,
122 InformerFactory: informerFactory,
123 VolumesDirectory: &s.c.Root.Data.Volumes,
124 }
125
126 clusternet := clusternet.Service{
127 NodeName: hostname,
128 Kubernetes: clientSet,
129 ClusterNet: s.c.ClusterNet,
130 InformerFactory: informerFactory,
131 DataDirectory: &s.c.Root.Data.Kubernetes.ClusterNetworking,
132 }
133
Lorenz Brunb682ba52020-07-08 14:51:36 +0200134 nfproxy := nfproxy.Service{
135 ClusterCIDR: s.c.ClusterNet,
136 ClientSet: clientSet,
137 }
138
Serge Bazanskic2c7ad92020-07-13 17:20:09 +0200139 for _, sub := range []struct {
140 name string
141 runnable supervisor.Runnable
142 }{
143 {"apiserver", apiserver.Run},
Serge Bazanski967be212020-11-02 11:26:59 +0100144 {"controller-manager", runControllerManager(*controllerManagerConfig)},
145 {"scheduler", runScheduler(*schedulerConfig)},
Serge Bazanskic2c7ad92020-07-13 17:20:09 +0200146 {"kubelet", kubelet.Run},
147 {"reconciler", reconciler.Run(clientSet)},
148 {"csi-plugin", csiPlugin.Run},
149 {"csi-provisioner", csiProvisioner.Run},
150 {"clusternet", clusternet.Run},
Lorenz Brunb682ba52020-07-08 14:51:36 +0200151 {"nfproxy", nfproxy.Run},
Serge Bazanskic2c7ad92020-07-13 17:20:09 +0200152 } {
153 err := supervisor.Run(ctx, sub.name, sub.runnable)
154 if err != nil {
155 return fmt.Errorf("could not run sub-service %q: %w", sub.name, err)
156 }
157 }
158
Lorenz Brunfa5c2fc2020-09-28 13:32:12 +0200159 supervisor.Logger(ctx).Info("Registering K8s CoreDNS")
160 clusterDNSDirective := dns.NewKubernetesDirective("cluster.local", masterKubeconfig)
161 s.c.CorednsRegistrationChan <- clusterDNSDirective
162
Serge Bazanskic2c7ad92020-07-13 17:20:09 +0200163 supervisor.Signal(ctx, supervisor.SignalHealthy)
Lorenz Brunfa5c2fc2020-09-28 13:32:12 +0200164 <-ctx.Done()
165 s.c.CorednsRegistrationChan <- dns.CancelDirective(clusterDNSDirective)
Serge Bazanskic2c7ad92020-07-13 17:20:09 +0200166 return nil
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100167}
168
Lorenz Brun878f5f92020-05-12 16:15:39 +0200169// GetDebugKubeconfig issues a kubeconfig for an arbitrary given identity. Useful for debugging and testing.
Serge Bazanskic2c7ad92020-07-13 17:20:09 +0200170func (s *Service) GetDebugKubeconfig(ctx context.Context, request *apb.GetDebugKubeconfigRequest) (*apb.GetDebugKubeconfigResponse, error) {
171 ca := s.c.KPKI.Certificates[pki.IdCA]
172 debugKubeconfig, err := pki.New(ca, "", pki.Client(request.Id, request.Groups)).Kubeconfig(ctx, s.c.KPKI.KV)
Lorenz Brun878f5f92020-05-12 16:15:39 +0200173 if err != nil {
174 return nil, status.Errorf(codes.Unavailable, "Failed to generate kubeconfig: %v", err)
175 }
Serge Bazanskic2c7ad92020-07-13 17:20:09 +0200176 return &apb.GetDebugKubeconfigResponse{DebugKubeconfig: string(debugKubeconfig)}, nil
Lorenz Brun6e8f69c2019-11-18 10:44:24 +0100177}