go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/gce/api/config/v1/vm.go (about) 1 // Copyright 2018 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package config 16 17 import ( 18 "strings" 19 20 "google.golang.org/protobuf/proto" 21 22 "go.chromium.org/luci/config/validation" 23 "go.chromium.org/luci/gae/service/datastore" 24 ) 25 26 // Ensure VM implements datastore.PropertyConverter. 27 // This allows VMs to be read from and written to the datastore. 28 var _ datastore.PropertyConverter = &VM{} 29 30 // FromProperty implements datastore.PropertyConverter. 31 func (v *VM) FromProperty(p datastore.Property) error { 32 if p.Value() == nil { 33 v = &VM{} 34 return nil 35 } 36 return proto.Unmarshal(p.Value().([]byte), v) 37 } 38 39 // ToProperty implements datastore.PropertyConverter. 40 func (v *VM) ToProperty() (datastore.Property, error) { 41 p := datastore.Property{} 42 bytes, err := proto.Marshal(v) 43 if err != nil { 44 return datastore.Property{}, err 45 } 46 // noindex is not respected in the tags in the model. 47 return p, p.SetValue(bytes, datastore.NoIndex) 48 } 49 50 // SetZone sets the given zone throughout this VM. 51 func (v *VM) SetZone(zone string) { 52 for _, disk := range v.GetDisk() { 53 disk.Type = strings.Replace(disk.Type, "{{.Zone}}", zone, -1) 54 } 55 v.MachineType = strings.Replace(v.GetMachineType(), "{{.Zone}}", zone, -1) 56 v.Zone = zone 57 } 58 59 // Validate validates this VM description. 60 // Metadata FromFile must already be converted to FromText. 61 func (v *VM) Validate(c *validation.Context) { 62 if len(v.GetDisk()) == 0 { 63 c.Errorf("at least one disk is required") 64 } 65 for i, d := range v.GetDisk() { 66 c.Enter("disk %d", i) 67 d.Validate(c) 68 c.Exit() 69 } 70 if v.GetMachineType() == "" { 71 c.Errorf("machine type is required") 72 } 73 for i, meta := range v.GetMetadata() { 74 c.Enter("metadata %d", i) 75 // Implicitly rejects FromFile. 76 // FromFile must be converted to FromText before calling. 77 if !strings.Contains(meta.GetFromText(), ":") { 78 c.Errorf("metadata from text must be in key:value form") 79 } 80 c.Exit() 81 } 82 if len(v.GetNetworkInterface()) == 0 { 83 c.Errorf("at least one network interface is required") 84 } 85 if v.GetProject() == "" { 86 c.Errorf("project is required") 87 } 88 if v.GetZone() == "" { 89 c.Errorf("zone is required") 90 } 91 }