blob: 151dd90febfc2a2ba950527fa5c44ffdf6d7e80d [file] [log] [blame]
giolekva8aa73e82022-07-09 11:34:39 +04001package main
2
3import (
4 "context"
5 "crypto/ed25519"
6 "crypto/rand"
7 "crypto/x509"
8 _ "embed"
9 "encoding/pem"
10 "fmt"
11 "golang.org/x/crypto/ssh"
12 "log"
13 "os"
14 "path/filepath"
15 "time"
16
17 "github.com/giolekva/pcloud/core/installer/soft"
18 "github.com/spf13/cobra"
19 "helm.sh/helm/v3/pkg/action"
20 "helm.sh/helm/v3/pkg/chart/loader"
21 "helm.sh/helm/v3/pkg/kube"
22)
23
24var bootstrapFlags struct {
25 chartsDir string
26 adminPubKey string
27 adminPrivKey string
28}
29
30func bootstrapCmd() *cobra.Command {
31 cmd := &cobra.Command{
32 Use: "bootstrap",
33 RunE: bootstrapCmdRun,
34 }
35 cmd.Flags().StringVar(
36 &bootstrapFlags.chartsDir,
37 "charts-dir",
38 "",
39 "",
40 )
41 cmd.Flags().StringVar(
42 &bootstrapFlags.adminPubKey,
43 "admin-pub-key",
44 "",
45 "",
46 )
47 cmd.Flags().StringVar(
48 &bootstrapFlags.adminPrivKey,
49 "admin-priv-key",
50 "",
51 "",
52 )
53 return cmd
54}
55
56func bootstrapCmdRun(cmd *cobra.Command, args []string) error {
57 adminPubKey, adminPrivKey, err := readAdminKeys()
58 if err != nil {
59 return err
60 }
61 fluxPub, fluxPriv, err := generateSSHKeys()
62 if err != nil {
63 return err
64 }
65 softServePub, softServePriv, err := generateSSHKeys()
66 if err != nil {
67 return err
68 }
69 fmt.Println("Installing SoftServe")
70 if err := installSoftServe(softServePub, softServePriv, string(adminPubKey)); err != nil {
71 return err
72 }
73 time.Sleep(30 * time.Second)
74 ss, err := soft.NewClient("192.168.0.208", 22, adminPrivKey, log.Default())
75 if err != nil {
76 return err
77 }
78 if err := ss.UpdateConfig(
79 soft.DefaultConfig([]string{string(adminPubKey), fluxPub}),
80 "set admin keys"); err != nil {
81 return err
82 }
83 if err := ss.ReloadConfig(); err != nil {
84 return err
85 }
86 fmt.Println("Creating /pcloud repo")
87 if err := ss.AddRepository("pcloud", "# PCloud Systems\n"); err != nil {
88 return err
89 }
90 fmt.Println("Installing Flux")
91 if err := installFlux("ssh://soft-serve.pcloud.svc.cluster.local:22/pcloud", "soft-serve.pcloud.svc.cluster.local", softServePub, fluxPriv); err != nil {
92 return err
93 }
94 return nil
95}
96
97func installSoftServe(pubKey, privKey, adminKey string) error {
98 config, err := createActionConfig()
99 if err != nil {
100 return err
101 }
102 chart, err := loader.Load(filepath.Join(bootstrapFlags.chartsDir, "soft-serve"))
103 if err != nil {
104 return err
105 }
106 values := map[string]interface{}{
107 "privateKey": privKey,
108 "publicKey": pubKey,
109 "adminKey": adminKey,
110 }
111 installer := action.NewInstall(config)
112 installer.Namespace = "pcloud"
113 installer.CreateNamespace = true
114 installer.ReleaseName = "soft-serve"
115 installer.Wait = true
116 installer.Timeout = 5 * time.Minute
117 if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
118 return err
119 }
120 return nil
121}
122
123func installFlux(repoAddr, repoHost, repoHostPubKey, privateKey string) error {
124 config, err := createActionConfig()
125 if err != nil {
126 return err
127 }
128 chart, err := loader.Load(filepath.Join(bootstrapFlags.chartsDir, "flux-bootstrap"))
129 if err != nil {
130 return err
131 }
132 values := map[string]interface{}{
133 "repositoryAddress": repoAddr,
134 "repositoryHost": repoHost,
135 "repositoryHostPublicKey": repoHostPubKey,
136 "privateKey": privateKey,
137 }
138 installer := action.NewInstall(config)
139 installer.Namespace = "pcloud"
140 installer.CreateNamespace = true
141 installer.ReleaseName = "flux"
142 installer.Wait = true
143 installer.WaitForJobs = true
144 installer.Timeout = 5 * time.Minute
145 if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
146 return err
147 }
148 return nil
149}
150
151func createActionConfig() (*action.Configuration, error) {
152 config := new(action.Configuration)
153 if err := config.Init(
154 kube.GetConfig(rootFlags.kubeConfig, "", ""),
155 "pcloud",
156 "",
157 func(fmtString string, args ...interface{}) {
158 fmt.Printf(fmtString, args...)
159 fmt.Println()
160 },
161 ); err != nil {
162 return nil, err
163 }
164 return config, nil
165}
166
167func generateSSHKeys() (string, string, error) {
168 pub, priv, err := ed25519.GenerateKey(rand.Reader)
169 if err != nil {
170 return "", "", err
171 }
172 privEnc, err := x509.MarshalPKCS8PrivateKey(priv)
173 if err != nil {
174 return "", "", err
175 }
176 privPem := pem.EncodeToMemory(
177 &pem.Block{
178 Type: "PRIVATE KEY",
179 Bytes: privEnc,
180 },
181 )
182 pubKey, err := ssh.NewPublicKey(pub)
183 if err != nil {
184 return "", "", err
185 }
186 return string(ssh.MarshalAuthorizedKey(pubKey)), string(privPem), nil
187}
188
189func readAdminKeys() ([]byte, []byte, error) {
190 pubKey, err := os.ReadFile(bootstrapFlags.adminPubKey)
191 if err != nil {
192 return nil, nil, err
193 }
194 privKey, err := os.ReadFile(bootstrapFlags.adminPrivKey)
195 if err != nil {
196 return nil, nil, err
197 }
198 return pubKey, privKey, nil
199}