blob: 045b25801abcfeaaf506d98f8495a7e56d6184dd [file] [log] [blame]
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +04001// TODO
2// * flux -n lekva create source git pcloud --url=ssh://192.168.0.211/pcloud-apps --branch=main --private-key-file=/Users/lekva/.ssh/id_rsa
3
giolekva8aa73e82022-07-09 11:34:39 +04004package main
5
6import (
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +04007 "embed"
8 "encoding/base64"
giolekva8aa73e82022-07-09 11:34:39 +04009 "fmt"
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +040010 "github.com/spf13/cobra"
giolekva8aa73e82022-07-09 11:34:39 +040011 "log"
12 "os"
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +040013 "path"
14 "text/template"
giolekva8aa73e82022-07-09 11:34:39 +040015
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +040016 "github.com/giolekva/pcloud/core/installer"
giolekva8aa73e82022-07-09 11:34:39 +040017 "github.com/giolekva/pcloud/core/installer/soft"
giolekva8aa73e82022-07-09 11:34:39 +040018)
19
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +040020//go:embed env-tmpl
21var filesTmpls embed.FS
22
giolekva8aa73e82022-07-09 11:34:39 +040023var createEnvFlags struct {
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +040024 name string
25 ip string
26 port int
27 adminPrivKey string
28 adminUsername string
giolekva8aa73e82022-07-09 11:34:39 +040029}
30
31func createEnvCmd() *cobra.Command {
32 cmd := &cobra.Command{
33 Use: "create-env",
34 RunE: createEnvCmdRun,
35 }
36 cmd.Flags().StringVar(
37 &createEnvFlags.name,
38 "name",
39 "",
40 "",
41 )
42 cmd.Flags().StringVar(
Giorgi Lekveishvili87be4ae2023-06-11 23:41:09 +040043 &createEnvFlags.ip,
44 "ip",
45 "",
46 "",
47 )
48 cmd.Flags().IntVar(
49 &createEnvFlags.port,
Giorgi Lekveishviliad59bfb2023-06-12 00:04:17 +040050 "port",
Giorgi Lekveishvili87be4ae2023-06-11 23:41:09 +040051 22,
52 "",
53 )
54 cmd.Flags().StringVar(
giolekva8aa73e82022-07-09 11:34:39 +040055 &createEnvFlags.adminPrivKey,
56 "admin-priv-key",
57 "",
58 "",
59 )
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +040060 cmd.Flags().StringVar(
61 &createEnvFlags.adminUsername,
62 "admin-username",
63 "",
64 "",
65 )
giolekva8aa73e82022-07-09 11:34:39 +040066 return cmd
67}
68
69func createEnvCmdRun(cmd *cobra.Command, args []string) error {
70 adminPrivKey, err := os.ReadFile(createEnvFlags.adminPrivKey)
71 if err != nil {
72 return err
73 }
Giorgi Lekveishvili87be4ae2023-06-11 23:41:09 +040074 ss, err := soft.NewClient(createEnvFlags.ip, createEnvFlags.port, adminPrivKey, log.Default())
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +040075 if err != nil {
76 return err
77 }
78 ssPubKey, err := ss.GetPublicKey()
79 if err != nil {
80 return err
81 }
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +040082 keys, err := installer.NewSSHKeyPair()
giolekva8aa73e82022-07-09 11:34:39 +040083 if err != nil {
84 return err
85 }
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +040086 if 1 == 2 {
87 readme := fmt.Sprintf("# %s PCloud environment", createEnvFlags.name)
88 if err := ss.AddRepository(createEnvFlags.name, readme); err != nil {
89 return err
90 }
91 fluxUserName := fmt.Sprintf("flux-%s", createEnvFlags.name)
92 if err := ss.AddUser(fluxUserName, keys.Public); err != nil {
93 return err
94 }
95 if err := ss.AddCollaborator(createEnvFlags.name, fluxUserName); err != nil {
96 return err
97 }
98 }
99 envRepo, err := ss.GetRepo(createEnvFlags.name)
100 if envRepo == nil {
giolekva8aa73e82022-07-09 11:34:39 +0400101 return err
102 }
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400103 if err := initEnvRepo(installer.NewRepoIO(envRepo, ss.Signer)); err != nil {
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400104 return err
105 }
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400106 if 1 == 2 {
107 repo, err := ss.GetRepo("pcloud")
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400108 if err != nil {
109 return err
110 }
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400111 repoIO := installer.NewRepoIO(repo, ss.Signer)
112 kust, err := repoIO.ReadKustomization("environments/kustomization.yaml")
113 if err != nil {
114 return err
115 }
116 kust.AddResources(createEnvFlags.name)
117 tmpls, err := template.ParseFS(filesTmpls, "env-tmpl/*.yaml")
118 if err != nil {
119 return err
120 }
121 for _, tmpl := range tmpls.Templates() {
122 dstPath := path.Join("environments", createEnvFlags.name, tmpl.Name())
123 dst, err := repoIO.Writer(dstPath)
124 if err != nil {
125 return err
126 }
127 defer dst.Close()
128 if err := tmpl.Execute(dst, map[string]string{
129 "Name": createEnvFlags.name,
130 "PrivateKey": base64.StdEncoding.EncodeToString([]byte(keys.Private)),
131 "PublicKey": base64.StdEncoding.EncodeToString([]byte(keys.Public)),
132 "GitHost": createEnvFlags.ip,
133 "KnownHosts": base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s %s", createEnvFlags.ip, ssPubKey))),
134 }); err != nil {
135 return err
136 }
137 }
138 if err := repoIO.WriteKustomization("environments/kustomization.yaml", *kust); err != nil {
139 return err
140 }
141 if err := repoIO.CommitAndPush(fmt.Sprintf("%s: initialize environment", createEnvFlags.name)); err != nil {
142 return err
143 }
144 }
145 return nil
146}
147
148func initEnvRepo(r installer.RepoIO) error {
149 appManager, err := installer.NewAppManager(r)
150 if err != nil {
151 return err
152 }
153 appsRepo := installer.NewInMemoryAppRepository(installer.CreateAllApps())
154 if 1 == 2 {
155 config := installer.Config{ // TODO(gioleka): configurable
156 Values: installer.Values{
157 PCloudEnvName: "pcloud",
158 Id: "lekva",
159 ContactEmail: "giolekva@gmail.com",
160 Domain: "lekva.me",
161 PrivateDomain: "p.lekva.me",
162 PublicIP: "46.49.35.44",
163 NamespacePrefix: "lekva-",
164 },
165 }
166 if err := r.WriteYaml("config.yaml", config); err != nil {
167 return err
168 }
169 {
170 out, err := r.Writer("pcloud-charts.yaml")
171 if err != nil {
172 return err
173 }
174 defer out.Close()
175 _, err = out.Write([]byte(`
176apiVersion: source.toolkit.fluxcd.io/v1beta2
177kind: GitRepository
178metadata:
179 name: pcloud
180 namespace: lekva
181spec:
182 interval: 1m0s
183 url: https://github.com/giolekva/pcloud
184 ref:
185 branch: main
186`))
187 if err != nil {
188 return err
189 }
190 }
191 rootKust := installer.NewKustomization()
192 rootKust.AddResources("pcloud-charts.yaml", "apps")
193 if err := r.WriteKustomization("kustomization.yaml", rootKust); err != nil {
194 return err
195 }
196 appsKust := installer.NewKustomization()
197 if err := r.WriteKustomization("apps/kustomization.yaml", appsKust); err != nil {
198 return err
199 }
200 r.CommitAndPush("initialize config")
201 {
202 app, err := appsRepo.Find("metallb-config-env")
203 if err != nil {
204 return err
205 }
206 if err := appManager.Install(*app, map[string]any{
207 "IngressPrivate": "10.1.0.1",
208 "Headscale": "10.1.0.2",
209 "SoftServe": "10.1.0.3",
210 "Rest": map[string]any{
211 "From": "10.1.0.100",
212 "To": "10.1.0.255",
213 },
214 }); err != nil {
215 return err
216 }
217 }
218 {
219 app, err := appsRepo.Find("ingress-private")
220 if err != nil {
221 return err
222 }
223 if err := appManager.Install(*app, map[string]any{
224 "GandiAPIToken": "", // TODO(gioleka): configurable
225 }); err != nil {
226 return err
227 }
228 }
229 {
230 app, err := appsRepo.Find("core-auth")
231 if err != nil {
232 return err
233 }
234 if err := appManager.Install(*app, map[string]any{
235 "Subdomain": "test", // TODO(giolekva): make core-auth chart actually use this
236 }); err != nil {
237 return err
238 }
239 }
240 }
241 {
242 app, err := appsRepo.Find("headscale")
243 if err != nil {
244 return err
245 }
246 if err := appManager.Install(*app, map[string]any{
247 "Subdomain": "headscale",
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400248 }); err != nil {
249 return err
250 }
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400251 }
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400252 if 1 == 2 {
253 {
254 app, err := appsRepo.Find("tailscale-proxy")
255 if err != nil {
256 return err
257 }
258 if err := appManager.Install(*app, map[string]any{
259 "Username": createEnvFlags.adminUsername,
260 "IPSubnet": "10.1.0.0/24",
261 }); err != nil {
262 return err
263 }
264 // TODO(giolekva): headscale accept routes
265 }
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400266 }
giolekva8aa73e82022-07-09 11:34:39 +0400267 return nil
268}