AppManager: Handle new port forwards during app update
Change-Id: I72a4c5b7ec4bd5ba6ddd32cd3f33dce023d7d9ea
diff --git a/core/installer/app.go b/core/installer/app.go
index f830455..0b59ca1 100644
--- a/core/installer/app.go
+++ b/core/installer/app.go
@@ -494,7 +494,7 @@
for k, v := range v {
if v != nil {
if _, ok := d[k]; !ok {
- d[k] = v
+ ret[k] = v
}
}
}
@@ -519,7 +519,6 @@
if err != nil {
return EnvAppRendered{}, err
}
- // return EnvAppRendered{}, fmt.Errorf("asdasd")
if charts == nil {
charts = make(map[string]helmv2.HelmChartTemplateSpec)
}
diff --git a/core/installer/app_manager.go b/core/installer/app_manager.go
index 7995a41..d0faed4 100644
--- a/core/installer/app_manager.go
+++ b/core/installer/app_manager.go
@@ -10,6 +10,7 @@
"net/http"
"path"
"path/filepath"
+ "slices"
"strings"
"sync"
@@ -632,6 +633,9 @@
overrides CueAppData,
opts ...InstallOption,
) (ReleaseResources, error) {
+ if values == nil {
+ values = map[string]any{}
+ }
m.l.Lock()
defer m.l.Unlock()
if err := m.repo.Pull(); err != nil {
@@ -642,10 +646,29 @@
return ReleaseResources{}, err
}
instanceDir := filepath.Join(m.appDirRoot, instanceId)
- app, err := m.GetInstanceApp(instanceId, overrides)
+ oldApp, err := m.GetInstanceApp(instanceId, nil)
if err != nil {
return ReleaseResources{}, err
}
+ newApp, err := m.GetInstanceApp(instanceId, overrides)
+ if err != nil {
+ return ReleaseResources{}, err
+ }
+ oldPorts := findPortFields(oldApp.Schema())
+ newPorts := findPortFields(newApp.Schema())
+ portFields := []string{}
+ for _, np := range newPorts {
+ if !slices.Contains(oldPorts, np) {
+ portFields = append(portFields, np)
+ }
+ }
+ fakeReservations := map[string]reservePortResp{}
+ for i, f := range portFields {
+ fakeReservations[f] = reservePortResp{Port: i}
+ }
+ if err := setPortFields(values, fakeReservations); err != nil {
+ return ReleaseResources{}, err
+ }
instanceConfigPath := filepath.Join(instanceDir, "config.json")
config, err := m.appConfig(instanceConfigPath)
if err != nil {
@@ -663,7 +686,36 @@
if err != nil {
return ReleaseResources{}, err
}
- rendered, err := app.Render(config.Release, env, networks, ToAccessConfigs(clusters), merge(config.Input, values), renderedCfg.LocalCharts, m.vpnAPIClient)
+ rendered, err := newApp.Render(config.Release, env, networks, ToAccessConfigs(clusters), merge(config.Input, values), renderedCfg.LocalCharts, m.vpnAPIClient)
+ if err != nil {
+ return ReleaseResources{}, err
+ }
+ reservators := map[string]reservePortInfo{}
+ allocators := map[string]string{}
+ for _, pf := range rendered.Ports {
+ found := false
+ for _, fr := range fakeReservations {
+ if fr.Port == pf.Port {
+ found = true
+ }
+ }
+ if !found {
+ continue
+ }
+ reservators[portFields[pf.Port]] = reservePortInfo{
+ reserveAddr: pf.Network.ReservePortAddr,
+ RemoteProxy: pf.Cluster != "",
+ }
+ allocators[portFields[pf.Port]] = pf.Network.AllocatePortAddr
+ }
+ portReservations, err := reservePorts(reservators)
+ if err != nil {
+ return ReleaseResources{}, err
+ }
+ if err := setPortFields(values, portReservations); err != nil {
+ return ReleaseResources{}, err
+ }
+ rendered, err = newApp.Render(config.Release, env, networks, ToAccessConfigs(clusters), merge(config.Input, values), renderedCfg.LocalCharts, m.vpnAPIClient)
if err != nil {
return ReleaseResources{}, err
}
@@ -685,6 +737,22 @@
if err := installApp(m.repo, instanceDir, rendered.Name, rendered.Config, rendered.Resources, rendered.Data, opts...); err != nil {
return ReleaseResources{}, err
}
+ toOpen := []PortForward{}
+ for _, op := range rendered.Ports {
+ found := false
+ for _, rp := range portReservations {
+ if rp.Port == op.Port {
+ found = true
+ break
+ }
+ }
+ if !found {
+ toOpen = append(toOpen, op)
+ }
+ }
+ if err := openPorts(toOpen, portReservations, allocators, config.Release.Namespace); err != nil {
+ return ReleaseResources{}, err
+ }
for _, ocp := range renderedCfg.Out.ClusterProxy {
found := false
for _, ncp := range rendered.ClusterProxies {
diff --git a/core/installer/app_test.go b/core/installer/app_test.go
index 7a7bf7a..0838f14 100644
--- a/core/installer/app_test.go
+++ b/core/installer/app_test.go
@@ -6,6 +6,7 @@
"net"
"testing"
+ "cuelang.org/go/cue"
"cuelang.org/go/cue/errors"
)
@@ -644,3 +645,63 @@
t.Log(string(r))
}
}
+
+func TestUpdateUsesPreviousValues(t *testing.T) {
+ contents := `
+input: {
+ port: int | *5
+}
+
+out: {
+ openPort: [{
+ name: "api"
+ network: networks["private"]
+ port: input.port
+ service: {
+ name: "app"
+ port: 8080
+ }
+ }]
+}
+
+input: {
+ port: 10
+}
+`
+ app, err := NewCueEnvApp(CueAppData{
+ "base.cue": []byte(cueBaseConfig),
+ "app.cue": []byte(contents),
+ "global.cue": []byte(cueEnvAppGlobal),
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ a, ok := app.(cueEnvApp)
+ if !ok {
+ t.Fatal("expected cue app")
+ }
+ defaults, err := ExtractDefaultValues(a.cfg.LookupPath(cue.ParsePath("input")))
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Log(defaults)
+ if defaults.(map[string]any)["port"].(int64) != 10 {
+ t.Fatal("port")
+ }
+}
+
+func TestMerge(t *testing.T) {
+ x := map[string]any{
+ "key": map[string]any{
+ "pub": 1,
+ "priv": 2,
+ },
+ }
+ y := map[string]any{
+ "foo": 3,
+ }
+ z := merge(x, y)
+ if _, ok := z["foo"]; !ok {
+ t.Fatal(z)
+ }
+}
diff --git a/core/installer/schema.go b/core/installer/schema.go
index fb5d305..c7f7196 100644
--- a/core/installer/schema.go
+++ b/core/installer/schema.go
@@ -383,7 +383,7 @@
// TODO(gio): handle numbers
return nil, fmt.Errorf("implement: %s", v)
case cue.IntKind:
- if d, ok := v.Default(); ok {
+ if d, ok := v.Default(); ok || d.IsConcrete() {
return d.Int64()
}
case cue.ListKind: