github.com/rigado/snapd@v2.42.5-go-mod+incompatible/overlord/configstate/configcore/cloud.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2018 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package configcore 21 22 import ( 23 "encoding/json" 24 "io/ioutil" 25 "os" 26 27 "github.com/snapcore/snapd/dirs" 28 "github.com/snapcore/snapd/logger" 29 "github.com/snapcore/snapd/overlord/auth" 30 "github.com/snapcore/snapd/overlord/configstate/config" 31 "github.com/snapcore/snapd/overlord/state" 32 ) 33 34 func alreadySeeded(tr config.Conf) (bool, error) { 35 st := tr.State() 36 st.Lock() 37 defer st.Unlock() 38 var seeded bool 39 err := tr.State().Get("seeded", &seeded) 40 if err != nil && err != state.ErrNoState { 41 return false, err 42 } 43 return seeded, nil 44 } 45 46 type cloudInitInstanceData struct { 47 V1 struct { 48 Region string 49 Name string 50 AvailabilityZone string 51 } 52 } 53 54 func (c *cloudInitInstanceData) UnmarshalJSON(bs []byte) error { 55 var instanceDataJSON struct { 56 V1 struct { 57 Region string `json:"region"` 58 // these fields can come with - or _ as separators 59 Name string `json:"cloud_name"` 60 AltName string `json:"cloud-name"` 61 AvailabilityZone string `json:"availability_zone"` 62 AltAvailabilityZone string `json:"availability-zone"` 63 } `json:"v1"` 64 } 65 66 if err := json.Unmarshal(bs, &instanceDataJSON); err != nil { 67 return err 68 } 69 70 c.V1.Region = instanceDataJSON.V1.Region 71 switch { 72 case instanceDataJSON.V1.Name != "": 73 c.V1.Name = instanceDataJSON.V1.Name 74 c.V1.AvailabilityZone = instanceDataJSON.V1.AvailabilityZone 75 case instanceDataJSON.V1.AltName != "": 76 c.V1.Name = instanceDataJSON.V1.AltName 77 c.V1.AvailabilityZone = instanceDataJSON.V1.AltAvailabilityZone 78 } 79 return nil 80 } 81 82 func setCloudInfoWhenSeeding(tr config.Conf) error { 83 // if we are during seeding try to capture cloud information 84 seeded, err := alreadySeeded(tr) 85 if err != nil { 86 return err 87 } 88 if seeded { 89 // already done 90 return nil 91 } 92 93 data, err := ioutil.ReadFile(dirs.CloudInstanceDataFile) 94 if os.IsNotExist(err) { 95 // nothing to do 96 return nil 97 } 98 if err != nil { 99 logger.Noticef("cannot read cloud instance information %q: %v", dirs.CloudInstanceDataFile, err) 100 return nil 101 } 102 103 var instanceData cloudInitInstanceData 104 err = json.Unmarshal(data, &instanceData) 105 if err != nil { 106 logger.Noticef("cannot unmarshal cloud instance information %q: %v", dirs.CloudInstanceDataFile, err) 107 return nil 108 } 109 110 cloudName := instanceData.V1.Name 111 if cloudName == "" || cloudName == "nocloud" || cloudName == "none" { 112 // not a cloud 113 return nil 114 } 115 116 tr.Set("core", "cloud", auth.CloudInfo{ 117 Name: cloudName, 118 Region: instanceData.V1.Region, 119 AvailabilityZone: instanceData.V1.AvailabilityZone, 120 }) 121 return nil 122 }