示例#1
0
func (s *changesSuite) TestFromData(c *gc.C) {
	for i, test := range fromDataTests {
		c.Logf("test %d: %s", i, test.about)

		// Retrieve and validate the bundle data.
		data, err := charm.ReadBundleData(strings.NewReader(test.content))
		c.Assert(err, jc.ErrorIsNil)
		err = data.Verify(nil)
		c.Assert(err, jc.ErrorIsNil)

		// Retrieve the changes, and convert them to a sequence of records.
		changes := bundlechanges.FromData(data)
		records := make([]record, len(changes))
		for i, change := range changes {
			r := record{
				Id:       change.Id(),
				Requires: change.Requires(),
				Method:   change.Method(),
				GUIArgs:  change.GUIArgs(),
			}
			r.Params = reflect.ValueOf(change).Elem().FieldByName("Params").Interface()
			records[i] = r
		}

		// Output the records for debugging.
		b, err := json.MarshalIndent(records, "", "  ")
		c.Assert(err, jc.ErrorIsNil)
		c.Logf("obtained records: %s", b)

		// Check that the obtained records are what we expect.
		c.Assert(records, jc.DeepEquals, test.expected)
	}
}
示例#2
0
文件: main.go 项目: axw/bundlechanges
// process generates and print to w the set of changes required to deploy
// the bundle data to be retrieved using r.
func process(r io.Reader, w io.Writer) error {
	// Read the bundle data.
	data, err := charm.ReadBundleData(r)
	if err != nil {
		return err
	}
	// Validate the bundle.
	if err := data.Verify(nil); err != nil {
		return err
	}
	// Generate the changes and convert them to the standard form.
	changes := bundlechanges.FromData(data)
	records := make([]*record, len(changes))
	for i, change := range changes {
		records[i] = &record{
			Id:       change.Id(),
			Requires: change.Requires(),
			Method:   change.Method(),
			Args:     change.GUIArgs(),
		}
	}
	// Serialize and print the records.
	content, err := json.MarshalIndent(records, "", "  ")
	if err != nil {
		return err
	}
	fmt.Fprintln(w, string(content))
	return nil
}
示例#3
0
// GetBundleChanges returns the list of changes required to deploy the given
// bundle data. The changes are sorted by requirements, so that they can be
// applied in order.
func (c *Client) GetBundleChanges(args params.GetBundleChangesParams) (params.GetBundleChangesResults, error) {
	var results params.GetBundleChangesResults
	data, err := charm.ReadBundleData(strings.NewReader(args.BundleDataYAML))
	if err != nil {
		return results, errors.Annotate(err, "cannot read bundle YAML")
	}
	if err := data.Verify(func(s string) error {
		_, err := constraints.Parse(s)
		return err
	}); err != nil {
		if err, ok := err.(*charm.VerificationError); ok {
			results.Errors = make([]string, len(err.Errors))
			for i, e := range err.Errors {
				results.Errors[i] = e.Error()
			}
			return results, nil
		}
		// This should never happen as Verify only returns verification errors.
		return results, errors.Annotate(err, "cannot verify bundle")
	}
	changes := bundlechanges.FromData(data)
	results.Changes = make([]*params.BundleChangesChange, len(changes))
	for i, c := range changes {
		results.Changes[i] = &params.BundleChangesChange{
			Id:       c.Id(),
			Method:   c.Method(),
			Args:     c.GUIArgs(),
			Requires: c.Requires(),
		}
	}
	return results, nil
}
示例#4
0
文件: bundle.go 项目: makyo/juju
// 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
}
示例#5
0
文件: bundle.go 项目: OSBI/juju
// 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
}