/
destroy.go
131 lines (108 loc) · 3.54 KB
/
destroy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package app
import (
"fmt"
"net"
"strings"
"github.com/jcelliott/lumber"
"github.com/nanobox-io/golang-docker-client"
"github.com/nanobox-io/nanobox/models"
"github.com/nanobox-io/nanobox/processors/app/dns"
"github.com/nanobox-io/nanobox/processors/component"
"github.com/nanobox-io/nanobox/processors/provider"
"github.com/nanobox-io/nanobox/util"
"github.com/nanobox-io/nanobox/util/dhcp"
"github.com/nanobox-io/nanobox/util/display"
"github.com/nanobox-io/nanobox/util/locker"
)
// Destroy removes the app from the provider and the database
func Destroy(appModel *models.App) error {
// init docker client
if err := provider.Init(); err != nil {
return util.ErrorAppend(err, "failed to init docker client")
}
locker.LocalLock()
defer locker.LocalUnlock()
// short-circuit if this app isn't created
if appModel.IsNew() {
return nil
}
// load the env for the display context
envModel, err := appModel.Env()
if err != nil {
lumber.Error("app:Start:models.App.Env()")
return util.ErrorAppend(err, "failed to load app env")
}
if err := dns.RemoveAll(appModel); err != nil {
return util.ErrorAppend(err, "failed to remove dns aliases")
}
display.OpenContext("%s (%s)", envModel.Name, appModel.DisplayName())
defer display.CloseContext()
// remove the dev container if there is one
docker.ContainerRemove(fmt.Sprintf("nanobox_%s", appModel.ID))
// destroy the associated components
if err := destroyComponents(appModel); err != nil {
return util.ErrorAppend(err, "failed to destroy components")
}
// release IPs
if err := releaseIPs(appModel); err != nil {
return util.ErrorAppend(err, "failed to release IPs")
}
// destroy the app model
if err := appModel.Delete(); err != nil {
lumber.Error("app:Destroy:models.App{ID:%s}.Destroy(): %s", appModel.ID, err.Error())
return util.ErrorAppend(err, "failed to delete app model")
}
cleanImages()
return nil
}
// destroyComponents destroys all the components of this app
func destroyComponents(appModel *models.App) error {
display.OpenContext("Removing components")
defer display.CloseContext()
componentModels, err := appModel.Components()
if err != nil {
lumber.Error("app:destroyComponents:models.App{ID:%s}.Components() %s", appModel.ID, err.Error())
return util.ErrorAppend(err, "unable to retrieve components")
}
if len(componentModels) == 0 {
display.StartTask("Skipping (no components)")
display.StopTask()
return nil
}
for _, componentModel := range componentModels {
if err := component.Destroy(appModel, componentModel); err != nil {
return util.ErrorAppend(err, "failed to destroy app component")
}
}
return nil
}
// releaseIPs releases the app-level ip addresses
func releaseIPs(appModel *models.App) error {
display.StartTask("Releasing IPs")
defer display.StopTask()
// release all of the local IPs
for _, ip := range appModel.LocalIPs {
// release the IP
if err := dhcp.ReturnIP(net.ParseIP(ip)); err != nil {
display.ErrorTask()
lumber.Error("app:Destroy:releaseIPs:dhcp.ReturnIP(%s): %s", ip, err.Error())
return util.ErrorAppend(err, "failed to release IP")
}
}
return nil
}
func cleanImages() {
images, err := docker.ImageList()
if err != nil {
return
}
for _, image := range images {
for _, tag := range image.RepoTags {
// if there is a tag that is not our build and it is one of ours.. try removing it (without force)
if tag != "" && !strings.HasPrefix(tag, "nanobox/build") && strings.HasPrefix(tag, "nanobox/") {
tag = strings.Replace(tag, ":latest", "", 1)
docker.ImageRemove(tag, false)
}
}
}
}