blob: efc72d3d12109655c69b95e28847cbce549fab09 [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
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020086 // Change system state
87 s.state = common.StateConfigured
88
89 s.logger.Info("New Cluster set up. Node is now fully operational")
90
91 return nil
92}
93
94func (s *SmalltownNode) EnterJoinClusterMode() error {
95 if s.state == common.StateConfigured {
96 return ErrAlreadySetup
97 }
98 s.state = common.StateClusterJoinMode
99
100 s.logger.Info("Node is now in the cluster join mode")
101
102 return nil
103}
104
Leopold Schabel68c58752019-11-14 21:00:59 +0100105func (s *SmalltownNode) JoinCluster(clusterString string, certs *api.ConsensusCertificates) error {
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +0200106 if s.state != common.StateClusterJoinMode {
107 return ErrNotInJoinMode
108 }
109
Leopold Schabel68c58752019-11-14 21:00:59 +0100110 s.logger.Info("Joining cluster", zap.String("cluster", clusterString))
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +0200111
112 err := s.SetupBackend()
113 if err != nil {
114 return err
115 }
116
117 config := s.Consensus.GetConfig()
Leopold Schabel68c58752019-11-14 21:00:59 +0100118 config.Name = s.hostname
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +0200119 config.InitialCluster = clusterString
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +0200120 s.Consensus.SetConfig(config)
Leopold Schabel68c58752019-11-14 21:00:59 +0100121 if err := s.Consensus.WriteCertificateFiles(certs); err != nil {
Lorenz Bruna4ea9d02019-10-31 11:40:30 +0100122 return err
123 }
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +0200124
125 // Start consensus
126 err = s.Consensus.Start()
127 if err != nil {
128 return err
129 }
130
131 s.state = common.StateConfigured
132
133 s.logger.Info("Joined cluster. Node is now syncing.")
134
135 return nil
136}