host.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. // Copyright 2019 Yunion
  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. package azure
  15. import (
  16. "fmt"
  17. "strings"
  18. "time"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/util/osprofile"
  23. "yunion.io/x/pkg/util/seclib"
  24. "yunion.io/x/pkg/utils"
  25. api "yunion.io/x/cloudmux/pkg/apis/compute"
  26. "yunion.io/x/cloudmux/pkg/cloudprovider"
  27. "yunion.io/x/cloudmux/pkg/multicloud"
  28. )
  29. type SHost struct {
  30. multicloud.SHostBase
  31. zone *SZone
  32. }
  33. func (self *SHost) GetId() string {
  34. return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId())
  35. }
  36. func (self *SHost) GetName() string {
  37. return fmt.Sprintf("%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId)
  38. }
  39. func (self *SHost) GetGlobalId() string {
  40. return fmt.Sprintf("%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId)
  41. }
  42. func (self *SHost) IsEmulated() bool {
  43. return true
  44. }
  45. func (self *SHost) GetStatus() string {
  46. return api.HOST_STATUS_RUNNING
  47. }
  48. func (self *SHost) Refresh() error {
  49. return nil
  50. }
  51. func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
  52. secgroupId := ""
  53. for _, id := range desc.ExternalSecgroupIds {
  54. secgroupId = id
  55. }
  56. nic, err := self.zone.region.CreateNetworkInterface(desc.ProjectId, fmt.Sprintf("%s-ipconfig", desc.NameEn), desc.IpAddr, desc.ExternalNetworkId, secgroupId)
  57. if err != nil {
  58. return nil, errors.Wrapf(err, "CreateNetworkInterface")
  59. }
  60. instance, err := self.zone.region._createVM(desc, nic.ID)
  61. if err != nil {
  62. cloudprovider.Wait(time.Minute*2, time.Minute*6, func() (bool, error) {
  63. e := self.zone.region.DeleteNetworkInterface(nic.ID)
  64. if e == nil {
  65. return true, nil
  66. }
  67. log.Errorf("delete nic %s error: %v", nic.ID, err)
  68. return false, nil
  69. })
  70. return nil, err
  71. }
  72. instance.host = self
  73. return instance, nil
  74. }
  75. func (self *SRegion) _createVM(desc *cloudprovider.SManagedVMCreateConfig, nicId string) (*SInstance, error) {
  76. image, err := self.GetImageById(desc.ExternalImageId)
  77. if err != nil {
  78. return nil, errors.Wrapf(err, "GetImageById(%s)", desc.ExternalImageId)
  79. }
  80. if len(desc.Password) == 0 {
  81. //Azure创建必须要设置密码
  82. desc.Password = seclib.RandomPassword2(12)
  83. }
  84. if image.Properties.ProvisioningState != ImageStatusAvailable {
  85. return nil, fmt.Errorf("image %s not ready status: %s", desc.ExternalImageId, image.Properties.ProvisioningState)
  86. }
  87. if !utils.IsInStringArray(desc.OsType, []string{osprofile.OS_TYPE_LINUX, osprofile.OS_TYPE_WINDOWS}) {
  88. desc.OsType = string(image.GetOsType())
  89. }
  90. computeName := desc.Hostname
  91. for _, k := range "`~!@#$%^&*()=+_[]{}\\|;:.'\",<>/?" {
  92. computeName = strings.Replace(computeName, string(k), "", -1)
  93. }
  94. if len(computeName) > 15 {
  95. computeName = computeName[:15]
  96. }
  97. osProfile := map[string]string{
  98. "ComputerName": computeName,
  99. "AdminUsername": api.VM_AZURE_DEFAULT_LOGIN_USER,
  100. "AdminPassword": desc.Password,
  101. }
  102. if len(desc.UserData) > 0 {
  103. osProfile["CustomData"] = desc.UserData
  104. }
  105. params := jsonutils.Marshal(map[string]interface{}{
  106. "Name": desc.NameEn,
  107. "Location": self.Name,
  108. "Properties": map[string]interface{}{
  109. "HardwareProfile": map[string]string{
  110. "VMSize": "",
  111. },
  112. "OsProfile": osProfile,
  113. "NetworkProfile": map[string]interface{}{
  114. "NetworkInterfaces": []map[string]string{
  115. map[string]string{
  116. "Id": nicId,
  117. "deleteOption": "Delete",
  118. },
  119. },
  120. },
  121. "StorageProfile": map[string]interface{}{
  122. "ImageReference": image.getImageReference(),
  123. "OsDisk": map[string]interface{}{
  124. "Name": fmt.Sprintf("vdisk_%s_%d", desc.Name, time.Now().UnixNano()),
  125. "Caching": "ReadWrite",
  126. "ManagedDisk": map[string]string{
  127. "StorageAccountType": desc.SysDisk.StorageType,
  128. },
  129. "CreateOption": "FromImage",
  130. "DiskSizeGB": desc.SysDisk.SizeGB,
  131. "OsType": desc.OsType,
  132. },
  133. },
  134. },
  135. "Type": "Microsoft.Compute/virtualMachines",
  136. }).(*jsonutils.JSONDict)
  137. if len(desc.PublicKey) > 0 && desc.OsType == osprofile.OS_TYPE_LINUX {
  138. linuxConfiguration := map[string]interface{}{
  139. "DisablePasswordAuthentication": false,
  140. "SSH": map[string]interface{}{
  141. "PublicKeys": []map[string]string{
  142. map[string]string{
  143. "KeyData": desc.PublicKey,
  144. "Path": fmt.Sprintf("/home/%s/.ssh/authorized_keys", api.VM_AZURE_DEFAULT_LOGIN_USER),
  145. },
  146. },
  147. },
  148. }
  149. params.Add(jsonutils.Marshal(linuxConfiguration), "Properties", "OsProfile", "LinuxConfiguration")
  150. }
  151. if len(desc.Tags) > 0 {
  152. params.Add(jsonutils.Marshal(desc.Tags), "tags")
  153. }
  154. dataDisks := jsonutils.NewArray()
  155. for i := 0; i < len(desc.DataDisks); i++ {
  156. dataDisk := jsonutils.Marshal(map[string]interface{}{
  157. "Name": fmt.Sprintf("vdisk_%s_%d", desc.Name, time.Now().UnixNano()),
  158. "DiskSizeGB": desc.DataDisks[i].SizeGB,
  159. "CreateOption": "Empty",
  160. "ManagedDisk": map[string]string{
  161. "StorageAccountType": desc.DataDisks[i].StorageType,
  162. },
  163. "Lun": i,
  164. })
  165. dataDisks.Add(dataDisk)
  166. }
  167. if dataDisks.Length() > 0 {
  168. params.Add(dataDisks, "Properties", "StorageProfile", "DataDisks")
  169. }
  170. instance := &SInstance{}
  171. if len(desc.InstanceType) > 0 {
  172. params.Add(jsonutils.NewString(desc.InstanceType), "Properties", "HardwareProfile", "VMSize")
  173. log.Debugf("Try HardwareProfile : %s", desc.InstanceType)
  174. err = self.create(desc.ProjectId, params, instance)
  175. if err != nil {
  176. return nil, errors.Wrapf(err, "create")
  177. }
  178. return instance, nil
  179. }
  180. for _, profile := range self.getHardwareProfile(desc.Cpu, desc.MemoryMB) {
  181. params.Add(jsonutils.NewString(profile), "Properties", "HardwareProfile", "VMSize")
  182. log.Debugf("Try HardwareProfile : %s", profile)
  183. err = self.create(desc.ProjectId, params, &instance)
  184. if err != nil {
  185. for _, key := range []string{`"code":"InvalidParameter"`, `"code":"NicInUse"`} {
  186. if strings.Contains(err.Error(), key) {
  187. return nil, err
  188. }
  189. }
  190. log.Errorf("Failed for %s: %s", profile, err)
  191. continue
  192. }
  193. return instance, nil
  194. }
  195. if err != nil {
  196. return nil, err
  197. }
  198. return nil, fmt.Errorf("instance type %dC%dMB not avaiable", desc.Cpu, desc.MemoryMB)
  199. }
  200. func (self *SHost) GetAccessIp() string {
  201. return ""
  202. }
  203. func (self *SHost) GetAccessMac() string {
  204. return ""
  205. }
  206. func (self *SHost) GetCpuCount() int {
  207. return 0
  208. }
  209. func (self *SHost) GetCpuDesc() string {
  210. return ""
  211. }
  212. func (self *SHost) GetCpuMhz() int {
  213. return 0
  214. }
  215. func (self *SHost) GetMemSizeMB() int {
  216. return 0
  217. }
  218. func (self *SHost) GetEnabled() bool {
  219. return true
  220. }
  221. func (self *SHost) GetHostStatus() string {
  222. return api.HOST_ONLINE
  223. }
  224. func (self *SHost) GetNodeCount() int8 {
  225. return 0
  226. }
  227. func (self *SHost) GetHostType() string {
  228. return api.HOST_TYPE_AZURE
  229. }
  230. func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
  231. return self.zone.GetIStorageById(id)
  232. }
  233. func (self *SHost) GetSysInfo() jsonutils.JSONObject {
  234. info := jsonutils.NewDict()
  235. info.Add(jsonutils.NewString(CLOUD_PROVIDER_AZURE), "manufacture")
  236. return info
  237. }
  238. func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
  239. return self.zone.getIStorages(), nil
  240. }
  241. func (self *SHost) GetIVMById(instanceId string) (cloudprovider.ICloudVM, error) {
  242. instance, err := self.zone.region.GetInstance(instanceId)
  243. if err != nil {
  244. return nil, err
  245. }
  246. instance.host = self
  247. return instance, nil
  248. }
  249. func (self *SHost) GetStorageSizeMB() int64 {
  250. return 0
  251. }
  252. func (self *SHost) GetStorageType() string {
  253. return api.DISK_TYPE_HYBRID
  254. }
  255. func (self *SHost) GetSN() string {
  256. return ""
  257. }
  258. func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
  259. vms, err := self.zone.region.GetInstances()
  260. if err != nil {
  261. return nil, err
  262. }
  263. ivms := make([]cloudprovider.ICloudVM, len(vms))
  264. for i := 0; i < len(vms); i++ {
  265. vms[i].host = self
  266. ivms[i] = &vms[i]
  267. }
  268. return ivms, nil
  269. }
  270. func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
  271. wires, err := host.zone.GetIWires()
  272. if err != nil {
  273. return nil, errors.Wrap(err, "GetIWires")
  274. }
  275. return cloudprovider.GetHostNetifs(host, wires), nil
  276. }
  277. func (host *SHost) GetIsMaintenance() bool {
  278. return false
  279. }
  280. func (host *SHost) GetVersion() string {
  281. return AZURE_API_VERSION
  282. }