blob: dc794b396de5e8eeca63431a49bd8cd87a7bf8aa [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 api
18
19import (
20 "context"
21 "crypto/rand"
Lorenz Brunaa6b7342019-12-12 02:55:02 +010022 "encoding/base64"
23 "io"
24
25 "git.monogon.dev/source/nexantic.git/core/generated/api"
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020026 schema "git.monogon.dev/source/nexantic.git/core/generated/api"
Lorenz Brunaa6b7342019-12-12 02:55:02 +010027 "github.com/gogo/protobuf/proto"
28 "go.etcd.io/etcd/clientv3"
Serge Bazanski7ba31522020-02-03 16:08:19 +010029 "google.golang.org/grpc/codes"
30 "google.golang.org/grpc/status"
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020031
32 "go.uber.org/zap"
33)
34
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020035func (s *Server) AddNode(ctx context.Context, req *schema.AddNodeRequest) (*schema.AddNodeResponse, error) {
Lorenz Brunaa6b7342019-12-12 02:55:02 +010036 return nil, status.Error(codes.Unimplemented, "Unimplemented")
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020037}
38
Lorenz Brunaa6b7342019-12-12 02:55:02 +010039func (s *Server) RemoveNode(ctx context.Context, req *schema.RemoveNodeRequest) (*schema.RemoveNodeRequest, error) {
40 return nil, status.Error(codes.Unimplemented, "Unimplemented")
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020041}
42
Lorenz Brunaa6b7342019-12-12 02:55:02 +010043func (s *Server) ListNodes(ctx context.Context, req *schema.ListNodesRequest) (*schema.ListNodesResponse, error) {
44 store := s.getStore()
45 res, err := store.Get(ctx, "nodes/", clientv3.WithPrefix())
46 if err != nil {
47 return nil, status.Error(codes.Unavailable, "Consensus unavailable")
48 }
49 var resNodes []*api.Node
50 for _, nodeEntry := range res.Kvs {
51 var node api.Node
52 if err := proto.Unmarshal(nodeEntry.Value, &node); err != nil {
53 s.Logger.Error("Encountered invalid node data", zap.Error(err))
54 return nil, status.Error(codes.Internal, "Invalid data")
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020055 }
Lorenz Brunaa6b7342019-12-12 02:55:02 +010056 // Zero out Global Unlock Key, it's never supposed to leave the cluster
57 node.GlobalUnlockKey = []byte{}
58
59 resNodes = append(resNodes, &node)
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020060 }
61
Leopold Schabel68c58752019-11-14 21:00:59 +010062 return &schema.ListNodesResponse{
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +020063 Nodes: resNodes,
64 }, nil
65}
Lorenz Brunaa6b7342019-12-12 02:55:02 +010066
67func (s *Server) ListEnrolmentConfigs(ctx context.Context, req *api.ListEnrolmentConfigsRequest) (*api.ListEnrolmentConfigsResponse, error) {
68 return nil, status.Error(codes.Unimplemented, "Unimplemented")
69}
70
71func (s *Server) NewEnrolmentConfig(ctx context.Context, req *api.NewEnrolmentConfigRequest) (*api.NewEnrolmentConfigResponse, error) {
72 store := s.getStore()
73 token := make([]byte, 32)
74 if _, err := io.ReadFull(rand.Reader, token); err != nil {
75 return nil, status.Error(codes.Unavailable, "failed to get randonmess")
76 }
77 nodes, err := store.Get(ctx, "nodes/", clientv3.WithPrefix())
78 if err != nil {
79 return nil, status.Error(codes.Unavailable, "consensus unavailable")
80 }
81 var masterIPs [][]byte
82 for _, nodeKV := range nodes.Kvs {
83 var node api.Node
84 if err := proto.Unmarshal(nodeKV.Value, &node); err != nil {
85 return nil, status.Error(codes.Internal, "invalid node")
86 }
87 if node.State == api.Node_MASTER {
88 masterIPs = append(masterIPs, node.Address)
89 }
90 }
91 masterCert, err := s.GetMasterCert()
92 if err != nil {
93 return nil, status.Error(codes.Unavailable, "consensus unavailable")
94 }
95
96 enrolmentConfig := &api.EnrolmentConfig{
97 EnrolmentSecret: token,
98 MasterIps: masterIPs,
99 MastersCert: masterCert,
100 }
101 enrolmentConfigRaw, err := proto.Marshal(enrolmentConfig)
102 if err != nil {
103 return nil, status.Error(codes.Internal, "failed to encode config")
104 }
105 if _, err := store.Put(ctx, "enrolments/"+base64.RawURLEncoding.EncodeToString(token), string(enrolmentConfigRaw)); err != nil {
106 return nil, status.Error(codes.Unavailable, "consensus unavailable")
107 }
108 return &schema.NewEnrolmentConfigResponse{
109 EnrolmentConfig: enrolmentConfig,
110 }, nil
111}
112
113func (s *Server) RemoveEnrolmentConfig(ctx context.Context, req *api.RemoveEnrolmentConfigRequest) (*api.RemoveEnrolmentConfigResponse, error) {
114 return nil, status.Error(codes.Unimplemented, "Unimplemented")
115}