Installer: Separate infrastructure and environment apps.
Have two separate application managers, one for installing apps on the
dodo infra, and nother installing on individual environments.
Change-Id: I1b24f008e30c5533c48c22ea92328bc4bb7abc54
diff --git a/core/installer/app_manager.go b/core/installer/app_manager.go
index e438a26..7e89eec 100644
--- a/core/installer/app_manager.go
+++ b/core/installer/app_manager.go
@@ -14,7 +14,7 @@
"sigs.k8s.io/yaml"
)
-const appDir = "/apps"
+const appDirRoot = "/apps"
const configFileName = "config.yaml"
const kustomizationFileName = "kustomization.yaml"
@@ -30,32 +30,32 @@
}, nil
}
-func (m *AppManager) Config() (Config, error) {
- var cfg Config
+func (m *AppManager) Config() (AppEnvConfig, error) {
+ var cfg AppEnvConfig
if err := ReadYaml(m.repoIO, configFileName, &cfg); err != nil {
- return Config{}, err
+ return AppEnvConfig{}, err
} else {
return cfg, nil
}
}
-func (m *AppManager) appConfig(path string) (AppConfig, error) {
- var cfg AppConfig
+func (m *AppManager) appConfig(path string) (AppInstanceConfig, error) {
+ var cfg AppInstanceConfig
if err := ReadYaml(m.repoIO, path, &cfg); err != nil {
- return AppConfig{}, err
+ return AppInstanceConfig{}, err
} else {
return cfg, nil
}
}
-func (m *AppManager) FindAllInstances(name string) ([]AppConfig, error) {
- kust, err := ReadKustomization(m.repoIO, filepath.Join(appDir, "kustomization.yaml"))
+func (m *AppManager) FindAllInstances(name string) ([]AppInstanceConfig, error) {
+ kust, err := ReadKustomization(m.repoIO, filepath.Join(appDirRoot, "kustomization.yaml"))
if err != nil {
return nil, err
}
- ret := make([]AppConfig, 0)
+ ret := make([]AppInstanceConfig, 0)
for _, app := range kust.Resources {
- cfg, err := m.appConfig(filepath.Join(appDir, app, "config.yaml"))
+ cfg, err := m.appConfig(filepath.Join(appDirRoot, app, "config.yaml"))
if err != nil {
return nil, err
}
@@ -67,34 +67,34 @@
return ret, nil
}
-func (m *AppManager) FindInstance(id string) (AppConfig, error) {
- kust, err := ReadKustomization(m.repoIO, filepath.Join(appDir, "kustomization.yaml"))
+func (m *AppManager) FindInstance(id string) (AppInstanceConfig, error) {
+ kust, err := ReadKustomization(m.repoIO, filepath.Join(appDirRoot, "kustomization.yaml"))
if err != nil {
- return AppConfig{}, err
+ return AppInstanceConfig{}, err
}
for _, app := range kust.Resources {
if app == id {
- cfg, err := m.appConfig(filepath.Join(appDir, app, "config.yaml"))
+ cfg, err := m.appConfig(filepath.Join(appDirRoot, app, "config.yaml"))
if err != nil {
- return AppConfig{}, err
+ return AppInstanceConfig{}, err
}
cfg.Id = id
return cfg, nil
}
}
- return AppConfig{}, nil
+ return AppInstanceConfig{}, nil
}
-func (m *AppManager) AppConfig(name string) (AppConfig, error) {
- configF, err := m.repoIO.Reader(filepath.Join(appDir, name, configFileName))
+func (m *AppManager) AppConfig(name string) (AppInstanceConfig, error) {
+ configF, err := m.repoIO.Reader(filepath.Join(appDirRoot, name, configFileName))
if err != nil {
- return AppConfig{}, err
+ return AppInstanceConfig{}, err
}
defer configF.Close()
- var cfg AppConfig
+ var cfg AppInstanceConfig
contents, err := ioutil.ReadAll(configF)
if err != nil {
- return AppConfig{}, err
+ return AppInstanceConfig{}, err
}
err = yaml.UnmarshalStrict(contents, &cfg)
return cfg, err
@@ -152,19 +152,8 @@
return nil
}
-func InstallApp(repo RepoIO, nsc NamespaceCreator, app App, appDir string, namespace string, initValues map[string]any, derived Derived) error {
- if err := nsc.Create(namespace); err != nil {
- return err
- }
- derived.Release = Release{
- Namespace: namespace,
- RepoAddr: repo.FullAddress(),
- AppDir: appDir,
- }
- rendered, err := app.Render(derived)
- if err != nil {
- return err
- }
+// TODO(gio): rename to CommitApp
+func InstallApp(repo RepoIO, appDir string, rendered Rendered) error {
if err := openPorts(rendered.Ports); err != nil {
return err
}
@@ -179,12 +168,7 @@
if err := r.CreateDir(appDir); err != nil {
return "", err
}
- cfg := AppConfig{
- AppId: app.Name(),
- Config: initValues,
- Derived: derived,
- }
- if err := WriteYaml(r, path.Join(appDir, configFileName), cfg); err != nil {
+ if err := WriteYaml(r, path.Join(appDir, configFileName), rendered.Config); err != nil {
return "", err
}
}
@@ -205,54 +189,61 @@
return "", err
}
}
- return fmt.Sprintf("install: %s", app.Name()), nil
+ return fmt.Sprintf("install: %s", rendered.Name), nil
})
}
-func (m *AppManager) Install(app App, appDir string, namespace string, values map[string]any) error {
+// TODO(gio): commit instanceId -> appDir mapping as well
+func (m *AppManager) Install(app EnvApp, instanceId string, appDir string, namespace string, values map[string]any) error {
appDir = filepath.Clean(appDir)
if err := m.repoIO.Pull(); err != nil {
return err
}
- globalConfig, err := m.Config()
+ if err := m.nsCreator.Create(namespace); err != nil {
+ return err
+ }
+ env, err := m.Config()
if err != nil {
return err
}
- derivedValues, err := deriveValues(values, app.Schema(), CreateNetworks(globalConfig))
+ release := Release{
+ AppInstanceId: instanceId,
+ Namespace: namespace,
+ RepoAddr: m.repoIO.FullAddress(),
+ AppDir: appDir,
+ }
+ rendered, err := app.Render(release, env, values)
if err != nil {
return err
}
- derived := Derived{
- Global: globalConfig.Values,
- Values: derivedValues,
- }
- return InstallApp(m.repoIO, m.nsCreator, app, appDir, namespace, values, derived)
+ return InstallApp(m.repoIO, appDir, rendered)
}
-func (m *AppManager) Update(app App, instanceId string, config map[string]any) error {
+func (m *AppManager) Update(app EnvApp, instanceId string, values map[string]any) error {
if err := m.repoIO.Pull(); err != nil {
return err
}
- globalConfig, err := m.Config()
+ env, err := m.Config()
if err != nil {
return err
}
- instanceDir := filepath.Join(appDir, instanceId)
+ instanceDir := filepath.Join(appDirRoot, instanceId)
instanceConfigPath := filepath.Join(instanceDir, configFileName)
- appConfig, err := m.appConfig(instanceConfigPath)
+ config, err := m.appConfig(instanceConfigPath)
if err != nil {
return err
}
- derivedValues, err := deriveValues(config, app.Schema(), CreateNetworks(globalConfig))
+ release := Release{
+ AppInstanceId: instanceId,
+ Namespace: config.Release.Namespace,
+ RepoAddr: m.repoIO.FullAddress(),
+ AppDir: instanceDir,
+ }
+ rendered, err := app.Render(release, env, values)
if err != nil {
return err
}
- derived := Derived{
- Global: globalConfig.Values,
- Release: appConfig.Derived.Release,
- Values: derivedValues,
- }
- return InstallApp(m.repoIO, m.nsCreator, app, instanceDir, appConfig.Derived.Release.Namespace, config, derived)
+ return InstallApp(m.repoIO, instanceDir, rendered)
}
func (m *AppManager) Remove(instanceId string) error {
@@ -260,8 +251,8 @@
return err
}
return m.repoIO.Atomic(func(r RepoFS) (string, error) {
- r.RemoveDir(filepath.Join(appDir, instanceId))
- kustPath := filepath.Join(appDir, "kustomization.yaml")
+ r.RemoveDir(filepath.Join(appDirRoot, instanceId))
+ kustPath := filepath.Join(appDirRoot, "kustomization.yaml")
kust, err := ReadKustomization(r, kustPath)
if err != nil {
return "", err
@@ -273,20 +264,67 @@
}
// TODO(gio): deduplicate with cue definition in app.go, this one should be removed.
-func CreateNetworks(global Config) []Network {
+func CreateNetworks(env AppEnvConfig) []Network {
return []Network{
{
Name: "Public",
- IngressClass: fmt.Sprintf("%s-ingress-public", global.Values.PCloudEnvName),
- CertificateIssuer: fmt.Sprintf("%s-public", global.Values.Id),
- Domain: global.Values.Domain,
- AllocatePortAddr: fmt.Sprintf("http://port-allocator.%s-ingress-public/api/allocate", global.Values.PCloudEnvName),
+ IngressClass: fmt.Sprintf("%s-ingress-public", env.InfraName),
+ CertificateIssuer: fmt.Sprintf("%s-public", env.Id),
+ Domain: env.Domain,
+ AllocatePortAddr: fmt.Sprintf("http://port-allocator.%s-ingress-public.svc.cluster.local/api/allocate", env.InfraName),
},
{
Name: "Private",
- IngressClass: fmt.Sprintf("%s-ingress-private", global.Values.Id),
- Domain: global.Values.PrivateDomain,
- AllocatePortAddr: fmt.Sprintf("http://port-allocator.%s-ingress-private/api/allocate", global.Values.Id),
+ IngressClass: fmt.Sprintf("%s-ingress-private", env.Id),
+ Domain: env.PrivateDomain,
+ AllocatePortAddr: fmt.Sprintf("http://port-allocator.%s-ingress-private.svc.cluster.local/api/allocate", env.Id),
},
}
}
+
+// InfraAppmanager
+
+type InfraAppManager struct {
+ repoIO RepoIO
+ nsCreator NamespaceCreator
+}
+
+func NewInfraAppManager(repoIO RepoIO, nsCreator NamespaceCreator) (*InfraAppManager, error) {
+ return &InfraAppManager{
+ repoIO,
+ nsCreator,
+ }, nil
+}
+
+func (m *InfraAppManager) Config() (InfraConfig, error) {
+ var cfg InfraConfig
+ if err := ReadYaml(m.repoIO, configFileName, &cfg); err != nil {
+ return InfraConfig{}, err
+ } else {
+ return cfg, nil
+ }
+}
+
+func (m *InfraAppManager) Install(app InfraApp, appDir string, namespace string, values map[string]any) error {
+ appDir = filepath.Clean(appDir)
+ if err := m.repoIO.Pull(); err != nil {
+ return err
+ }
+ if err := m.nsCreator.Create(namespace); err != nil {
+ return err
+ }
+ infra, err := m.Config()
+ if err != nil {
+ return err
+ }
+ release := Release{
+ Namespace: namespace,
+ RepoAddr: m.repoIO.FullAddress(),
+ AppDir: appDir,
+ }
+ rendered, err := app.Render(release, infra, values)
+ if err != nil {
+ return err
+ }
+ return InstallApp(m.repoIO, appDir, rendered)
+}