github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/provider/maas/instance.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package maas 5 6 import ( 7 "fmt" 8 "strings" 9 10 "github.com/juju/errors" 11 "github.com/juju/gomaasapi/v2" 12 13 "github.com/juju/juju/core/instance" 14 corenetwork "github.com/juju/juju/core/network" 15 "github.com/juju/juju/core/network/firewall" 16 "github.com/juju/juju/core/status" 17 "github.com/juju/juju/environs/context" 18 ) 19 20 type maasInstance struct { 21 machine gomaasapi.Machine 22 constraintMatches gomaasapi.ConstraintMatches 23 environ *maasEnviron 24 } 25 26 func (mi *maasInstance) zone() (string, error) { 27 return mi.machine.Zone().Name(), nil 28 } 29 30 func (mi *maasInstance) hostname() (string, error) { 31 return mi.machine.Hostname(), nil 32 } 33 34 func (mi *maasInstance) hardwareCharacteristics() (*instance.HardwareCharacteristics, error) { 35 nodeArch := strings.Split(mi.machine.Architecture(), "/")[0] 36 nodeCpuCount := uint64(mi.machine.CPUCount()) 37 nodeMemoryMB := uint64(mi.machine.Memory()) 38 // zone can't error on the maasInstance implementation. 39 zone, _ := mi.zone() 40 tags := mi.machine.Tags() 41 hc := &instance.HardwareCharacteristics{ 42 Arch: &nodeArch, 43 CpuCores: &nodeCpuCount, 44 Mem: &nodeMemoryMB, 45 AvailabilityZone: &zone, 46 Tags: &tags, 47 } 48 return hc, nil 49 } 50 51 func (mi *maasInstance) displayName() (string, error) { 52 hostname := mi.machine.Hostname() 53 if hostname != "" { 54 return hostname, nil 55 } 56 return mi.machine.FQDN(), nil 57 } 58 59 func (mi *maasInstance) String() string { 60 return fmt.Sprintf("%s:%s", mi.machine.Hostname(), mi.machine.SystemID()) 61 } 62 63 func (mi *maasInstance) Id() instance.Id { 64 return instance.Id(mi.machine.SystemID()) 65 } 66 67 func (mi *maasInstance) Addresses(ctx context.ProviderCallContext) (corenetwork.ProviderAddresses, error) { 68 subnetsMap, err := mi.environ.subnetToSpaceIds(ctx) 69 if err != nil { 70 return nil, errors.Trace(err) 71 } 72 // Get all the interface details and extract the addresses. 73 interfaces, err := maasNetworkInterfaces(ctx, mi, subnetsMap) 74 75 if err != nil { 76 return nil, errors.Trace(err) 77 } 78 79 var addresses []corenetwork.ProviderAddress 80 for _, iface := range interfaces { 81 if primAddr := iface.PrimaryAddress(); primAddr.Value != "" { 82 addresses = append(addresses, primAddr) 83 } else { 84 logger.Debugf("no address found on interface %q", iface.InterfaceName) 85 } 86 } 87 88 logger.Debugf("%q has addresses %q", mi.machine.Hostname(), addresses) 89 return addresses, nil 90 } 91 92 // Status returns a juju status based on the maas instance returned 93 // status message. 94 func (mi *maasInstance) Status(ctx context.ProviderCallContext) instance.Status { 95 // A fresh status is not obtained here because the interface it is intended 96 // to satisfy gets a new maasInstance before each call, using a fresh status 97 // would cause us to mask errors since this interface does not contemplate 98 // returning them. 99 statusName := mi.machine.StatusName() 100 statusMsg := mi.machine.StatusMessage() 101 return convertInstanceStatus(statusName, statusMsg, mi.Id()) 102 } 103 104 func convertInstanceStatus(statusMsg, substatus string, id instance.Id) instance.Status { 105 maasInstanceStatus := status.Empty 106 switch normalizeStatus(statusMsg) { 107 case "": 108 logger.Debugf("unable to obtain status of instance %s", id) 109 statusMsg = "error in getting status" 110 case "deployed": 111 maasInstanceStatus = status.Running 112 case "deploying": 113 maasInstanceStatus = status.Allocating 114 if substatus != "" { 115 statusMsg = fmt.Sprintf("%s: %s", statusMsg, substatus) 116 } 117 case "failed deployment": 118 maasInstanceStatus = status.ProvisioningError 119 if substatus != "" { 120 statusMsg = fmt.Sprintf("%s: %s", statusMsg, substatus) 121 } 122 default: 123 maasInstanceStatus = status.Empty 124 statusMsg = fmt.Sprintf("%s: %s", statusMsg, substatus) 125 } 126 return instance.Status{ 127 Status: maasInstanceStatus, 128 Message: statusMsg, 129 } 130 } 131 132 func normalizeStatus(statusMsg string) string { 133 return strings.ToLower(strings.TrimSpace(statusMsg)) 134 } 135 136 // MAAS does not do firewalling so these port methods do nothing. 137 138 func (mi *maasInstance) OpenPorts(_ context.ProviderCallContext, _ string, _ firewall.IngressRules) error { 139 logger.Debugf("unimplemented OpenPorts() called") 140 return nil 141 } 142 143 func (mi *maasInstance) ClosePorts(_ context.ProviderCallContext, _ string, _ firewall.IngressRules) error { 144 logger.Debugf("unimplemented ClosePorts() called") 145 return nil 146 } 147 148 func (mi *maasInstance) IngressRules(_ context.ProviderCallContext, _ string) (firewall.IngressRules, error) { 149 logger.Debugf("unimplemented IngressRules() called") 150 return nil, nil 151 }