Example #1
0
func (m *mockStorageAccessor) StorageAttachmentLife(ids []params.StorageAttachmentId) ([]params.LifeResult, error) {
	if m.storageAttachmentLife != nil {
		return m.storageAttachmentLife(ids)
	}
	results := make([]params.LifeResult, len(ids))
	for i, id := range ids {
		storageTag, err := names.ParseStorageTag(id.StorageTag)
		if err != nil {
			results[i].Error = common.ServerError(err)
			continue
		}
		unitTag, err := names.ParseUnitTag(id.UnitTag)
		if err != nil {
			results[i].Error = common.ServerError(err)
			continue
		}
		att, err := m.storageAttachment(storageTag, unitTag)
		if err != nil {
			results[i].Error = common.ServerError(err)
			continue
		}
		results[i].Life = att.Life
	}
	return results, nil
}
Example #2
0
// Refresh fetches all of the unit's storage attachments and processes each
// one as in UpdateStorage.
func (a *Attachments) Refresh() error {
	attachmentIds, err := a.st.UnitStorageAttachments(a.unitTag)
	if err != nil {
		return errors.Annotate(err, "getting unit attachments")
	}
	storageTags := make([]names.StorageTag, len(attachmentIds))
	for i, attachmentId := range attachmentIds {
		storageTag, err := names.ParseStorageTag(attachmentId.StorageTag)
		if err != nil {
			return errors.Trace(err)
		}
		storageTags[i] = storageTag
	}
	// Remove non-existent storage from pending.
	for pending := range a.pending {
		var found bool
		for _, active := range storageTags {
			if pending == active {
				found = true
				break
			}
		}
		if !found {
			a.pending.Remove(pending)
		}
	}
	return a.UpdateStorage(storageTags)
}
Example #3
0
func (s *StorageAPI) watchOneStorageAttachment(id params.StorageAttachmentId, canAccess func(names.Tag) bool) (params.NotifyWatchResult, error) {
	// Watching a storage attachment is implemented as watching the
	// underlying volume or filesystem attachment. The only thing
	// we don't necessarily see in doing this is the lifecycle state
	// changes, but these may be observed by using the
	// WatchUnitStorageAttachments watcher.
	nothing := params.NotifyWatchResult{}
	unitTag, err := names.ParseUnitTag(id.UnitTag)
	if err != nil || !canAccess(unitTag) {
		return nothing, common.ErrPerm
	}
	storageTag, err := names.ParseStorageTag(id.StorageTag)
	if err != nil {
		return nothing, err
	}
	machineTag, err := s.st.UnitAssignedMachine(unitTag)
	if err != nil {
		return nothing, err
	}
	watch, err := common.WatchStorageAttachment(s.st, storageTag, machineTag, unitTag)
	if err != nil {
		return nothing, errors.Trace(err)
	}
	if _, ok := <-watch.Changes(); ok {
		return params.NotifyWatchResult{
			NotifyWatcherId: s.resources.Register(watch),
		}, nil
	}
	return nothing, watcher.EnsureErr(watch)
}
Example #4
0
func (s *StorageAPI) removeOneStorageAttachment(id params.StorageAttachmentId, canAccess func(names.Tag) bool) error {
	unitTag, err := names.ParseUnitTag(id.UnitTag)
	if err != nil {
		return err
	}
	if !canAccess(unitTag) {
		return common.ErrPerm
	}
	storageTag, err := names.ParseStorageTag(id.StorageTag)
	if err != nil {
		return err
	}
	return s.st.RemoveStorageAttachment(storageTag, unitTag)
}
Example #5
0
func (s *StorageAPI) getOneStateStorageAttachment(canAccess common.AuthFunc, id params.StorageAttachmentId) (state.StorageAttachment, error) {
	unitTag, err := names.ParseUnitTag(id.UnitTag)
	if err != nil {
		return nil, err
	}
	if !canAccess(unitTag) {
		return nil, common.ErrPerm
	}
	storageTag, err := names.ParseStorageTag(id.StorageTag)
	if err != nil {
		return nil, err
	}
	return s.st.StorageAttachment(storageTag, unitTag)
}
Example #6
0
// init processes the storage state directory and creates storagers
// for the state files found.
func (a *Attachments) init() error {
	if err := os.MkdirAll(a.storageStateDir, 0755); err != nil {
		return errors.Annotate(err, "creating storage state dir")
	}
	// Query all remote, known storage attachments for the unit,
	// so we can cull state files, and store current context.
	attachmentIds, err := a.st.UnitStorageAttachments(a.unitTag)
	if err != nil {
		return errors.Annotate(err, "getting unit attachments")
	}
	attachmentsByTag := make(map[names.StorageTag]struct{})
	for _, attachmentId := range attachmentIds {
		storageTag, err := names.ParseStorageTag(attachmentId.StorageTag)
		if err != nil {
			return errors.Trace(err)
		}
		attachmentsByTag[storageTag] = struct{}{}
	}
	stateFiles, err := readAllStateFiles(a.storageStateDir)
	if err != nil {
		return errors.Annotate(err, "reading storage state dirs")
	}
	for storageTag, stateFile := range stateFiles {
		if _, ok := attachmentsByTag[storageTag]; !ok {
			if err := stateFile.Remove(); err != nil {
				return errors.Trace(err)
			}
			continue
		}
		// Since there's a state file, we must previously have handled
		// at least "storage-attached", so there is no possibility of
		// short-circuiting the storage's removal.
		if err := a.add(storageTag, stateFile); err != nil {
			return errors.Trace(err)
		}
	}
	for storageTag := range attachmentsByTag {
		if _, ok := stateFiles[storageTag]; !ok {
			// There is no state file for the attachment, so no
			// hooks have been committed for it.
			a.pending.Add(storageTag)
		}
		// Non-locally recorded attachments will be further handled
		// by UpdateStorage.
	}
	return nil
}
Example #7
0
func createStorageInfo(details params.StorageDetails) (names.StorageTag, StorageInfo, error) {
	storageTag, err := names.ParseStorageTag(details.StorageTag)
	if err != nil {
		return names.StorageTag{}, StorageInfo{}, errors.Trace(err)
	}

	info := StorageInfo{
		Kind: details.Kind.String(),
		Status: EntityStatus{
			details.Status.Status,
			details.Status.Info,
			// TODO(axw) we should support formatting as ISO time
			common.FormatTime(details.Status.Since, false),
		},
		Persistent: details.Persistent,
	}

	if len(details.Attachments) > 0 {
		unitStorageAttachments := make(map[string]UnitStorageAttachment)
		for unitTagString, attachmentDetails := range details.Attachments {
			unitTag, err := names.ParseUnitTag(unitTagString)
			if err != nil {
				return names.StorageTag{}, StorageInfo{}, errors.Trace(err)
			}
			var machineId string
			if attachmentDetails.MachineTag != "" {
				machineTag, err := names.ParseMachineTag(attachmentDetails.MachineTag)
				if err != nil {
					return names.StorageTag{}, StorageInfo{}, errors.Trace(err)
				}
				machineId = machineTag.Id()
			}
			unitStorageAttachments[unitTag.Id()] = UnitStorageAttachment{
				machineId,
				attachmentDetails.Location,
			}
		}
		info.Attachments = &StorageAttachments{unitStorageAttachments}
	}

	return storageTag, info, nil
}
Example #8
0
// Show retrieves and returns detailed information about desired storage
// identified by supplied tags. If specified storage cannot be retrieved,
// individual error is returned instead of storage information.
func (api *API) Show(entities params.Entities) (params.StorageDetailsResults, error) {
	var all []params.StorageDetailsResult
	for _, entity := range entities.Entities {
		storageTag, err := names.ParseStorageTag(entity.Tag)
		if err != nil {
			all = append(all, params.StorageDetailsResult{
				Error: common.ServerError(err),
			})
			continue
		}
		found, instance, serverErr := api.getStorageInstance(storageTag)
		if err != nil {
			all = append(all, params.StorageDetailsResult{Error: serverErr})
			continue
		}
		if found {
			results := api.createStorageDetailsResult(storageTag, instance)
			all = append(all, results...)
		}
	}
	return params.StorageDetailsResults{Results: all}, nil
}
Example #9
0
// StorageDetails retrieves and returns detailed information about desired
// storage identified by supplied tags. If specified storage cannot be
// retrieved, individual error is returned instead of storage information.
func (api *API) StorageDetails(entities params.Entities) (params.StorageDetailsResults, error) {
	results := make([]params.StorageDetailsResult, len(entities.Entities))
	for i, entity := range entities.Entities {
		storageTag, err := names.ParseStorageTag(entity.Tag)
		if err != nil {
			results[i].Error = common.ServerError(err)
			continue
		}
		storageInstance, err := api.storage.StorageInstance(storageTag)
		if err != nil {
			results[i].Error = common.ServerError(err)
			continue
		}
		details, err := createStorageDetails(api.storage, storageInstance)
		if err != nil {
			results[i].Error = common.ServerError(err)
			continue
		}
		results[i].Result = details
	}
	return params.StorageDetailsResults{Results: results}, nil
}
Example #10
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
}
Example #11
0
func assertParseStorageTagInvalid(c *gc.C, tag string, expect error) {
	_, err := names.ParseStorageTag(tag)
	c.Assert(err, gc.ErrorMatches, expect.Error())
}
Example #12
0
func assertParseStorageTag(c *gc.C, tag string, expect names.StorageTag) {
	t, err := names.ParseStorageTag(tag)
	c.Assert(err, gc.IsNil)
	c.Assert(t, gc.Equals, expect)
}