// removeStorageInstanceOps removes the storage instance with the given
// tag from state, if the specified assertions hold true.
554712
func removeStorageInstanceOps(si *storageInstance, assert bson.D, force bool) ([]txn.Op, error) {
	// Remove the storage instance document, ensuring the owner does not
	// change from what's passed in.
	owner := si.maybeOwner()
	var ownerAssert bson.DocElem
	if owner != nil {
		ownerAssert = bson.DocElem{"owner", owner.String()}
	} else {
		ownerAssert = bson.DocElem{"owner", bson.D{{"$exists", false}}}
	}
	ops := []txn.Op{{
		C:      storageInstancesC,
		Id:     si.doc.Id,
		Assert: append(assert, ownerAssert),
		Remove: true,
	}}
	if owner != nil {
		// Ensure that removing the storage will not violate the
		// owner's charm storage requirements.
		validateRemoveOps, err := validateRemoveOwnerStorageInstanceOps(si)
		if err != nil {
			if !force {
				return nil, errors.Trace(err)
			}
			logger.Warningf("could not validate owner for storage instance %v during remove: %v", si.StorageTag().Id(), err)
		}
		ops = append(ops, validateRemoveOps...)

		// Decrement the owner's count for the storage name, freeing
		// up a slot for a new storage instance to be attached.
		decrefOp, err := decrefEntityStorageOp(si.sb.mb, owner, si.StorageName())
		if err != nil {
			if !force {
				return nil, errors.Trace(err)
			}
			logger.Warningf("could not decrement owner count for storage instance %v during remove: %v", si.StorageTag().Id(), err)
		} else {
			ops = append(ops, decrefOp)
		}
	}

	machineStorageOp := func(c string, id string) txn.Op {
		return txn.Op{
			C:      c,
			Id:     id,
			Assert: bson.D{{"storageid", si.doc.Id}},
			Update: bson.D{{"$unset", bson.D{{"storageid", nil}}}},
		}
	}

	// Destroy any assigned volume/filesystem, and clear the storage
	// reference to avoid a dangling pointer while the volume/filesystem
	// is being destroyed.
	var haveFilesystem bool
	filesystem, err := si.sb.storageInstanceFilesystem(si.StorageTag())
	if err == nil {
		ops = append(ops, machineStorageOp(
			filesystemsC, filesystem.Tag().Id(),
		))
		fsOps, err := destroyFilesystemOps(si.sb, filesystem, si.doc.Releasing, nil)
		if err != nil {
			if !force {
				return nil, errors.Trace(err)
			}
			logger.Warningf("could not get operations to destroy filesystem %v when removing storage instance %v: %v", filesystem.FilesystemTag().Id(), si.StorageTag().Id(), err)
		}
		ops = append(ops, fsOps...)
		haveFilesystem = true
	} else if !errors.IsNotFound(err) {
		if !force {
			return nil, errors.Trace(err)
		}
		logger.Warningf("could not get filesystem when removing storage instance %v: %v", si.StorageTag().Id(), err)
	}
	volume, err := si.sb.storageInstanceVolume(si.StorageTag())
	if err == nil {
		ops = append(ops, machineStorageOp(
			volumesC, volume.Tag().Id(),
		))
		// If the storage instance has a filesystem, it may also
		// have a volume (i.e. for volume-backed filesystem). In
		// this case, we want to destroy only the filesystem; when
		// the filesystem is removed, the volume will be destroyed.
		if !haveFilesystem {
			volOps, err := destroyVolumeOps(si.sb, volume, si.doc.Releasing, nil)
			if err != nil {
				if !force {
					return nil, errors.Trace(err)
				}
				logger.Warningf("could not get operations to destroy volume %v when removing storage instance %v: %v", volume.Tag().Id(), si.StorageTag().Id(), err)
			}
			ops = append(ops, volOps...)
		}
	} else if !errors.IsNotFound(err) {
		if !force {
			return nil, errors.Trace(err)
		}
		logger.Warningf("could not get volume when removing storage instance %v: %v", si.StorageTag().Id(), err)
	}
	return ops, nil
}
657640
func (s *blockDiskStore) removeReferences(
	ctx context.Context, id kbfsblock.ID, contexts []kbfsblock.Context,
	tag string) (liveCount int, err error) {
	cleanup, err := s.exclusify(ctx, id)
	if err != nil {
		return 0, err
	}
	defer cleanup()

	info, err := s.getInfo(id)
	if err != nil {
		return 0, err
	}
	if len(info.Refs) == 0 {
		return 0, nil
	}

	for _, context := range contexts {
		err := info.Refs.remove(context, tag)
		if err != nil {
			return 0, err
		}
		if len(info.Refs) == 0 {
			break
		}
	}

	err = s.putInfo(id, info)
	if err != nil {
		return 0, err
	}

	return len(info.Refs), nil
}
1185441
func (sb *storageBackend) DetachStorage(storage names.StorageTag, unit names.UnitTag, force bool, maxWait time.Duration) (err error) {
	defer errors.DeferredAnnotatef(&err, "cannot destroy storage attachment %s:%s", storage.Id(), unit.Id())
	buildTxn := func(attempt int) ([]txn.Op, error) {
		s, err := sb.storageAttachment(storage, unit)
		if errors.IsNotFound(err) && attempt > 0 {
			// On the first attempt, we expect it to exist.
			return nil, jujutxn.ErrNoOperations
		} else if err != nil {
			return nil, errors.Trace(err)
		}
		if s.doc.Life == Dying {
			return nil, jujutxn.ErrNoOperations
		}
		si, err := sb.storageInstance(storage)
		if err != nil {
			return nil, jujutxn.ErrNoOperations
		}
		var ops []txn.Op
		var ownerAssert bson.DocElem
		switch owner := si.maybeOwner(); owner {
		case nil:
			ownerAssert = bson.DocElem{"owner", bson.D{{"$exists", false}}}
		case unit:
			validateRemoveOps, err := validateRemoveOwnerStorageInstanceOps(si)
			if err != nil {
				return nil, errors.Trace(err)
			}
			ops = append(ops, validateRemoveOps...)
			fallthrough
		default:
			ownerAssert = bson.DocElem{"owner", si.doc.Owner}
		}
		ops = append(ops, txn.Op{
			C:      storageInstancesC,
			Id:     si.doc.Id,
			Assert: bson.D{ownerAssert},
		})

		// Check if the unit is assigned to a machine, and if the
		// associated machine storage has been attached yet. If not,
		// we can short-circuit the removal of the storage attachment.
		var assert interface{}
		removeStorageAttachment := true
		u, err := sb.unit(unit.Id())
		if err != nil {
			return nil, errors.Trace(err)
		}

		processAttachments := true
		var hostTag names.Tag = unit
		if u.ShouldBeAssigned() {
			machineId, err := u.AssignedMachineId()
			if errors.IsNotAssigned(err) {
				// The unit is not assigned to a machine, therefore
				// there can be no associated machine storage. It
				// is safe to remove.
				ops = append(ops, u.noAssignedMachineOp())
				processAttachments = false
			} else if err != nil {
				return nil, errors.Trace(err)
			}
			hostTag = names.NewMachineTag(machineId)
		}
		if processAttachments {
			volumeAttachment, filesystemAttachment, err := sb.storageHostAttachment(
				si, unit, hostTag,
			)
			if err != nil {
				return nil, errors.Trace(err)
			}
			if volumeAttachment != nil {
				var assert interface{}
				if _, err := volumeAttachment.Info(); err == nil {
					// The volume attachment has been provisioned,
					// so we cannot short-circuit the removal of
					// the storage attachment.
					removeStorageAttachment = false
					assert = txn.DocExists
				} else {
					assert = bson.D{{"info", bson.D{{"$exists", false}}}}
				}
				ops = append(ops, txn.Op{
					C: volumeAttachmentsC,
					Id: volumeAttachmentId(
						volumeAttachment.Host().Id(),
						volumeAttachment.Volume().Id(),
					),
					Assert: assert,
				})
			}
			if filesystemAttachment != nil {
				var assert interface{}
				if _, err := filesystemAttachment.Info(); err == nil {
					// The filesystem attachment has been provisioned,
					// so we cannot short-circuit the removal of
					// the storage attachment.
					removeStorageAttachment = false
					assert = txn.DocExists
				} else {
					assert = bson.D{{"info", bson.D{{"$exists", false}}}}
				}
				ops = append(ops, txn.Op{
					C: filesystemAttachmentsC,
					Id: filesystemAttachmentId(
						filesystemAttachment.Host().Id(),
						filesystemAttachment.Filesystem().Id(),
					),
					Assert: assert,
				})
			}
		}
		if removeStorageAttachment {
			// Short-circuit the removal of the storage attachment.
			return removeStorageAttachmentOps(sb, s, si, force, assert, ops...)
		}
		return append(ops, detachStorageOps(storage, unit)...), nil
	}
	return sb.mb.db().Run(buildTxn)
}
120142
func removeFilesystems(ctx *context, ops map[names.FilesystemTag]*removeFilesystemOp) error {
	tags := make([]names.FilesystemTag, 0, len(ops))
	for tag := range ops {
		tags = append(tags, tag)
	}
	removeFilesystemParams, err := removeFilesystemParams(ctx, tags)
	if err != nil {
		return errors.Trace(err)
	}
	filesystemParams := make([]storage.FilesystemParams, len(tags))
	removeFilesystemParamsByTag := make(map[names.FilesystemTag]params.RemoveFilesystemParams)
	for i, args := range removeFilesystemParams {
		removeFilesystemParamsByTag[tags[i]] = args
		filesystemParams[i] = storage.FilesystemParams{
			Tag:      tags[i],
			Provider: storage.ProviderType(args.Provider),
		}
	}
	paramsBySource, filesystemSources, err := filesystemParamsBySource(
		ctx.config.StorageDir,
		filesystemParams,
		ctx.managedFilesystemSource,
		ctx.config.Registry,
	)
	if err != nil {
		return errors.Trace(err)
	}
	var remove []names.Tag
	var reschedule []scheduleOp
	var statuses []params.EntityStatusArgs
	removeFilesystems := func(tags []names.FilesystemTag, ids []string, f func(environscontext.ProviderCallContext, []string) ([]error, error)) error {
		if len(ids) == 0 {
			return nil
		}
		errs, err := f(ctx.config.CloudCallContext, ids)
		if err != nil {
			return errors.Trace(err)
		}
		for i, err := range errs {
			tag := tags[i]
			if err == nil {
				remove = append(remove, tag)
				continue
			}
			// Failed to destroy or release filesystem; reschedule and update status.
			reschedule = append(reschedule, ops[tag])
			statuses = append(statuses, params.EntityStatusArgs{
				Tag:    tag.String(),
				Status: status.Error.String(),
				Info:   errors.Annotate(err, "removing filesystem").Error(),
			})
		}
		return nil
	}
	for sourceName, filesystemParams := range paramsBySource {
		logger.Debugf("removing filesystems from %q: %v", sourceName, filesystemParams)
		filesystemSource := filesystemSources[sourceName]
		removeTags := make([]names.FilesystemTag, len(filesystemParams))
		removeParams := make([]params.RemoveFilesystemParams, len(filesystemParams))
		for i, args := range filesystemParams {
			removeTags[i] = args.Tag
			removeParams[i] = removeFilesystemParamsByTag[args.Tag]
		}
		destroyTags, destroyIds, releaseTags, releaseIds := partitionRemoveFilesystemParams(removeTags, removeParams)
		if err := removeFilesystems(destroyTags, destroyIds, filesystemSource.DestroyFilesystems); err != nil {
			return errors.Trace(err)
		}
		if err := removeFilesystems(releaseTags, releaseIds, filesystemSource.ReleaseFilesystems); err != nil {
			return errors.Trace(err)
		}
	}
	scheduleOperations(ctx, reschedule...)
	setStatus(ctx, statuses)
	if err := removeEntities(ctx, remove); err != nil {
		return errors.Annotate(err, "removing filesystems from state")
	}
	return nil
}
351935
func removeLinkLayerDevicesRefsOp(linkLayerDeviceDocID string) txn.Op {
	hasNoChildren := bson.D{{"num-children", 0}}
	return txn.Op{
		C:      linkLayerDevicesRefsC,
		Id:     linkLayerDeviceDocID,
		Assert: hasNoChildren,
		Remove: true,
	}
}
983431
func (p ResourcePersistence) NewRemoveUnitResourcesOps(unitID string) ([]txn.Op, error) {
	docs, err := p.unitResources(unitID)
	if err != nil {
		return nil, errors.Trace(err)
	}

	ops := newRemoveResourcesOps(docs)
	// We do not remove the resource from the blob store here. That is
	// an application-level matter.
	return ops, nil
}
458853
func (sto *unionStorage) RemoveBlobs(ctx context.Context, blobs []blob.Ref) error {
	return blobserver.ErrReadonly
}
290641
func (r *Relation) removeLocalEndpointOps(ep Endpoint, departingUnitName string, op *ForcedOperation) ([]txn.Op, error) {
	var asserts bson.D
	hasRelation := bson.D{{"relationcount", bson.D{{"$gt", 0}}}}
	departingUnitApplicationMatchesEndpoint := func() bool {
		s, err := names.UnitApplication(departingUnitName)
		return err == nil && s == ep.ApplicationName
	}
	var cleanupOps []txn.Op
	if departingUnitName == "" {
		// We're constructing a destroy operation, either of the relation
		// or one of its applications, and can therefore be assured that both
		// applications are Alive.
		asserts = append(hasRelation, isAliveDoc...)
	} else if departingUnitApplicationMatchesEndpoint() {
		// This application must have at least one unit -- the one that's
		// departing the relation -- so it cannot be ready for removal.
		cannotDieYet := bson.D{{"unitcount", bson.D{{"$gt", 0}}}}
		asserts = append(hasRelation, cannotDieYet...)
	} else {
		// This application may require immediate removal.
		// Check if the application is Dying, and if so, queue up a potential
		// cleanup in case this was the last reference.
		applications, closer := r.st.db().GetCollection(applicationsC)
		defer closer()

		asserts = append(hasRelation)
		var appDoc applicationDoc
		if err := applications.FindId(ep.ApplicationName).One(&appDoc); err == nil {
			if appDoc.Life != Alive {
				cleanupOps = append(cleanupOps, newCleanupOp(
					cleanupApplication,
					ep.ApplicationName,
					false, // destroyStorage
					op.Force,
				))
			}
		} else if !op.Force {
			return nil, errors.Trace(err)
		}
	}
	return append([]txn.Op{{
		C:      applicationsC,
		Id:     r.st.docID(ep.ApplicationName),
		Assert: asserts,
		Update: bson.D{{"$inc", bson.D{{"relationcount", -1}}}},
	}}, cleanupOps...), nil
}
1253689
func DeleteInstance(cloud fi.Cloud, t *resources.Resource) error {
	c := cloud.(awsup.AWSCloud)

	id := t.ID
	glog.V(2).Infof("Deleting EC2 instance %q", id)
	request := &ec2.TerminateInstancesInput{
		InstanceIds: []*string{&id},
	}
	_, err := c.EC2().TerminateInstances(request)
	if err != nil {
		if awsup.AWSErrorCode(err) == "InvalidInstanceID.NotFound" {
			glog.V(2).Infof("Got InvalidInstanceID.NotFound error deleting instance %q; will treat as already-deleted", id)
		} else {
			return fmt.Errorf("error deleting Instance %q: %v", id, err)
		}
	}
	return nil
}
1345159
func (d *DeviceMapperDriver) cleanUpSnapshots() {
	snapshotsOnDisk, err := d.getSnapshotsOnDisk()
	if err != nil || snapshotsOnDisk == nil {
		return
	}

	glog.V(2).Infof("Snapshots on disk: %v", snapshotsOnDisk)

	snapshotsInMetadata, err := d.getSnapshotsFromMetadata()
	if err != nil || snapshotsInMetadata == nil {
		return
	}

	glog.V(2).Infof("Snapshots in metadata: %v", snapshotsInMetadata)

	for _, snapshotOnDisk := range snapshotsOnDisk {
		if _, ok := snapshotsInMetadata[snapshotOnDisk]; !ok {
			glog.V(2).Infof("Removing Snapshot: %v", snapshotOnDisk)
			os.RemoveAll(filepath.Join(d.MetadataDir(), snapshotOnDisk))
		} else {
			// Remove the snapshot on disk since it was found in the metadata map.  This
			// will leave the snapshotsInMetadata map with only snapshots that are in metadata but
			// not on disk, so they should all be removed from the metadata.
			delete(snapshotsInMetadata, snapshotOnDisk)
		}
	}

	for snapshotInMetadata, volumeName := range snapshotsInMetadata {
		glog.V(2).Infof("Removing Snapshot from metadata: %v", snapshotInMetadata)
		v, err := d.getVolume(volumeName, false)
		if err != nil {
			continue
		}

		v.Lock()
		defer v.Unlock()

		deviceHash, err := v.Metadata.LookupSnapshotDevice(snapshotInMetadata)
		if err != nil {
			glog.Errorf("Error removing snapshot: %v", err)
			continue
		}

		// Remove the snapshot info from the volume metadata
		if err := v.Metadata.RemoveSnapshot(snapshotInMetadata); err != nil {
			glog.Errorf("Error removing snapshot: %v", err)
			continue
		}

		glog.V(2).Infof("Deactivating snapshot device %s", deviceHash)
		v.driver.DeviceSet.Lock()
		err = v.driver.DeactivateDevice(deviceHash)
		v.driver.DeviceSet.Unlock()
		if err != nil {
			glog.Errorf("Error deactivating device (%s): %s", deviceHash, err)
			continue
		}
		if err := v.driver.deleteDevice(deviceHash, false); err != nil {
			glog.Errorf("Error removing snapshot: %v", err)
			continue
		}
	}
}
309142
func (st *State) removeAllInCollectionOps(name string) ([]txn.Op, error) {
	return st.removeInCollectionOps(name, nil)
}
1146790
func removeAttachments(ctx *context, ids []params.MachineStorageId) error {
	if len(ids) == 0 {
		return nil
	}
	errorResults, err := ctx.config.Life.RemoveAttachments(ids)
	if err != nil {
		return errors.Annotate(err, "removing attachments")
	}
	for i, result := range errorResults {
		if result.Error != nil && !params.IsCodeNotFound(result.Error) {
			// ignore not found error.
			return errors.Annotatef(
				result.Error, "removing attachment of %s to %s from state",
				ids[i].AttachmentTag, ids[i].MachineTag,
			)
		}
	}
	return nil
}
1318213
func (st *State) RemoveCloudAccess(cloud string, user names.UserTag) error {
	buildTxn := func(int) ([]txn.Op, error) {
		_, err := st.GetCloudAccess(cloud, user)
		if err != nil {
			return nil, err
		}
		ops := []txn.Op{removePermissionOp(cloudGlobalKey(cloud), userGlobalKey(userAccessID(user)))}
		return ops, nil
	}

	err := st.db().Run(buildTxn)
	return errors.Trace(err)
}
89730
func (sb *storageBackend) RemoveVolume(tag names.VolumeTag) (err error) {
	defer errors.DeferredAnnotatef(&err, "removing volume %s", tag.Id())
	buildTxn := func(attempt int) ([]txn.Op, error) {
		volume, err := sb.Volume(tag)
		if errors.IsNotFound(err) {
			return nil, jujutxn.ErrNoOperations
		} else if err != nil {
			return nil, errors.Trace(err)
		}
		if volume.Life() != Dead {
			return nil, errors.New("volume is not dead")
		}
		return sb.removeVolumeOps(tag), nil
	}
	return sb.mb.db().Run(buildTxn)
}
978762
func (sb *storageBackend) RemoveVolumeAttachmentPlan(hostTag names.Tag, volume names.VolumeTag) (err error) {
	defer errors.DeferredAnnotatef(&err, "removing attachment plan of volume %s from machine %s", volume.Id(), hostTag.Id())
	buildTxn := func(attempt int) ([]txn.Op, error) {
		plans, err := sb.machineVolumeAttachmentPlans(hostTag, volume)
		if errors.IsNotFound(err) {
			return nil, jujutxn.ErrNoOperations
		}
		if err != nil {
			return nil, errors.Trace(err)
		}
		// We should only have one plan for a volume
		if plans != nil && len(plans) > 0 {
			if plans[0].Life() != Dying {
				return nil, jujutxn.ErrNoOperations
			}
		} else {
			return nil, jujutxn.ErrNoOperations
		}
		return removeVolumeAttachmentPlanOps(hostTag, volume), nil
	}
	return sb.mb.db().Run(buildTxn)
}
1374594
func (gce *Cloud) RemoveInstancesFromInstanceGroup(name string, zone string, instanceNames []string) error {
	if len(instanceNames) == 0 {
		return nil
	}
	instances := []*compute.InstanceReference{}
	for _, ins := range instanceNames {
		instanceLink := makeHostURL(gce.projectID, zone, ins)
		instances = append(instances, &compute.InstanceReference{Instance: instanceLink})
	}
	op, err := gce.service.InstanceGroups.RemoveInstances(
		gce.projectID, zone, name,
		&compute.InstanceGroupsRemoveInstancesRequest{
			Instances: instances,
		}).Do()

	if err != nil {
		if isHTTPErrorCode(err, http.StatusNotFound) {
			return nil
		}
		return err
	}
	return gce.waitForZoneOp(op, zone)
}
932055
func (v *volume) StorageInstance() (names.StorageTag, error) {
	if v.doc.StorageId == "" {
		msg := fmt.Sprintf("volume %q is not assigned to any storage instance", v.Tag().Id())
		return names.StorageTag{}, errors.NewNotAssigned(nil, msg)
	}
	return names.NewStorageTag(v.doc.StorageId), nil
}