github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/upgrades.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/mgo/v3/bson"
     9  	"github.com/juju/mgo/v3/txn"
    10  )
    11  
    12  // Until we add 3.0 upgrade steps, keep static analysis happy.
    13  var _ = func() {
    14  	_ = applyToAllModelSettings(nil, nil)
    15  }
    16  
    17  // runForAllModelStates will run runner function for every model passing a state
    18  // for that model.
    19  //
    20  //nolint:unused
    21  func runForAllModelStates(pool *StatePool, runner func(st *State) error) error {
    22  	st, err := pool.SystemState()
    23  	if err != nil {
    24  		return errors.Trace(err)
    25  	}
    26  	models, closer := st.db().GetCollection(modelsC)
    27  	defer closer()
    28  
    29  	var modelDocs []bson.M
    30  	err = models.Find(nil).Select(bson.M{"_id": 1}).All(&modelDocs)
    31  	if err != nil {
    32  		return errors.Annotate(err, "failed to read models")
    33  	}
    34  
    35  	for _, modelDoc := range modelDocs {
    36  		modelUUID := modelDoc["_id"].(string)
    37  		model, err := pool.Get(modelUUID)
    38  		if err != nil {
    39  			return errors.Annotatef(err, "failed to open model %q", modelUUID)
    40  		}
    41  		defer func() {
    42  			model.Release()
    43  		}()
    44  		if err := runner(model.State); err != nil {
    45  			return errors.Annotatef(err, "model UUID %q", modelUUID)
    46  		}
    47  	}
    48  	return nil
    49  }
    50  
    51  // applyToAllModelSettings iterates the model settings documents and applies the
    52  // passed in function to them.  If the function returns 'true' it indicates the
    53  // settings have been modified, and they should be written back to the
    54  // database.
    55  // Note that if there are any problems with updating settings, then none of the
    56  // changes will be applied, as they are all updated in a single transaction.
    57  func applyToAllModelSettings(st *State, change func(*settingsDoc) (bool, error)) error {
    58  	uuids, err := st.AllModelUUIDs()
    59  	if err != nil {
    60  		return errors.Trace(err)
    61  	}
    62  
    63  	coll, closer := st.db().GetRawCollection(settingsC)
    64  	defer closer()
    65  
    66  	var ids []string
    67  	for _, uuid := range uuids {
    68  		ids = append(ids, uuid+":e")
    69  	}
    70  
    71  	iter := coll.Find(bson.M{"_id": bson.M{"$in": ids}}).Iter()
    72  	defer iter.Close()
    73  
    74  	var ops []txn.Op
    75  	var doc settingsDoc
    76  	for iter.Next(&doc) {
    77  		settingsChanged, err := change(&doc)
    78  		if err != nil {
    79  			return errors.Trace(err)
    80  		}
    81  		if settingsChanged {
    82  			ops = append(ops, txn.Op{
    83  				C:      settingsC,
    84  				Id:     doc.DocID,
    85  				Assert: txn.DocExists,
    86  				Update: bson.M{"$set": bson.M{"settings": doc.Settings}},
    87  			})
    88  		}
    89  	}
    90  	if err := iter.Close(); err != nil {
    91  		return errors.Trace(err)
    92  	}
    93  	if len(ops) > 0 {
    94  		return errors.Trace(st.runRawTransaction(ops))
    95  	}
    96  	return nil
    97  }