~juju-qa/ubuntu/xenial/juju/2.0-rc2

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/state/cleanup.go

  • Committer: Nicholas Skaggs
  • Date: 2016-09-30 14:39:30 UTC
  • mfrom: (1.8.1)
  • Revision ID: nicholas.skaggs@canonical.com-20160930143930-vwwhrefh6ftckccy
import upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
        // SCHEMACHANGE: the names are expressive, the values not so much.
21
21
        cleanupRelationSettings              cleanupKind = "settings"
22
22
        cleanupUnitsForDyingService          cleanupKind = "units"
23
 
        cleanupCharmForDyingService          cleanupKind = "charm"
 
23
        cleanupCharm                         cleanupKind = "charm"
24
24
        cleanupDyingUnit                     cleanupKind = "dyingUnit"
25
25
        cleanupRemovedUnit                   cleanupKind = "removedUnit"
26
26
        cleanupServicesForDyingModel         cleanupKind = "applications"
33
33
        cleanupMachinesForDyingModel         cleanupKind = "modelMachines"
34
34
)
35
35
 
36
 
// cleanupDoc represents a potentially large set of documents that should be
37
 
// removed.
 
36
// cleanupDoc originally represented a set of documents that should be
 
37
// removed, but the Prefix field no longer means anything more than
 
38
// "what will be passed to the cleanup func".
38
39
type cleanupDoc struct {
39
 
        DocID     string `bson:"_id"`
40
 
        ModelUUID string `bson:"model-uuid"`
41
 
        Kind      cleanupKind
42
 
        Prefix    string
 
40
        DocID  string      `bson:"_id"`
 
41
        Kind   cleanupKind `bson:"kind"`
 
42
        Prefix string      `bson:"prefix"`
43
43
}
44
44
 
45
45
// newCleanupOp returns a txn.Op that creates a cleanup document with a unique
46
46
// id and the supplied kind and prefix.
47
 
func (st *State) newCleanupOp(kind cleanupKind, prefix string) txn.Op {
 
47
func newCleanupOp(kind cleanupKind, prefix string) txn.Op {
48
48
        doc := &cleanupDoc{
49
 
                DocID:     st.docID(fmt.Sprint(bson.NewObjectId())),
50
 
                ModelUUID: st.ModelUUID(),
51
 
                Kind:      kind,
52
 
                Prefix:    prefix,
 
49
                DocID:  fmt.Sprint(bson.NewObjectId()),
 
50
                Kind:   kind,
 
51
                Prefix: prefix,
53
52
        }
54
53
        return txn.Op{
55
54
                C:      cleanupsC,
84
83
                switch doc.Kind {
85
84
                case cleanupRelationSettings:
86
85
                        err = st.cleanupRelationSettings(doc.Prefix)
87
 
                case cleanupCharmForDyingService:
88
 
                        err = st.cleanupCharmForDyingService(doc.Prefix)
 
86
                case cleanupCharm:
 
87
                        err = st.cleanupCharm(doc.Prefix)
89
88
                case cleanupUnitsForDyingService:
90
89
                        err = st.cleanupUnitsForDyingService(doc.Prefix)
91
90
                case cleanupDyingUnit:
118
117
                        }
119
118
                }
120
119
                if err != nil {
121
 
                        logger.Errorf("cleanup failed: %v", err)
 
120
                        logger.Errorf("cleanup failed for %v(%q): %v", doc.Kind, doc.Prefix, err)
122
121
                        continue
123
122
                }
124
123
                ops := []txn.Op{{
151
150
}
152
151
 
153
152
func (st *State) cleanupRelationSettings(prefix string) error {
154
 
        settings, closer := st.getCollection(settingsC)
155
 
        defer closer()
156
 
        // Documents marked for cleanup are not otherwise referenced in the
157
 
        // system, and will not be under watch, and are therefore safe to
158
 
        // delete directly.
159
 
        settingsW := settings.Writeable()
160
 
 
161
 
        sel := bson.D{{"_id", bson.D{{"$regex", "^" + st.docID(prefix)}}}}
162
 
        if count, err := settingsW.Find(sel).Count(); err != nil {
163
 
                return fmt.Errorf("cannot detect cleanup targets: %v", err)
164
 
        } else if count != 0 {
165
 
                if _, err := settingsW.RemoveAll(sel); err != nil {
166
 
                        return fmt.Errorf("cannot remove documents marked for cleanup: %v", err)
167
 
                }
 
153
        change := relationSettingsCleanupChange{Prefix: st.docID(prefix)}
 
154
        if err := Apply(st.database, change); err != nil {
 
155
                return errors.Trace(err)
168
156
        }
169
157
        return nil
170
158
}
267
255
        return nil
268
256
}
269
257
 
270
 
func (st *State) cleanupCharmForDyingService(charmURL string) error {
 
258
// cleanupCharm is speculative: it can abort without error for many
 
259
// reasons, because it's triggered somewhat overenthusiastically for
 
260
// simplicity's sake.
 
261
func (st *State) cleanupCharm(charmURL string) error {
271
262
        curl, err := charm.ParseURL(charmURL)
272
263
        if err != nil {
273
264
                return errors.Annotatef(err, "invalid charm URL %v", charmURL)
274
265
        }
 
266
        if curl.Schema != "local" {
 
267
                // No cleanup necessary or possible.
 
268
                return nil
 
269
        }
 
270
 
275
271
        ch, err := st.Charm(curl)
276
272
        if errors.IsNotFound(err) {
277
273
                // Charm already removed.
278
274
                return nil
279
 
        }
280
 
        if err != nil {
281
 
                return errors.Annotate(err, "cannot read charm record from state")
282
 
        }
283
 
        if err := st.deleteCharmArchive(curl, ch.StoragePath()); err != nil && !errors.IsNotFound(err) {
284
 
                return errors.Annotate(err, "cannot remove charm archive from storage")
 
275
        } else if err != nil {
 
276
                return errors.Annotate(err, "reading charm")
 
277
        }
 
278
 
 
279
        err = ch.Destroy()
 
280
        switch errors.Cause(err) {
 
281
        case nil:
 
282
        case errCharmInUse:
 
283
                // No cleanup necessary at this time.
 
284
                return nil
 
285
        default:
 
286
                return errors.Annotate(err, "destroying charm")
 
287
        }
 
288
 
 
289
        if err := ch.Remove(); err != nil {
 
290
                return errors.Trace(err)
285
291
        }
286
292
        return nil
287
293
}