Installer: deallocate ports upon app uninstall
Change-Id: I19298537fed02de03a9e74fa351cf23f733de699
diff --git a/core/installer/app_manager.go b/core/installer/app_manager.go
index 4f01d46..cad18eb 100644
--- a/core/installer/app_manager.go
+++ b/core/installer/app_manager.go
@@ -152,7 +152,14 @@
SourcePort int `json:"sourcePort"`
TargetService string `json:"targetService"`
TargetPort int `json:"targetPort"`
- Secret string `json:"secret"`
+ Secret string `json:"secret,omitempty"`
+}
+
+type removePortReq struct {
+ Protocol string `json:"protocol"`
+ SourcePort int `json:"sourcePort"`
+ TargetService string `json:"targetService"`
+ TargetPort int `json:"targetPort"`
}
type reservePortResp struct {
@@ -209,12 +216,41 @@
return err
}
if resp.StatusCode != http.StatusOK {
- return fmt.Errorf("Could not allocate port %d, status code: %d", p.SourcePort, resp.StatusCode)
+ var r bytes.Buffer
+ io.Copy(&r, resp.Body)
+ return fmt.Errorf("Could not allocate port %d, status code %d, message: %s", p.SourcePort, resp.StatusCode, r.String())
}
}
return nil
}
+func closePorts(ports []PortForward) error {
+ var retErr error
+ for _, p := range ports {
+ var buf bytes.Buffer
+ req := removePortReq{
+ Protocol: p.Protocol,
+ SourcePort: p.SourcePort,
+ TargetService: p.TargetService,
+ TargetPort: p.TargetPort,
+ }
+ if err := json.NewEncoder(&buf).Encode(req); err != nil {
+ retErr = err
+ continue
+ }
+ resp, err := http.Post(p.RemoveAddr, "application/json", &buf)
+ if err != nil {
+ retErr = err
+ continue
+ }
+ if resp.StatusCode != http.StatusOK {
+ retErr = fmt.Errorf("Could not deallocate port %d, status code: %d", p.SourcePort, resp.StatusCode)
+ continue
+ }
+ }
+ return retErr
+}
+
func createKustomizationChain(r soft.RepoFS, path string) error {
for p := filepath.Clean(path); p != "/"; {
parent, child := filepath.Split(p)
@@ -419,6 +455,7 @@
}
// TODO(gio): add ingress-nginx to release resources
if err := openPorts(rendered.Ports, portReservations, allocators); err != nil {
+ fmt.Println(err)
return ReleaseResources{}, err
}
return ReleaseResources{
@@ -489,11 +526,11 @@
if err != nil {
return ReleaseResources{}, err
}
- localCharts, err := extractLocalCharts(m.repoIO, filepath.Join(instanceDir, "rendered.json"))
+ renderedCfg, err := readRendered(m.repoIO, filepath.Join(instanceDir, "rendered.json"))
if err != nil {
return ReleaseResources{}, err
}
- rendered, err := app.Render(config.Release, env, values, localCharts)
+ rendered, err := app.Render(config.Release, env, values, renderedCfg.LocalCharts)
if err != nil {
return ReleaseResources{}, err
}
@@ -504,8 +541,15 @@
if err := m.repoIO.Pull(); err != nil {
return err
}
- return m.repoIO.Do(func(r soft.RepoFS) (string, error) {
- r.RemoveDir(filepath.Join(m.appDirRoot, instanceId))
+ var portForward []PortForward
+ if err := m.repoIO.Do(func(r soft.RepoFS) (string, error) {
+ instanceDir := filepath.Join(m.appDirRoot, instanceId)
+ renderedCfg, err := readRendered(m.repoIO, filepath.Join(instanceDir, "rendered.json"))
+ if err != nil {
+ return "", err
+ }
+ portForward = renderedCfg.PortForward
+ r.RemoveDir(instanceDir)
kustPath := filepath.Join(m.appDirRoot, "kustomization.yaml")
kust, err := soft.ReadKustomization(r, kustPath)
if err != nil {
@@ -514,26 +558,35 @@
kust.RemoveResources(instanceId)
soft.WriteYaml(r, kustPath, kust)
return fmt.Sprintf("uninstall: %s", instanceId), nil
- })
+ }); err != nil {
+ return err
+ }
+ if err := closePorts(portForward); err != nil {
+ fmt.Println(err)
+ return err
+ }
+ return nil
}
// TODO(gio): deduplicate with cue definition in app.go, this one should be removed.
func CreateNetworks(env EnvConfig) []Network {
return []Network{
{
- Name: "Public",
- 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),
- ReservePortAddr: fmt.Sprintf("http://port-allocator.%s-ingress-public.svc.cluster.local/api/reserve", env.InfraName),
+ Name: "Public",
+ 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),
+ ReservePortAddr: fmt.Sprintf("http://port-allocator.%s-ingress-public.svc.cluster.local/api/reserve", env.InfraName),
+ DeallocatePortAddr: fmt.Sprintf("http://port-allocator.%s-ingress-public.svc.cluster.local/api/remove", env.InfraName),
},
{
- Name: "Private",
- 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),
- ReservePortAddr: fmt.Sprintf("http://port-allocator.%s-ingress-private.svc.cluster.local/api/reserve", env.Id),
+ Name: "Private",
+ 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),
+ ReservePortAddr: fmt.Sprintf("http://port-allocator.%s-ingress-private.svc.cluster.local/api/reserve", env.Id),
+ DeallocatePortAddr: fmt.Sprintf("http://port-allocator.%s-ingress-private.svc.cluster.local/api/remove", env.Id),
},
}
}
@@ -703,11 +756,11 @@
if err != nil {
return ReleaseResources{}, err
}
- localCharts, err := extractLocalCharts(m.repoIO, filepath.Join(instanceDir, "rendered.json"))
+ renderedCfg, err := readRendered(m.repoIO, filepath.Join(instanceDir, "rendered.json"))
if err != nil {
return ReleaseResources{}, err
}
- rendered, err := app.Render(config.Release, env, values, localCharts)
+ rendered, err := app.Render(config.Release, env, values, renderedCfg.LocalCharts)
if err != nil {
return ReleaseResources{}, err
}
@@ -754,19 +807,20 @@
type renderedInstance struct {
LocalCharts map[string]helmv2.HelmChartTemplateSpec `json:"localCharts"`
+ PortForward []PortForward `json:"portForward"`
}
-func extractLocalCharts(fs soft.RepoFS, path string) (map[string]helmv2.HelmChartTemplateSpec, error) {
+func readRendered(fs soft.RepoFS, path string) (renderedInstance, error) {
r, err := fs.Reader(path)
if err != nil {
- return nil, err
+ return renderedInstance{}, err
}
defer r.Close()
var cfg renderedInstance
if err := json.NewDecoder(r).Decode(&cfg); err != nil {
- return nil, err
+ return renderedInstance{}, err
}
- return cfg.LocalCharts, nil
+ return cfg, nil
}
func findPortFields(scm Schema) []string {