// deployBundle deploys the given bundle data using the given API client and // charm store client. The deployment is not transactional, and its progress is // notified using the given deployment logger. func deployBundle( bundleFilePath string, data *charm.BundleData, channel csparams.Channel, client *api.Client, serviceDeployer *serviceDeployer, resolver *charmURLResolver, log deploymentLogger, bundleStorage map[string]map[string]storage.Constraints, ) (map[*charm.URL]*macaroon.Macaroon, error) { verifyConstraints := func(s string) error { _, err := constraints.Parse(s) return err } verifyStorage := func(s string) error { _, err := storage.ParseConstraints(s) return err } var verifyError error if bundleFilePath == "" { verifyError = data.Verify(verifyConstraints, verifyStorage) } else { verifyError = data.VerifyLocal(bundleFilePath, verifyConstraints, verifyStorage) } if verifyError != nil { if verr, ok := verifyError.(*charm.VerificationError); ok { errs := make([]string, len(verr.Errors)) for i, err := range verr.Errors { errs[i] = err.Error() } return nil, errors.New("the provided bundle has the following errors:\n" + strings.Join(errs, "\n")) } return nil, errors.Annotate(verifyError, "cannot deploy bundle") } // Retrieve bundle changes. changes := bundlechanges.FromData(data) numChanges := len(changes) // Initialize the unit status. status, err := client.Status(nil) if err != nil { return nil, errors.Annotate(err, "cannot get model status") } unitStatus := make(map[string]string, numChanges) for _, serviceData := range status.Services { for unit, unitData := range serviceData.Units { unitStatus[unit] = unitData.Machine } } // Instantiate a watcher used to follow the deployment progress. watcher, err := watchAll(client) if err != nil { return nil, errors.Annotate(err, "cannot watch model") } defer watcher.Stop() serviceClient, err := serviceDeployer.newServiceAPIClient() if err != nil { return nil, errors.Annotate(err, "cannot get service client") } annotationsClient, err := serviceDeployer.newAnnotationsAPIClient() if err != nil { return nil, errors.Annotate(err, "cannot get annotations client") } // Instantiate the bundle handler. h := &bundleHandler{ bundleDir: bundleFilePath, changes: changes, results: make(map[string]string, numChanges), channel: channel, client: client, serviceClient: serviceClient, annotationsClient: annotationsClient, serviceDeployer: serviceDeployer, bundleStorage: bundleStorage, resolver: resolver, log: log, data: data, unitStatus: unitStatus, ignoredMachines: make(map[string]bool, len(data.Services)), ignoredUnits: make(map[string]bool, len(data.Services)), watcher: watcher, } // Deploy the bundle. csMacs := make(map[*charm.URL]*macaroon.Macaroon) channels := make(map[*charm.URL]csparams.Channel) for _, change := range changes { switch change := change.(type) { case *bundlechanges.AddCharmChange: cURL, channel, csMac, err2 := h.addCharm(change.Id(), change.Params) if err2 == nil { csMacs[cURL] = csMac channels[cURL] = channel } err = err2 case *bundlechanges.AddMachineChange: err = h.addMachine(change.Id(), change.Params) case *bundlechanges.AddRelationChange: err = h.addRelation(change.Id(), change.Params) case *bundlechanges.AddServiceChange: var cURL *charm.URL cURL, err = charm.ParseURL(resolve(change.Params.Charm, h.results)) if err == nil { chID := charmstore.CharmID{ URL: cURL, Channel: channels[cURL], } csMac := csMacs[cURL] err = h.addService(change.Id(), change.Params, chID, csMac) } case *bundlechanges.AddUnitChange: err = h.addUnit(change.Id(), change.Params) case *bundlechanges.ExposeChange: err = h.exposeService(change.Id(), change.Params) case *bundlechanges.SetAnnotationsChange: err = h.setAnnotations(change.Id(), change.Params) default: return nil, errors.Errorf("unknown change type: %T", change) } if err != nil { return nil, errors.Annotate(err, "cannot deploy bundle") } } return csMacs, nil }
// deployBundle deploys the given bundle data using the given API client and // charm store client. The deployment is not transactional, and its progress is // notified using the given deployment logger. func deployBundle( data *charm.BundleData, client *api.Client, serviceDeployer *serviceDeployer, csclient *csClient, repoPath string, conf *config.Config, log deploymentLogger, bundleStorage map[string]map[string]storage.Constraints, ) error { verifyConstraints := func(s string) error { _, err := constraints.Parse(s) return err } verifyStorage := func(s string) error { _, err := storage.ParseConstraints(s) return err } if err := data.Verify(verifyConstraints, verifyStorage); err != nil { return errors.Annotate(err, "cannot deploy bundle") } // Retrieve bundle changes. changes := bundlechanges.FromData(data) numChanges := len(changes) // Initialize the unit status. status, err := client.Status(nil) if err != nil { return errors.Annotate(err, "cannot get model status") } unitStatus := make(map[string]string, numChanges) for _, serviceData := range status.Services { for unit, unitData := range serviceData.Units { unitStatus[unit] = unitData.Machine } } // Instantiate a watcher used to follow the deployment progress. watcher, err := watchAll(client) if err != nil { return errors.Annotate(err, "cannot watch model") } defer watcher.Stop() serviceClient, err := serviceDeployer.newServiceAPIClient() if err != nil { return errors.Annotate(err, "cannot get service client") } annotationsClient, err := serviceDeployer.newAnnotationsAPIClient() if err != nil { return errors.Annotate(err, "cannot get annotations client") } // Instantiate the bundle handler. h := &bundleHandler{ changes: changes, results: make(map[string]string, numChanges), client: client, serviceClient: serviceClient, annotationsClient: annotationsClient, serviceDeployer: serviceDeployer, bundleStorage: bundleStorage, csclient: csclient, repoPath: repoPath, conf: conf, log: log, data: data, unitStatus: unitStatus, ignoredMachines: make(map[string]bool, len(data.Services)), ignoredUnits: make(map[string]bool, len(data.Services)), watcher: watcher, } // Deploy the bundle. for _, change := range changes { switch change := change.(type) { case *bundlechanges.AddCharmChange: err = h.addCharm(change.Id(), change.Params) case *bundlechanges.AddMachineChange: err = h.addMachine(change.Id(), change.Params) case *bundlechanges.AddRelationChange: err = h.addRelation(change.Id(), change.Params) case *bundlechanges.AddServiceChange: err = h.addService(change.Id(), change.Params) case *bundlechanges.AddUnitChange: err = h.addUnit(change.Id(), change.Params) case *bundlechanges.ExposeChange: err = h.exposeService(change.Id(), change.Params) case *bundlechanges.SetAnnotationsChange: err = h.setAnnotations(change.Id(), change.Params) default: return errors.Errorf("unknown change type: %T", change) } if err != nil { return errors.Annotate(err, "cannot deploy bundle") } } return nil }