1package cmd
2
3import (
4	bihttpagent "github.com/cloudfoundry/bosh-agent/agentclient/http"
5	bosherr "github.com/cloudfoundry/bosh-utils/errors"
6	bihttpclient "github.com/cloudfoundry/bosh-utils/httpclient"
7	boshlog "github.com/cloudfoundry/bosh-utils/logger"
8	"github.com/cppforlife/go-patch/patch"
9
10	biblobstore "github.com/cloudfoundry/bosh-cli/blobstore"
11	bicloud "github.com/cloudfoundry/bosh-cli/cloud"
12	biconfig "github.com/cloudfoundry/bosh-cli/config"
13	bicpirel "github.com/cloudfoundry/bosh-cli/cpi/release"
14	bidepl "github.com/cloudfoundry/bosh-cli/deployment"
15	boshtpl "github.com/cloudfoundry/bosh-cli/director/template"
16	biinstall "github.com/cloudfoundry/bosh-cli/installation"
17	boshinst "github.com/cloudfoundry/bosh-cli/installation"
18	biinstallmanifest "github.com/cloudfoundry/bosh-cli/installation/manifest"
19	birelsetmanifest "github.com/cloudfoundry/bosh-cli/release/set/manifest"
20	biui "github.com/cloudfoundry/bosh-cli/ui"
21)
22
23type DeploymentDeleter interface {
24	DeleteDeployment(skipDrain bool, stage biui.Stage) (err error)
25}
26
27func NewDeploymentDeleter(
28	ui biui.UI,
29	logTag string,
30	logger boshlog.Logger,
31	deploymentStateService biconfig.DeploymentStateService,
32	releaseManager boshinst.ReleaseManager,
33	cloudFactory bicloud.Factory,
34	agentClientFactory bihttpagent.AgentClientFactory,
35	blobstoreFactory biblobstore.Factory,
36	deploymentManagerFactory bidepl.ManagerFactory,
37	deploymentManifestPath string,
38	deploymentVars boshtpl.Variables,
39	deploymentOp patch.Op,
40	cpiInstaller bicpirel.CpiInstaller,
41	cpiUninstaller biinstall.Uninstaller,
42	releaseFetcher boshinst.ReleaseFetcher,
43	releaseSetAndInstallationManifestParser ReleaseSetAndInstallationManifestParser,
44	tempRootConfigurator TempRootConfigurator,
45	targetProvider biinstall.TargetProvider,
46) DeploymentDeleter {
47	return &deploymentDeleter{
48		ui:                                      ui,
49		logTag:                                  logTag,
50		logger:                                  logger,
51		deploymentStateService:                  deploymentStateService,
52		releaseManager:                          releaseManager,
53		cloudFactory:                            cloudFactory,
54		agentClientFactory:                      agentClientFactory,
55		blobstoreFactory:                        blobstoreFactory,
56		deploymentManagerFactory:                deploymentManagerFactory,
57		deploymentManifestPath:                  deploymentManifestPath,
58		deploymentVars:                          deploymentVars,
59		deploymentOp:                            deploymentOp,
60		cpiInstaller:                            cpiInstaller,
61		cpiUninstaller:                          cpiUninstaller,
62		releaseFetcher:                          releaseFetcher,
63		releaseSetAndInstallationManifestParser: releaseSetAndInstallationManifestParser,
64		tempRootConfigurator:                    tempRootConfigurator,
65		targetProvider:                          targetProvider,
66	}
67}
68
69type deploymentDeleter struct {
70	ui                                      biui.UI
71	logTag                                  string
72	logger                                  boshlog.Logger
73	deploymentStateService                  biconfig.DeploymentStateService
74	releaseManager                          boshinst.ReleaseManager
75	cloudFactory                            bicloud.Factory
76	agentClientFactory                      bihttpagent.AgentClientFactory
77	blobstoreFactory                        biblobstore.Factory
78	deploymentManagerFactory                bidepl.ManagerFactory
79	deploymentManifestPath                  string
80	deploymentVars                          boshtpl.Variables
81	deploymentOp                            patch.Op
82	cpiInstaller                            bicpirel.CpiInstaller
83	cpiUninstaller                          biinstall.Uninstaller
84	releaseFetcher                          boshinst.ReleaseFetcher
85	releaseSetAndInstallationManifestParser ReleaseSetAndInstallationManifestParser
86	tempRootConfigurator                    TempRootConfigurator
87	targetProvider                          biinstall.TargetProvider
88}
89
90func (c *deploymentDeleter) DeleteDeployment(skipDrain bool, stage biui.Stage) (err error) {
91	c.ui.BeginLinef("Deployment state: '%s'\n", c.deploymentStateService.Path())
92
93	if !c.deploymentStateService.Exists() {
94		c.ui.BeginLinef("No deployment state file found.\n")
95		return nil
96	}
97
98	deploymentState, err := c.deploymentStateService.Load()
99	if err != nil {
100		return bosherr.WrapError(err, "Loading deployment state")
101	}
102
103	target, err := c.targetProvider.NewTarget()
104	if err != nil {
105		return bosherr.WrapError(err, "Determining installation target")
106	}
107
108	err = c.tempRootConfigurator.PrepareAndSetTempRoot(target.TmpPath(), c.logger)
109	if err != nil {
110		return bosherr.WrapError(err, "Setting temp root")
111	}
112
113	defer func() {
114		err := c.releaseManager.DeleteAll()
115		if err != nil {
116			c.logger.Warn(c.logTag, "Deleting all extracted releases: %s", err.Error())
117		}
118	}()
119
120	var installationManifest biinstallmanifest.Manifest
121
122	err = stage.PerformComplex("validating", func(stage biui.Stage) error {
123		var releaseSetManifest birelsetmanifest.Manifest
124		releaseSetManifest, installationManifest, err = c.releaseSetAndInstallationManifestParser.ReleaseSetAndInstallationManifest(c.deploymentManifestPath, c.deploymentVars, c.deploymentOp)
125		if err != nil {
126			return err
127		}
128
129		cpiReleaseName := installationManifest.Template.Release
130		cpiReleaseRef, found := releaseSetManifest.FindByName(cpiReleaseName)
131		if !found {
132			return bosherr.Errorf("installation release '%s' must refer to a release in releases", cpiReleaseName)
133		}
134
135		err = c.releaseFetcher.DownloadAndExtract(cpiReleaseRef, stage)
136		if err != nil {
137			return err
138		}
139
140		err = c.cpiInstaller.ValidateCpiRelease(installationManifest, stage)
141
142		return err
143	})
144	if err != nil {
145		return err
146	}
147
148	err = c.cpiInstaller.WithInstalledCpiRelease(installationManifest, target, stage, func(localCpiInstallation biinstall.Installation) error {
149		return localCpiInstallation.WithRunningRegistry(c.logger, stage, func() error {
150			err = c.findAndDeleteDeployment(skipDrain, stage, localCpiInstallation, deploymentState.DirectorID, installationManifest.Mbus, installationManifest.Cert.CA)
151
152			if err != nil {
153				return err
154			}
155
156			return stage.Perform("Uninstalling local artifacts for CPI and deployment", func() error {
157				err := c.cpiUninstaller.Uninstall(localCpiInstallation.Target())
158				if err != nil {
159					return err
160				}
161
162				return c.deploymentStateService.Cleanup()
163			})
164		})
165	})
166
167	return err
168}
169
170func (c *deploymentDeleter) findAndDeleteDeployment(skipDrain bool, stage biui.Stage, installation biinstall.Installation, directorID, installationMbus, caCert string) error {
171	deploymentManager, err := c.deploymentManager(installation, directorID, installationMbus, caCert)
172	if err != nil {
173		return err
174	}
175
176	err = c.findCurrentDeploymentAndDelete(skipDrain, stage, deploymentManager)
177	if err != nil {
178		return bosherr.WrapError(err, "Deleting deployment")
179	}
180
181	return deploymentManager.Cleanup(stage)
182}
183
184func (c *deploymentDeleter) findCurrentDeploymentAndDelete(skipDrain bool, stage biui.Stage, deploymentManager bidepl.Manager) error {
185	c.logger.Debug(c.logTag, "Finding current deployment...")
186
187	deployment, found, err := deploymentManager.FindCurrent()
188	if err != nil {
189		return bosherr.WrapError(err, "Finding current deployment")
190	}
191
192	return stage.PerformComplex("deleting deployment", func(deleteStage biui.Stage) error {
193		if !found {
194			//TODO: skip? would require adding skip support to PerformComplex
195			c.logger.Debug(c.logTag, "No current deployment found...")
196			return nil
197		}
198
199		return deployment.Delete(skipDrain, deleteStage)
200	})
201}
202
203func (c *deploymentDeleter) deploymentManager(installation biinstall.Installation, directorID, installationMbus, caCert string) (bidepl.Manager, error) {
204	c.logger.Debug(c.logTag, "Creating cloud client...")
205
206	stemcellApiVersion := 1
207	deploymentStateService, err := c.deploymentStateService.Load()
208	if err == nil {
209		for _, s := range deploymentStateService.Stemcells {
210			if deploymentStateService.CurrentStemcellID == s.ID {
211				stemcellApiVersion = s.ApiVersion
212				break
213			}
214		}
215	}
216
217	cloud, err := c.cloudFactory.NewCloud(installation, directorID, stemcellApiVersion)
218	if err != nil {
219		return nil, bosherr.WrapError(err, "Creating CPI client from CPI installation")
220	}
221
222	c.logger.Debug(c.logTag, "Creating agent client...")
223
224	agentClient, _ := c.agentClientFactory.NewAgentClient(directorID, installationMbus, caCert)
225
226	c.logger.Debug(c.logTag, "Creating blobstore client...")
227
228	blobstore, err := c.blobstoreFactory.Create(installationMbus, bihttpclient.CreateDefaultClientInsecureSkipVerify())
229	if err != nil {
230		return nil, bosherr.WrapError(err, "Creating blobstore client")
231	}
232
233	c.logger.Debug(c.logTag, "Creating deployment manager...")
234
235	return c.deploymentManagerFactory.NewManager(cloud, agentClient, blobstore), nil
236}
237