blob: ae18ff860c7ffa6b9e74041e80326382cd52933a [file] [log] [blame]
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +04001package installer
2
3import (
gio3af43942024-04-16 08:13:50 +04004 "bytes"
5 "encoding/json"
6 "errors"
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +04007 "fmt"
gio3af43942024-04-16 08:13:50 +04008 "io/fs"
gio3af43942024-04-16 08:13:50 +04009 "net/http"
10 "path"
Giorgi Lekveishvili6e813182023-06-30 13:45:30 +040011 "path/filepath"
gioe72b54f2024-04-22 10:44:41 +040012
13 "github.com/giolekva/pcloud/core/installer/io"
14 "github.com/giolekva/pcloud/core/installer/soft"
gio778577f2024-04-29 09:44:38 +040015
16 "sigs.k8s.io/yaml"
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +040017)
18
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040019const configFileName = "config.yaml"
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +040020const kustomizationFileName = "kustomization.yaml"
21
gio778577f2024-04-29 09:44:38 +040022var ErrorNotFound = errors.New("not found")
23
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +040024type AppManager struct {
gioe72b54f2024-04-22 10:44:41 +040025 repoIO soft.RepoIO
gio308105e2024-04-19 13:12:13 +040026 nsCreator NamespaceCreator
27 appDirRoot string
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +040028}
29
gioe72b54f2024-04-22 10:44:41 +040030func NewAppManager(repoIO soft.RepoIO, nsCreator NamespaceCreator, appDirRoot string) (*AppManager, error) {
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040031 return &AppManager{
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +040032 repoIO,
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +040033 nsCreator,
gio308105e2024-04-19 13:12:13 +040034 appDirRoot,
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040035 }, nil
36}
37
gioe72b54f2024-04-22 10:44:41 +040038func (m *AppManager) Config() (EnvConfig, error) {
39 var cfg EnvConfig
40 if err := soft.ReadYaml(m.repoIO, configFileName, &cfg); err != nil {
41 return EnvConfig{}, err
gio3af43942024-04-16 08:13:50 +040042 } else {
43 return cfg, nil
44 }
45}
46
gio3cdee592024-04-17 10:15:56 +040047func (m *AppManager) appConfig(path string) (AppInstanceConfig, error) {
48 var cfg AppInstanceConfig
gioe72b54f2024-04-22 10:44:41 +040049 if err := soft.ReadJson(m.repoIO, path, &cfg); err != nil {
gio3cdee592024-04-17 10:15:56 +040050 return AppInstanceConfig{}, err
gio3af43942024-04-16 08:13:50 +040051 } else {
52 return cfg, nil
53 }
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +040054}
55
gio308105e2024-04-19 13:12:13 +040056func (m *AppManager) FindAllInstances() ([]AppInstanceConfig, error) {
gio09a3e5b2024-04-26 14:11:06 +040057 m.repoIO.Pull()
gioe72b54f2024-04-22 10:44:41 +040058 kust, err := soft.ReadKustomization(m.repoIO, filepath.Join(m.appDirRoot, "kustomization.yaml"))
gio3af43942024-04-16 08:13:50 +040059 if err != nil {
60 return nil, err
61 }
gio3cdee592024-04-17 10:15:56 +040062 ret := make([]AppInstanceConfig, 0)
gio3af43942024-04-16 08:13:50 +040063 for _, app := range kust.Resources {
gio308105e2024-04-19 13:12:13 +040064 cfg, err := m.appConfig(filepath.Join(m.appDirRoot, app, "config.json"))
65 if err != nil {
66 return nil, err
67 }
68 cfg.Id = app
69 ret = append(ret, cfg)
70 }
71 return ret, nil
72}
73
74func (m *AppManager) FindAllAppInstances(name string) ([]AppInstanceConfig, error) {
gioe72b54f2024-04-22 10:44:41 +040075 kust, err := soft.ReadKustomization(m.repoIO, filepath.Join(m.appDirRoot, "kustomization.yaml"))
gio308105e2024-04-19 13:12:13 +040076 if err != nil {
77 return nil, err
78 }
79 ret := make([]AppInstanceConfig, 0)
80 for _, app := range kust.Resources {
81 cfg, err := m.appConfig(filepath.Join(m.appDirRoot, app, "config.json"))
gio3af43942024-04-16 08:13:50 +040082 if err != nil {
83 return nil, err
84 }
85 cfg.Id = app
86 if cfg.AppId == name {
87 ret = append(ret, cfg)
88 }
89 }
90 return ret, nil
Giorgi Lekveishvili76951482023-06-30 23:25:09 +040091}
92
gio778577f2024-04-29 09:44:38 +040093func (m *AppManager) FindInstance(id string) (*AppInstanceConfig, error) {
gioe72b54f2024-04-22 10:44:41 +040094 kust, err := soft.ReadKustomization(m.repoIO, filepath.Join(m.appDirRoot, "kustomization.yaml"))
gio3af43942024-04-16 08:13:50 +040095 if err != nil {
gio778577f2024-04-29 09:44:38 +040096 return nil, err
gio3af43942024-04-16 08:13:50 +040097 }
98 for _, app := range kust.Resources {
99 if app == id {
gio308105e2024-04-19 13:12:13 +0400100 cfg, err := m.appConfig(filepath.Join(m.appDirRoot, app, "config.json"))
gio3af43942024-04-16 08:13:50 +0400101 if err != nil {
gio778577f2024-04-29 09:44:38 +0400102 return nil, err
gio3af43942024-04-16 08:13:50 +0400103 }
104 cfg.Id = id
gio778577f2024-04-29 09:44:38 +0400105 return &cfg, nil
gio3af43942024-04-16 08:13:50 +0400106 }
107 }
gio778577f2024-04-29 09:44:38 +0400108 return nil, ErrorNotFound
Giorgi Lekveishvili76951482023-06-30 23:25:09 +0400109}
110
gio3cdee592024-04-17 10:15:56 +0400111func (m *AppManager) AppConfig(name string) (AppInstanceConfig, error) {
gio3cdee592024-04-17 10:15:56 +0400112 var cfg AppInstanceConfig
gioe72b54f2024-04-22 10:44:41 +0400113 if err := soft.ReadJson(m.repoIO, filepath.Join(m.appDirRoot, name, "config.json"), &cfg); err != nil {
gio3cdee592024-04-17 10:15:56 +0400114 return AppInstanceConfig{}, err
Giorgi Lekveishvili03ee5852023-05-30 13:20:10 +0400115 }
gio308105e2024-04-19 13:12:13 +0400116 return cfg, nil
Giorgi Lekveishvili03ee5852023-05-30 13:20:10 +0400117}
118
gio3af43942024-04-16 08:13:50 +0400119type allocatePortReq struct {
120 Protocol string `json:"protocol"`
121 SourcePort int `json:"sourcePort"`
122 TargetService string `json:"targetService"`
123 TargetPort int `json:"targetPort"`
124}
125
126func openPorts(ports []PortForward) error {
127 for _, p := range ports {
128 var buf bytes.Buffer
129 req := allocatePortReq{
130 Protocol: p.Protocol,
131 SourcePort: p.SourcePort,
132 TargetService: p.TargetService,
133 TargetPort: p.TargetPort,
134 }
135 if err := json.NewEncoder(&buf).Encode(req); err != nil {
136 return err
137 }
138 resp, err := http.Post(p.Allocator, "application/json", &buf)
139 if err != nil {
140 return err
141 }
142 if resp.StatusCode != http.StatusOK {
143 return fmt.Errorf("Could not allocate port %d, status code: %d", p.SourcePort, resp.StatusCode)
144 }
145 }
146 return nil
147}
148
gioe72b54f2024-04-22 10:44:41 +0400149func createKustomizationChain(r soft.RepoFS, path string) error {
gio3af43942024-04-16 08:13:50 +0400150 for p := filepath.Clean(path); p != "/"; {
151 parent, child := filepath.Split(p)
152 kustPath := filepath.Join(parent, "kustomization.yaml")
gioe72b54f2024-04-22 10:44:41 +0400153 kust, err := soft.ReadKustomization(r, kustPath)
gio3af43942024-04-16 08:13:50 +0400154 if err != nil {
155 if errors.Is(err, fs.ErrNotExist) {
gioe72b54f2024-04-22 10:44:41 +0400156 k := io.NewKustomization()
gio3af43942024-04-16 08:13:50 +0400157 kust = &k
158 } else {
159 return err
160 }
161 }
162 kust.AddResources(child)
gioe72b54f2024-04-22 10:44:41 +0400163 if err := soft.WriteYaml(r, kustPath, kust); err != nil {
gio3af43942024-04-16 08:13:50 +0400164 return err
165 }
166 p = filepath.Clean(parent)
167 }
168 return nil
169}
170
gio778577f2024-04-29 09:44:38 +0400171type Resource struct {
172 Name string `json:"name"`
173 Namespace string `json:"namespace"`
174}
175
176type ReleaseResources struct {
177 Helm []Resource
178}
179
gio3cdee592024-04-17 10:15:56 +0400180// TODO(gio): rename to CommitApp
gio0eaf2712024-04-14 13:08:46 +0400181func installApp(
gioe72b54f2024-04-22 10:44:41 +0400182 repo soft.RepoIO,
183 appDir string,
184 name string,
185 config any,
186 ports []PortForward,
187 resources CueAppData,
188 data CueAppData,
gio778577f2024-04-29 09:44:38 +0400189 opts ...soft.DoOption,
190) (ReleaseResources, error) {
gio778577f2024-04-29 09:44:38 +0400191 return ReleaseResources{}, repo.Do(func(r soft.RepoFS) (string, error) {
gio308105e2024-04-19 13:12:13 +0400192 if err := r.RemoveDir(appDir); err != nil {
193 return "", err
194 }
195 resourcesDir := path.Join(appDir, "resources")
196 if err := r.CreateDir(resourcesDir); err != nil {
gio3af43942024-04-16 08:13:50 +0400197 return "", err
198 }
199 {
gioe72b54f2024-04-22 10:44:41 +0400200 if err := soft.WriteYaml(r, path.Join(appDir, configFileName), config); err != nil {
gio3af43942024-04-16 08:13:50 +0400201 return "", err
202 }
gioe72b54f2024-04-22 10:44:41 +0400203 if err := soft.WriteJson(r, path.Join(appDir, "config.json"), config); err != nil {
gio308105e2024-04-19 13:12:13 +0400204 return "", err
205 }
gioe72b54f2024-04-22 10:44:41 +0400206 for name, contents := range data {
gio308105e2024-04-19 13:12:13 +0400207 if name == "config.json" || name == "kustomization.yaml" || name == "resources" {
208 return "", fmt.Errorf("%s is forbidden", name)
209 }
210 w, err := r.Writer(path.Join(appDir, name))
gio3af43942024-04-16 08:13:50 +0400211 if err != nil {
212 return "", err
213 }
gio308105e2024-04-19 13:12:13 +0400214 defer w.Close()
215 if _, err := w.Write(contents); err != nil {
gio3af43942024-04-16 08:13:50 +0400216 return "", err
217 }
218 }
gio308105e2024-04-19 13:12:13 +0400219 }
220 {
221 if err := createKustomizationChain(r, resourcesDir); err != nil {
222 return "", err
223 }
gioe72b54f2024-04-22 10:44:41 +0400224 appKust := io.NewKustomization()
225 for name, contents := range resources {
gio308105e2024-04-19 13:12:13 +0400226 appKust.AddResources(name)
227 w, err := r.Writer(path.Join(resourcesDir, name))
228 if err != nil {
229 return "", err
230 }
231 defer w.Close()
232 if _, err := w.Write(contents); err != nil {
233 return "", err
234 }
235 }
gioe72b54f2024-04-22 10:44:41 +0400236 if err := soft.WriteYaml(r, path.Join(resourcesDir, "kustomization.yaml"), appKust); err != nil {
gio3af43942024-04-16 08:13:50 +0400237 return "", err
238 }
239 }
gioe72b54f2024-04-22 10:44:41 +0400240 return fmt.Sprintf("install: %s", name), nil
gio308105e2024-04-19 13:12:13 +0400241 }, opts...)
gio3af43942024-04-16 08:13:50 +0400242}
243
gio3cdee592024-04-17 10:15:56 +0400244// TODO(gio): commit instanceId -> appDir mapping as well
gio0eaf2712024-04-14 13:08:46 +0400245func (m *AppManager) Install(app EnvApp, instanceId string, appDir string, namespace string, values map[string]any, opts ...InstallOption) (ReleaseResources, error) {
246 o := &installOptions{}
247 for _, i := range opts {
248 i(o)
249 }
gio3af43942024-04-16 08:13:50 +0400250 appDir = filepath.Clean(appDir)
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400251 if err := m.repoIO.Pull(); err != nil {
gio778577f2024-04-29 09:44:38 +0400252 return ReleaseResources{}, err
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400253 }
gio3cdee592024-04-17 10:15:56 +0400254 if err := m.nsCreator.Create(namespace); err != nil {
gio778577f2024-04-29 09:44:38 +0400255 return ReleaseResources{}, err
gio3cdee592024-04-17 10:15:56 +0400256 }
gio0eaf2712024-04-14 13:08:46 +0400257 var env EnvConfig
258 if o.Env != nil {
259 env = *o.Env
260 } else {
261 var err error
262 env, err = m.Config()
263 if err != nil {
264 return ReleaseResources{}, err
265 }
Giorgi Lekveishvili6e813182023-06-30 13:45:30 +0400266 }
gio3cdee592024-04-17 10:15:56 +0400267 release := Release{
268 AppInstanceId: instanceId,
269 Namespace: namespace,
270 RepoAddr: m.repoIO.FullAddress(),
271 AppDir: appDir,
272 }
273 rendered, err := app.Render(release, env, values)
gioef01fbb2024-04-12 16:52:59 +0400274 if err != nil {
gio778577f2024-04-29 09:44:38 +0400275 return ReleaseResources{}, err
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400276 }
gio0eaf2712024-04-14 13:08:46 +0400277 dopts := []soft.DoOption{}
278 if o.Branch != "" {
279 dopts = append(dopts, soft.WithForce())
280 dopts = append(dopts, soft.WithCommitToBranch(o.Branch))
281 }
282 if _, err := installApp(m.repoIO, appDir, rendered.Name, rendered.Config, rendered.Ports, rendered.Resources, rendered.Data, dopts...); err != nil {
gio778577f2024-04-29 09:44:38 +0400283 return ReleaseResources{}, err
284 }
gioff2a29a2024-05-01 17:06:42 +0400285 // TODO(gio): add ingress-nginx to release resources
286 if err := openPorts(rendered.Ports); err != nil {
287 return ReleaseResources{}, err
288 }
gio778577f2024-04-29 09:44:38 +0400289 return ReleaseResources{
290 Helm: extractHelm(rendered.Resources),
291 }, nil
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400292}
Giorgi Lekveishvili76951482023-06-30 23:25:09 +0400293
gio778577f2024-04-29 09:44:38 +0400294type helmRelease struct {
295 Metadata Resource `json:"metadata"`
gio0eaf2712024-04-14 13:08:46 +0400296 Kind string `json:"kind"`
gio778577f2024-04-29 09:44:38 +0400297 Status struct {
298 Conditions []struct {
299 Type string `json:"type"`
300 Status string `json:"status"`
301 } `json:"conditions"`
302 } `json:"status,omitempty"`
303}
304
305func extractHelm(resources CueAppData) []Resource {
306 ret := make([]Resource, 0, len(resources))
307 for _, contents := range resources {
308 var h helmRelease
309 if err := yaml.Unmarshal(contents, &h); err != nil {
310 panic(err) // TODO(gio): handle
311 }
gio0eaf2712024-04-14 13:08:46 +0400312 if h.Kind == "HelmRelease" {
313 ret = append(ret, h.Metadata)
314 }
gio778577f2024-04-29 09:44:38 +0400315 }
316 return ret
317}
318
319func (m *AppManager) Update(app EnvApp, instanceId string, values map[string]any, opts ...soft.DoOption) (ReleaseResources, error) {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400320 if err := m.repoIO.Pull(); err != nil {
gio778577f2024-04-29 09:44:38 +0400321 return ReleaseResources{}, err
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400322 }
gio3cdee592024-04-17 10:15:56 +0400323 env, err := m.Config()
Giorgi Lekveishvili76951482023-06-30 23:25:09 +0400324 if err != nil {
gio778577f2024-04-29 09:44:38 +0400325 return ReleaseResources{}, err
Giorgi Lekveishvili76951482023-06-30 23:25:09 +0400326 }
gio308105e2024-04-19 13:12:13 +0400327 instanceDir := filepath.Join(m.appDirRoot, instanceId)
328 instanceConfigPath := filepath.Join(instanceDir, "config.json")
gio3cdee592024-04-17 10:15:56 +0400329 config, err := m.appConfig(instanceConfigPath)
Giorgi Lekveishvili76951482023-06-30 23:25:09 +0400330 if err != nil {
gio778577f2024-04-29 09:44:38 +0400331 return ReleaseResources{}, err
Giorgi Lekveishvili76951482023-06-30 23:25:09 +0400332 }
gio3cdee592024-04-17 10:15:56 +0400333 release := Release{
334 AppInstanceId: instanceId,
335 Namespace: config.Release.Namespace,
336 RepoAddr: m.repoIO.FullAddress(),
337 AppDir: instanceDir,
338 }
339 rendered, err := app.Render(release, env, values)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400340 if err != nil {
gio778577f2024-04-29 09:44:38 +0400341 return ReleaseResources{}, err
Giorgi Lekveishvili76951482023-06-30 23:25:09 +0400342 }
gio0eaf2712024-04-14 13:08:46 +0400343 return installApp(m.repoIO, instanceDir, rendered.Name, rendered.Config, rendered.Ports, rendered.Resources, rendered.Data, opts...)
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400344}
345
346func (m *AppManager) Remove(instanceId string) error {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400347 if err := m.repoIO.Pull(); err != nil {
348 return err
349 }
gioe72b54f2024-04-22 10:44:41 +0400350 return m.repoIO.Do(func(r soft.RepoFS) (string, error) {
gio308105e2024-04-19 13:12:13 +0400351 r.RemoveDir(filepath.Join(m.appDirRoot, instanceId))
352 kustPath := filepath.Join(m.appDirRoot, "kustomization.yaml")
gioe72b54f2024-04-22 10:44:41 +0400353 kust, err := soft.ReadKustomization(r, kustPath)
gio3af43942024-04-16 08:13:50 +0400354 if err != nil {
355 return "", err
356 }
357 kust.RemoveResources(instanceId)
gioe72b54f2024-04-22 10:44:41 +0400358 soft.WriteYaml(r, kustPath, kust)
gio3af43942024-04-16 08:13:50 +0400359 return fmt.Sprintf("uninstall: %s", instanceId), nil
360 })
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400361}
362
Giorgi Lekveishvili67383962024-03-22 19:27:34 +0400363// TODO(gio): deduplicate with cue definition in app.go, this one should be removed.
gioe72b54f2024-04-22 10:44:41 +0400364func CreateNetworks(env EnvConfig) []Network {
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400365 return []Network{
366 {
367 Name: "Public",
gio3cdee592024-04-17 10:15:56 +0400368 IngressClass: fmt.Sprintf("%s-ingress-public", env.InfraName),
369 CertificateIssuer: fmt.Sprintf("%s-public", env.Id),
370 Domain: env.Domain,
371 AllocatePortAddr: fmt.Sprintf("http://port-allocator.%s-ingress-public.svc.cluster.local/api/allocate", env.InfraName),
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400372 },
373 {
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400374 Name: "Private",
gio3cdee592024-04-17 10:15:56 +0400375 IngressClass: fmt.Sprintf("%s-ingress-private", env.Id),
376 Domain: env.PrivateDomain,
377 AllocatePortAddr: fmt.Sprintf("http://port-allocator.%s-ingress-private.svc.cluster.local/api/allocate", env.Id),
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400378 },
379 }
Giorgi Lekveishvili76951482023-06-30 23:25:09 +0400380}
gio3cdee592024-04-17 10:15:56 +0400381
382// InfraAppmanager
383
384type InfraAppManager struct {
gioe72b54f2024-04-22 10:44:41 +0400385 repoIO soft.RepoIO
gio3cdee592024-04-17 10:15:56 +0400386 nsCreator NamespaceCreator
387}
388
gio0eaf2712024-04-14 13:08:46 +0400389type installOptions struct {
390 Env *EnvConfig
391 Branch string
392}
393
394type InstallOption func(*installOptions)
395
396func WithConfig(env *EnvConfig) InstallOption {
397 return func(o *installOptions) {
398 o.Env = env
399 }
400}
401
402func WithBranch(branch string) InstallOption {
403 return func(o *installOptions) {
404 o.Branch = branch
405 }
406}
407
gioe72b54f2024-04-22 10:44:41 +0400408func NewInfraAppManager(repoIO soft.RepoIO, nsCreator NamespaceCreator) (*InfraAppManager, error) {
gio3cdee592024-04-17 10:15:56 +0400409 return &InfraAppManager{
410 repoIO,
411 nsCreator,
412 }, nil
413}
414
415func (m *InfraAppManager) Config() (InfraConfig, error) {
416 var cfg InfraConfig
gioe72b54f2024-04-22 10:44:41 +0400417 if err := soft.ReadYaml(m.repoIO, configFileName, &cfg); err != nil {
gio3cdee592024-04-17 10:15:56 +0400418 return InfraConfig{}, err
419 } else {
420 return cfg, nil
421 }
422}
423
gioe72b54f2024-04-22 10:44:41 +0400424func (m *InfraAppManager) appConfig(path string) (InfraAppInstanceConfig, error) {
425 var cfg InfraAppInstanceConfig
426 if err := soft.ReadJson(m.repoIO, path, &cfg); err != nil {
427 return InfraAppInstanceConfig{}, err
428 } else {
429 return cfg, nil
430 }
431}
432
433func (m *InfraAppManager) FindInstance(id string) (InfraAppInstanceConfig, error) {
434 kust, err := soft.ReadKustomization(m.repoIO, filepath.Join("/infrastructure", "kustomization.yaml"))
435 if err != nil {
436 return InfraAppInstanceConfig{}, err
437 }
438 for _, app := range kust.Resources {
439 if app == id {
440 cfg, err := m.appConfig(filepath.Join("/infrastructure", app, "config.json"))
441 if err != nil {
442 return InfraAppInstanceConfig{}, err
443 }
444 cfg.Id = id
445 return cfg, nil
446 }
447 }
448 return InfraAppInstanceConfig{}, nil
449}
450
gio778577f2024-04-29 09:44:38 +0400451func (m *InfraAppManager) Install(app InfraApp, appDir string, namespace string, values map[string]any) (ReleaseResources, error) {
gio3cdee592024-04-17 10:15:56 +0400452 appDir = filepath.Clean(appDir)
453 if err := m.repoIO.Pull(); err != nil {
gio778577f2024-04-29 09:44:38 +0400454 return ReleaseResources{}, err
gio3cdee592024-04-17 10:15:56 +0400455 }
456 if err := m.nsCreator.Create(namespace); err != nil {
gio778577f2024-04-29 09:44:38 +0400457 return ReleaseResources{}, err
gio3cdee592024-04-17 10:15:56 +0400458 }
459 infra, err := m.Config()
460 if err != nil {
gio778577f2024-04-29 09:44:38 +0400461 return ReleaseResources{}, err
gio3cdee592024-04-17 10:15:56 +0400462 }
463 release := Release{
464 Namespace: namespace,
465 RepoAddr: m.repoIO.FullAddress(),
466 AppDir: appDir,
467 }
468 rendered, err := app.Render(release, infra, values)
469 if err != nil {
gio778577f2024-04-29 09:44:38 +0400470 return ReleaseResources{}, err
gio3cdee592024-04-17 10:15:56 +0400471 }
gio0eaf2712024-04-14 13:08:46 +0400472 return installApp(m.repoIO, appDir, rendered.Name, rendered.Config, rendered.Ports, rendered.Resources, rendered.Data)
gioe72b54f2024-04-22 10:44:41 +0400473}
474
gio778577f2024-04-29 09:44:38 +0400475func (m *InfraAppManager) Update(app InfraApp, instanceId string, values map[string]any, opts ...soft.DoOption) (ReleaseResources, error) {
gioe72b54f2024-04-22 10:44:41 +0400476 if err := m.repoIO.Pull(); err != nil {
gio778577f2024-04-29 09:44:38 +0400477 return ReleaseResources{}, err
gioe72b54f2024-04-22 10:44:41 +0400478 }
479 env, err := m.Config()
480 if err != nil {
gio778577f2024-04-29 09:44:38 +0400481 return ReleaseResources{}, err
gioe72b54f2024-04-22 10:44:41 +0400482 }
483 instanceDir := filepath.Join("/infrastructure", instanceId)
484 instanceConfigPath := filepath.Join(instanceDir, "config.json")
485 config, err := m.appConfig(instanceConfigPath)
486 if err != nil {
gio778577f2024-04-29 09:44:38 +0400487 return ReleaseResources{}, err
gioe72b54f2024-04-22 10:44:41 +0400488 }
489 release := Release{
490 AppInstanceId: instanceId,
491 Namespace: config.Release.Namespace,
492 RepoAddr: m.repoIO.FullAddress(),
493 AppDir: instanceDir,
494 }
495 rendered, err := app.Render(release, env, values)
496 if err != nil {
gio778577f2024-04-29 09:44:38 +0400497 return ReleaseResources{}, err
gioe72b54f2024-04-22 10:44:41 +0400498 }
gio0eaf2712024-04-14 13:08:46 +0400499 return installApp(m.repoIO, instanceDir, rendered.Name, rendered.Config, rendered.Ports, rendered.Resources, rendered.Data, opts...)
gio3cdee592024-04-17 10:15:56 +0400500}