blob: 98873d389cdd1b8d4e419b516b9ba7160b8a9800 [file] [log] [blame]
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +02001// 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 node
18
19import (
Lorenz Bruna4ea9d02019-10-31 11:40:30 +010020 "git.monogon.dev/source/nexantic.git/core/generated/api"
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020021 "git.monogon.dev/source/nexantic.git/core/internal/common"
Leopold Schabel68c58752019-11-14 21:00:59 +010022 "git.monogon.dev/source/nexantic.git/core/internal/storage"
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020023
24 "errors"
Lorenz Bruna4ea9d02019-10-31 11:40:30 +010025
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020026 "go.uber.org/zap"
27)
28
29var (
30 ErrConsensusAlreadyProvisioned = errors.New("consensus is already provisioned; make sure the data folder is empty")
31 ErrAlreadySetup = errors.New("node is already set up")
32 ErrNotInJoinMode = errors.New("node is not in the cluster join mode")
33 ErrTrustNotInitialized = errors.New("trust backend not initialized")
34 ErrStorageNotInitialized = errors.New("storage not initialized")
35)
36
37func (s *SmalltownNode) CurrentState() common.SmalltownState {
38 return s.state
39}
40
41func (s *SmalltownNode) GetJoinClusterToken() string {
42 return s.joinToken
43}
44
Leopold Schabel68c58752019-11-14 21:00:59 +010045func (s *SmalltownNode) SetupNewCluster() error {
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020046 if s.state == common.StateConfigured {
47 return ErrAlreadySetup
48 }
Leopold Schabel68c58752019-11-14 21:00:59 +010049 dataPath, err := s.Storage.GetPathInPlace(storage.PlaceData, "etcd")
50 if err == storage.ErrNotInitialized {
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020051 return ErrStorageNotInitialized
52 } else if err != nil {
53 return err
54 }
55
Leopold Schabel68c58752019-11-14 21:00:59 +010056 s.logger.Info("Setting up a new cluster")
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020057 s.logger.Info("Provisioning consensus")
58
59 // Make sure etcd is not yet provisioned
60 if s.Consensus.IsProvisioned() {
61 return ErrConsensusAlreadyProvisioned
62 }
63
64 // Spin up etcd
65 config := s.Consensus.GetConfig()
66 config.NewCluster = true
Leopold Schabel68c58752019-11-14 21:00:59 +010067 config.Name = s.hostname
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020068 config.DataDir = dataPath
69 s.Consensus.SetConfig(config)
70
Leopold Schabel68c58752019-11-14 21:00:59 +010071 // Generate the cluster CA and store it to local storage.
Lorenz Bruna4ea9d02019-10-31 11:40:30 +010072 if err := s.Consensus.PrecreateCA(); err != nil {
73 return err
74 }
75
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020076 err = s.Consensus.Start()
77 if err != nil {
78 return err
79 }
80
Leopold Schabel68c58752019-11-14 21:00:59 +010081 // Now that the cluster is up and running, we can persist the CA to the cluster.
Lorenz Bruna4ea9d02019-10-31 11:40:30 +010082 if err := s.Consensus.InjectCA(); err != nil {
83 return err
84 }
85
Lorenz Brun6e8f69c2019-11-18 10:44:24 +010086 if err := s.Kubernetes.NewCluster(); err != nil {
87 return err
88 }
89
90 if err := s.Kubernetes.Start(); err != nil {
91 return err
92 }
93
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020094 // Change system state
95 s.state = common.StateConfigured
96
97 s.logger.Info("New Cluster set up. Node is now fully operational")
98
99 return nil
100}
101
102func (s *SmalltownNode) EnterJoinClusterMode() error {
103 if s.state == common.StateConfigured {
104 return ErrAlreadySetup
105 }
106 s.state = common.StateClusterJoinMode
107
108 s.logger.Info("Node is now in the cluster join mode")
109
110 return nil
111}
112
Leopold Schabel68c58752019-11-14 21:00:59 +0100113func (s *SmalltownNode) JoinCluster(clusterString string, certs *api.ConsensusCertificates) error {
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +0200114 if s.state != common.StateClusterJoinMode {
115 return ErrNotInJoinMode
116 }
117
Leopold Schabel68c58752019-11-14 21:00:59 +0100118 s.logger.Info("Joining cluster", zap.String("cluster", clusterString))
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +0200119
120 err := s.SetupBackend()
121 if err != nil {
122 return err
123 }
124
125 config := s.Consensus.GetConfig()
Leopold Schabel68c58752019-11-14 21:00:59 +0100126 config.Name = s.hostname
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +0200127 config.InitialCluster = clusterString
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +0200128 s.Consensus.SetConfig(config)
Leopold Schabel68c58752019-11-14 21:00:59 +0100129 if err := s.Consensus.WriteCertificateFiles(certs); err != nil {
Lorenz Bruna4ea9d02019-10-31 11:40:30 +0100130 return err
131 }
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +0200132
133 // Start consensus
134 err = s.Consensus.Start()
135 if err != nil {
136 return err
137 }
138
139 s.state = common.StateConfigured
140
141 s.logger.Info("Joined cluster. Node is now syncing.")
142
143 return nil
144}