github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/constraints.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state 5 6 import ( 7 "fmt" 8 9 "github.com/juju/errors" 10 "github.com/juju/mgo/v3" 11 "github.com/juju/mgo/v3/bson" 12 "github.com/juju/mgo/v3/txn" 13 14 "github.com/juju/juju/core/constraints" 15 "github.com/juju/juju/core/instance" 16 ) 17 18 // constraintsDoc is the Mongo DB representation of a constraints.Value. 19 type constraintsDoc struct { 20 DocID string `bson:"_id,omitempty"` 21 ModelUUID string `bson:"model-uuid"` 22 Arch *string 23 CpuCores *uint64 24 CpuPower *uint64 25 Mem *uint64 26 RootDisk *uint64 27 RootDiskSource *string 28 InstanceRole *string 29 InstanceType *string 30 Container *instance.ContainerType 31 Tags *[]string 32 Spaces *[]string 33 VirtType *string 34 Zones *[]string 35 AllocatePublicIP *bool 36 ImageID *string 37 } 38 39 func newConstraintsDoc(cons constraints.Value, id string) constraintsDoc { 40 result := constraintsDoc{ 41 DocID: id, 42 Arch: cons.Arch, 43 CpuCores: cons.CpuCores, 44 CpuPower: cons.CpuPower, 45 Mem: cons.Mem, 46 RootDisk: cons.RootDisk, 47 RootDiskSource: cons.RootDiskSource, 48 InstanceRole: cons.InstanceRole, 49 InstanceType: cons.InstanceType, 50 Container: cons.Container, 51 Tags: cons.Tags, 52 Spaces: cons.Spaces, 53 VirtType: cons.VirtType, 54 Zones: cons.Zones, 55 AllocatePublicIP: cons.AllocatePublicIP, 56 ImageID: cons.ImageID, 57 } 58 return result 59 } 60 61 func (doc constraintsDoc) value() constraints.Value { 62 result := constraints.Value{ 63 Arch: doc.Arch, 64 CpuCores: doc.CpuCores, 65 CpuPower: doc.CpuPower, 66 Mem: doc.Mem, 67 RootDisk: doc.RootDisk, 68 RootDiskSource: doc.RootDiskSource, 69 InstanceRole: doc.InstanceRole, 70 InstanceType: doc.InstanceType, 71 Container: doc.Container, 72 Tags: doc.Tags, 73 Spaces: doc.Spaces, 74 VirtType: doc.VirtType, 75 Zones: doc.Zones, 76 AllocatePublicIP: doc.AllocatePublicIP, 77 ImageID: doc.ImageID, 78 } 79 return result 80 } 81 82 // Constraints represents the state of a constraints with an ID. 83 type Constraints struct { 84 doc constraintsDoc 85 } 86 87 // ID returns the Mongo document ID for the constraints instance. 88 func (c *Constraints) ID() string { 89 return c.doc.DocID 90 } 91 92 // Value returns the constraints.Value represented by the Constraints' 93 // Mongo document. 94 func (c *Constraints) Value() constraints.Value { 95 return c.doc.value() 96 } 97 98 // ChangeSpaceNameOps returns the transaction operations required to rename 99 // a space used in these constraints. 100 func (c *Constraints) ChangeSpaceNameOps(from, to string) []txn.Op { 101 val := c.doc.value() 102 spaces := val.Spaces 103 if spaces == nil { 104 return nil 105 } 106 107 for i, space := range *spaces { 108 if space == from { 109 (*spaces)[i] = to 110 break 111 } 112 if space == "^"+from { 113 (*spaces)[i] = "^" + to 114 } 115 } 116 117 return []txn.Op{setConstraintsOp(c.ID(), val)} 118 } 119 120 // AllConstraints returns all constraints in the collection. 121 func (st *State) AllConstraints() ([]*Constraints, error) { 122 constraintsCollection, closer := st.db().GetCollection(constraintsC) 123 defer closer() 124 var docs []constraintsDoc 125 err := constraintsCollection.Find(nil).All(&docs) 126 127 cons := make([]*Constraints, len(docs)) 128 for i, doc := range docs { 129 cons[i] = &Constraints{doc: doc} 130 } 131 return cons, err 132 } 133 134 // ConstraintsBySpaceName returns all Constraints that include a positive 135 // or negative space constraint for the input space name. 136 func (st *State) ConstraintsBySpaceName(spaceName string) ([]*Constraints, error) { 137 constraintsCollection, closer := st.db().GetCollection(constraintsC) 138 defer closer() 139 140 var docs []constraintsDoc 141 query := bson.D{{"$or", []bson.D{ 142 {{"spaces", spaceName}}, 143 {{"spaces", "^" + spaceName}}, 144 }}} 145 err := constraintsCollection.Find(query).All(&docs) 146 147 cons := make([]*Constraints, len(docs)) 148 for i, doc := range docs { 149 cons[i] = &Constraints{doc: doc} 150 } 151 return cons, err 152 } 153 154 func createConstraintsOp(id string, cons constraints.Value) txn.Op { 155 return txn.Op{ 156 C: constraintsC, 157 Id: id, 158 Assert: txn.DocMissing, 159 Insert: newConstraintsDoc(cons, id), 160 } 161 } 162 163 func setConstraintsOp(id string, cons constraints.Value) txn.Op { 164 return txn.Op{ 165 C: constraintsC, 166 Id: id, 167 Assert: txn.DocExists, 168 Update: bson.D{{"$set", newConstraintsDoc(cons, id)}}, 169 } 170 } 171 172 func removeConstraintsOp(id string) txn.Op { 173 return txn.Op{ 174 C: constraintsC, 175 Id: id, 176 Remove: true, 177 } 178 } 179 180 func readConstraints(mb modelBackend, id string) (constraints.Value, error) { 181 constraintsCollection, closer := mb.db().GetCollection(constraintsC) 182 defer closer() 183 184 var doc constraintsDoc 185 if err := constraintsCollection.FindId(id).One(&doc); err == mgo.ErrNotFound { 186 return constraints.Value{}, errors.NotFoundf("constraints") 187 } else if err != nil { 188 return constraints.Value{}, err 189 } 190 return doc.value(), nil 191 } 192 193 func writeConstraints(mb modelBackend, id string, cons constraints.Value) error { 194 ops := []txn.Op{setConstraintsOp(id, cons)} 195 if err := mb.db().RunTransaction(ops); err != nil { 196 return fmt.Errorf("cannot set constraints: %v", err) 197 } 198 return nil 199 } 200 201 // AllConstraints retrieves all the constraints in the model 202 // and provides a way to query based on machine or application. 203 func (m *Model) AllConstraints() (*ModelConstraints, error) { 204 coll, closer := m.st.db().GetCollection(constraintsC) 205 defer closer() 206 207 var docs []constraintsDoc 208 err := coll.Find(nil).All(&docs) 209 if err != nil { 210 return nil, errors.Annotate(err, "cannot get all constraints for model") 211 } 212 all := &ModelConstraints{ 213 data: make(map[string]constraintsDoc), 214 } 215 for _, doc := range docs { 216 all.data[m.localID(doc.DocID)] = doc 217 } 218 return all, nil 219 } 220 221 // ModelConstraints represents all the constraints in a model 222 // keyed on global key. 223 type ModelConstraints struct { 224 data map[string]constraintsDoc 225 } 226 227 // Machine returns the constraints for the specified machine. 228 func (c *ModelConstraints) Machine(machineID string) constraints.Value { 229 doc, found := c.data[machineGlobalKey(machineID)] 230 if !found { 231 return constraints.Value{} 232 } 233 return doc.value() 234 } 235 236 // TODO: add methods for Model and Application constraints checks 237 // if desired. Not currently used in status calls.