Beispiel #1
0
// PrepareHook is part of the operation.Callbacks interface.
func (opc *operationCallbacks) PrepareHook(hi hook.Info) (string, error) {
	name := string(hi.Kind)
	switch {
	case hi.Kind.IsRelation():
		var err error
		name, err = opc.u.relations.PrepareHook(hi)
		if err != nil {
			return "", err
		}
	case hi.Kind.IsStorage():
		if err := opc.u.storage.ValidateHook(hi); err != nil {
			return "", err
		}
		storageName, err := names.StorageName(hi.StorageId)
		if err != nil {
			return "", err
		}
		name = fmt.Sprintf("%s-%s", storageName, hi.Kind)
		// TODO(axw) if the agent is not installed yet,
		// set the status to "preparing storage".
	case hi.Kind == hooks.ConfigChanged:
		// TODO(axw)
		//opc.u.f.DiscardConfigEvent()
	case hi.Kind == hook.LeaderSettingsChanged:
		// TODO(axw)
		//opc.u.f.DiscardLeaderSettingsEvent()
	}
	return name, nil
}
Beispiel #2
0
// HookContext is part of the ContextFactory interface.
func (f *contextFactory) HookContext(hookInfo hook.Info) (*HookContext, error) {
	ctx, err := f.coreContext()
	if err != nil {
		return nil, errors.Trace(err)
	}
	hookName := string(hookInfo.Kind)
	if hookInfo.Kind.IsRelation() {
		ctx.relationId = hookInfo.RelationId
		ctx.remoteUnitName = hookInfo.RemoteUnit
		relation, found := ctx.relations[hookInfo.RelationId]
		if !found {
			return nil, errors.Errorf("unknown relation id: %v", hookInfo.RelationId)
		}
		if hookInfo.Kind == hooks.RelationDeparted {
			relation.cache.RemoveMember(hookInfo.RemoteUnit)
		} else if hookInfo.RemoteUnit != "" {
			// Clear remote settings cache for changing remote unit.
			relation.cache.InvalidateMember(hookInfo.RemoteUnit)
		}
		hookName = fmt.Sprintf("%s-%s", relation.Name(), hookInfo.Kind)
	}
	if hookInfo.Kind.IsStorage() {
		ctx.storageTag = names.NewStorageTag(hookInfo.StorageId)
		if _, err := ctx.storage.Storage(ctx.storageTag); err != nil {
			return nil, errors.Annotatef(err, "could not retrieve storage for id: %v", hookInfo.StorageId)
		}
		storageName, err := names.StorageName(hookInfo.StorageId)
		if err != nil {
			return nil, errors.Trace(err)
		}
		hookName = fmt.Sprintf("%s-%s", storageName, hookName)
	}
	ctx.id = f.newId(hookName)
	return ctx, nil
}
Beispiel #3
0
// HookContext is part of the ContextFactory interface.
func (f *contextFactory) HookContext(hookInfo hook.Info) (*HookContext, error) {
	ctx, err := f.coreContext()
	if err != nil {
		return nil, errors.Trace(err)
	}
	hookName := string(hookInfo.Kind)
	if hookInfo.Kind.IsRelation() {
		ctx.relationId = hookInfo.RelationId
		ctx.remoteUnitName = hookInfo.RemoteUnit
		relation, found := ctx.relations[hookInfo.RelationId]
		if !found {
			return nil, errors.Errorf("unknown relation id: %v", hookInfo.RelationId)
		}
		if hookInfo.Kind == hooks.RelationDeparted {
			relation.cache.RemoveMember(hookInfo.RemoteUnit)
		} else if hookInfo.RemoteUnit != "" {
			// Clear remote settings cache for changing remote unit.
			relation.cache.InvalidateMember(hookInfo.RemoteUnit)
		}
		hookName = fmt.Sprintf("%s-%s", relation.Name(), hookInfo.Kind)
	}
	if hookInfo.Kind.IsStorage() {
		ctx.storageTag = names.NewStorageTag(hookInfo.StorageId)
		if _, found := ctx.storage.Storage(ctx.storageTag); !found {
			return nil, errors.Errorf("unknown storage id: %v", hookInfo.StorageId)
		}
		storageName, err := names.StorageName(hookInfo.StorageId)
		if err != nil {
			return nil, errors.Trace(err)
		}
		hookName = fmt.Sprintf("%s-%s", storageName, hookName)
	}
	// Metrics are only sent from the collect-metrics hook.
	if hookInfo.Kind == hooks.CollectMetrics {
		ch, err := getCharm(f.paths.GetCharmDir())
		if err != nil {
			return nil, errors.Trace(err)
		}
		ctx.definedMetrics = ch.Metrics()

		chURL, err := f.unit.CharmURL()
		if err != nil {
			return nil, errors.Trace(err)
		}

		charmMetrics := map[string]charm.Metric{}
		if ch.Metrics() != nil {
			charmMetrics = ch.Metrics().Metrics
		}
		ctx.metricsRecorder, err = metrics.NewJSONMetricRecorder(
			f.paths.GetMetricsSpoolDir(),
			charmMetrics,
			chURL.String())
		if err != nil {
			return nil, errors.Trace(err)
		}
	}
	ctx.id = f.newId(hookName)
	return ctx, nil
}
Beispiel #4
0
func (c *StorageListCommand) Run(ctx *cmd.Context) error {
	tags, err := c.ctx.StorageTags()
	if err != nil {
		return errors.Trace(err)
	}
	ids := make([]string, 0, len(tags))
	for _, tag := range tags {
		id := tag.Id()
		if c.storageName != "" {
			storageName, err := names.StorageName(id)
			if err != nil {
				return errors.Trace(err)
			}
			if storageName != c.storageName {
				continue
			}
		}
		ids = append(ids, id)
	}
	return c.out.Write(ctx, ids)
}
Beispiel #5
0
// formatStorageDetails takes a set of StorageDetail and creates a
// mapping keyed on unit and storage id.
func formatStorageDetails(storages []params.StorageDetails) (map[string]map[string]StorageInfo, error) {
	if len(storages) == 0 {
		return nil, nil
	}
	output := make(map[string]map[string]StorageInfo)
	for _, one := range storages {
		storageTag, err := names.ParseStorageTag(one.StorageTag)
		if err != nil {
			return nil, errors.Annotate(err, "invalid storage tag")
		}
		unitTag, err := names.ParseTag(one.UnitTag)
		if err != nil {
			return nil, errors.Annotate(err, "invalid unit tag")
		}

		storageName, err := names.StorageName(storageTag.Id())
		if err != nil {
			panic(err) // impossible
		}
		si := StorageInfo{
			StorageName: storageName,
			Kind:        one.Kind.String(),
			Status:      one.Status,
			Location:    one.Location,
			Persistent:  one.Persistent,
		}
		unit := unitTag.Id()
		unitColl, ok := output[unit]
		if !ok {
			unitColl = map[string]StorageInfo{}
			output[unit] = unitColl
		}
		unitColl[storageTag.Id()] = si
	}
	return output, nil
}
Beispiel #6
0
// validateFilesystemMountPoints validates the mount points of filesystems
// being attached to the specified machine. If there are any mount point
// path conflicts, an error will be returned.
func validateFilesystemMountPoints(m *Machine, newFilesystems []filesystemAttachmentTemplate) error {
	attachments, err := m.st.MachineFilesystemAttachments(m.MachineTag())
	if err != nil {
		return errors.Trace(err)
	}
	existing := make(map[names.FilesystemTag]string)
	for _, a := range attachments {
		params, ok := a.Params()
		if ok {
			existing[a.Filesystem()] = params.Location
			continue
		}
		info, err := a.Info()
		if err != nil {
			return errors.Trace(err)
		}
		existing[a.Filesystem()] = info.MountPoint
	}

	storageName := func(
		filesystemTag names.FilesystemTag,
		storageTag names.StorageTag,
	) string {
		if storageTag == (names.StorageTag{}) {
			return names.ReadableString(filesystemTag)
		}
		// We know the tag is valid, so ignore the error.
		storageName, _ := names.StorageName(storageTag.Id())
		return fmt.Sprintf("%q storage", storageName)
	}

	containsPath := func(a, b string) bool {
		a = path.Clean(a) + "/"
		b = path.Clean(b) + "/"
		return strings.HasPrefix(b, a)
	}

	// These sets are expected to be small, so sorting and comparing
	// adjacent values is not worth the cost of creating a reverse
	// lookup from location to filesystem.
	for _, template := range newFilesystems {
		newMountPoint := template.params.Location
		for oldFilesystemTag, oldMountPoint := range existing {
			var conflicted, swapOrder bool
			if containsPath(oldMountPoint, newMountPoint) {
				conflicted = true
			} else if containsPath(newMountPoint, oldMountPoint) {
				conflicted = true
				swapOrder = true
			}
			if !conflicted {
				continue
			}

			// Get a helpful identifier for the new filesystem. If it
			// is being created for a storage instance, then use
			// the storage name; otherwise use the filesystem name.
			newStorageName := storageName(template.tag, template.storage)

			// Likewise for the old filesystem, but this time we'll
			// need to consult state.
			oldFilesystem, err := m.st.Filesystem(oldFilesystemTag)
			if err != nil {
				return errors.Trace(err)
			}
			storageTag, err := oldFilesystem.Storage()
			if errors.IsNotAssigned(err) {
				storageTag = names.StorageTag{}
			} else if err != nil {
				return errors.Trace(err)
			}
			oldStorageName := storageName(oldFilesystemTag, storageTag)

			lhs := fmt.Sprintf("mount point %q for %s", oldMountPoint, oldStorageName)
			rhs := fmt.Sprintf("mount point %q for %s", newMountPoint, newStorageName)
			if swapOrder {
				lhs, rhs = rhs, lhs
			}
			return errors.Errorf("%s contains %s", lhs, rhs)
		}
	}
	return nil
}
Beispiel #7
0
func assertStorageNameInvalid(c *gc.C, id string) {
	_, err := names.StorageName(id)
	expect := fmt.Sprintf("%q is not a valid storage instance ID", id)
	c.Assert(err, gc.ErrorMatches, expect)
}
Beispiel #8
0
func assertStorageNameValid(c *gc.C, id, expect string) {
	name, err := names.StorageName(id)
	c.Assert(err, gc.IsNil)
	c.Assert(name, gc.Equals, expect)
}