cloudaccounts_prepare.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  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 models
  15. import (
  16. "context"
  17. "fmt"
  18. "sort"
  19. "yunion.io/x/cloudmux/pkg/cloudprovider"
  20. "yunion.io/x/cloudmux/pkg/multicloud/esxi"
  21. "yunion.io/x/jsonutils"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/pkg/util/httputils"
  24. "yunion.io/x/pkg/util/netutils"
  25. "yunion.io/x/pkg/util/rbacscope"
  26. proxyapi "yunion.io/x/onecloud/pkg/apis/cloudcommon/proxy"
  27. api "yunion.io/x/onecloud/pkg/apis/compute"
  28. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  29. "yunion.io/x/onecloud/pkg/cloudcommon/db/proxy"
  30. "yunion.io/x/onecloud/pkg/compute/options"
  31. "yunion.io/x/onecloud/pkg/httperrors"
  32. "yunion.io/x/onecloud/pkg/mcclient"
  33. )
  34. type sNetworkInfo struct {
  35. esxi.SNetworkInfo
  36. prefix string
  37. }
  38. func (scm *SCloudaccountManager) hostVMIPsPrepareNets(ctx context.Context, client *esxi.SESXiClient,
  39. input api.CloudaccountPerformPrepareNetsInput) ([]sNetworkInfo, error) {
  40. caName := input.Name
  41. wireLevel := input.WireLevelForVmware
  42. ret := make([]sNetworkInfo, 0)
  43. if len(wireLevel) == 0 {
  44. wireLevel = api.CLOUD_ACCOUNT_WIRE_LEVEL_VCENTER
  45. }
  46. switch wireLevel {
  47. case api.CLOUD_ACCOUNT_WIRE_LEVEL_VCENTER:
  48. nInfo, err := client.HostVmIPs(ctx)
  49. if err != nil {
  50. return nil, errors.Wrap(err, "unable to fetch ips of hosts and vms")
  51. }
  52. ret = append(ret, sNetworkInfo{
  53. SNetworkInfo: nInfo,
  54. prefix: caName,
  55. })
  56. case api.CLOUD_ACCOUNT_WIRE_LEVEL_DATACENTER:
  57. dcs, err := client.GetDatacenters()
  58. if err != nil {
  59. return ret, errors.Wrap(err, "GetDatacenters")
  60. }
  61. for _, dc := range dcs {
  62. nInfo, err := client.HostVmIPsInDc(ctx, dc)
  63. if err != nil {
  64. return ret, errors.Wrapf(err, "unable to fetch ips of hosts and vms for dc %q", dc.GetName())
  65. }
  66. ret = append(ret, sNetworkInfo{
  67. SNetworkInfo: nInfo,
  68. prefix: fmt.Sprintf("%s/%s", caName, dc.GetName()),
  69. })
  70. }
  71. case api.CLOUD_ACCOUNT_WIRE_LEVEL_CLUSTER:
  72. dcs, err := client.GetDatacenters()
  73. if err != nil {
  74. return ret, errors.Wrap(err, "GetDatacenters")
  75. }
  76. for _, dc := range dcs {
  77. clusters, err := dc.ListClusters()
  78. if err != nil {
  79. return nil, errors.Wrapf(err, "unable to ListCluster for dc %q", dc.GetName())
  80. }
  81. for _, cluster := range clusters {
  82. nInfo, err := client.HostVmIPsInCluster(ctx, cluster)
  83. if err != nil {
  84. return ret, errors.Wrapf(err, "unable to fetch ips of hosts and vms for dc %q cluster %q", dc.GetName(), cluster.GetName())
  85. }
  86. ret = append(ret, sNetworkInfo{
  87. SNetworkInfo: nInfo,
  88. prefix: fmt.Sprintf("%s/%s/%s", caName, dc.GetName(), cluster.GetName()),
  89. })
  90. }
  91. }
  92. default:
  93. return nil, httperrors.NewInputParameterError("valid wire_level_for_vmware, accept vcenter, datacenter, cluster")
  94. }
  95. return ret, nil
  96. }
  97. // Performpreparenets searches for suitable network facilities for physical and virtual machines under the cloud account or provides configuration recommendations for network facilities before importing a cloud account.
  98. func (scm *SCloudaccountManager) PerformPrepareNets(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudaccountPerformPrepareNetsInput) (api.CloudaccountPerformPrepareNetsOutput, error) {
  99. var (
  100. err error
  101. output api.CloudaccountPerformPrepareNetsOutput
  102. )
  103. if input.Provider != api.CLOUD_PROVIDER_VMWARE {
  104. return output, httperrors.NewNotSupportedError("not support for cloudaccount with provider '%s'", input.Provider)
  105. }
  106. // validate first
  107. ownerId, err := scm.FetchOwnerId(ctx, jsonutils.Marshal(input))
  108. if err != nil {
  109. return output, errors.Wrap(err, "FetchOwnerId in PerformPrepareNets")
  110. }
  111. if ownerId == nil {
  112. ownerId = userCred
  113. }
  114. // validate domain
  115. if len(input.ProjectDomainId) > 0 {
  116. _, input.DomainizedResourceInput, err = db.ValidateDomainizedResourceInput(ctx, input.DomainizedResourceInput)
  117. if err != nil {
  118. return output, err
  119. }
  120. }
  121. // Determine the zoneids according to esxiagent. If there is no esxiagent, zone0 is used by default. And the wires are filtered according to the specified domain and zoneids
  122. // make sure zone
  123. zoneids, err := scm.FetchEsxiZoneIds()
  124. if err != nil {
  125. return output, errors.Wrap(err, "unable to FetchEsxiZoneIds")
  126. }
  127. if len(zoneids) == 0 {
  128. id, err := scm.defaultZoneId(ctx, userCred)
  129. if err != nil {
  130. return output, errors.Wrap(err, "unable to fetch defaultZoneId")
  131. }
  132. zoneids = append(zoneids, id)
  133. }
  134. // Find the appropriate wire from above wires according to the Host's IP. The logic for finding is that the networks in the wire can contain the Host as much as possible. If no suitable one is found, a new wire is used.
  135. // fetch all Host
  136. factory, err := cloudprovider.GetProviderFactory(input.Provider)
  137. if err != nil {
  138. return output, errors.Wrap(err, "cloudprovider.GetProviderFactory")
  139. }
  140. input.SCloudaccount, err = factory.ValidateCreateCloudaccountData(ctx, input.SCloudaccountCredential)
  141. if err != nil {
  142. return output, errors.Wrap(err, "providerDriver.ValidateCreateCloudaccountData")
  143. }
  144. var proxyFunc httputils.TransportProxyFunc
  145. {
  146. if input.ProxySettingId == "" {
  147. input.ProxySettingId = proxyapi.ProxySettingId_DIRECT
  148. }
  149. var proxySetting *proxy.SProxySetting
  150. proxySetting, input.ProxySettingResourceInput, err = proxy.ValidateProxySettingResourceInput(ctx, userCred, input.ProxySettingResourceInput)
  151. if err != nil {
  152. return output, errors.Wrap(err, "ValidateProxySettingResourceInput")
  153. }
  154. proxyFunc = proxySetting.HttpTransportProxyFunc()
  155. }
  156. provider, err := factory.GetProvider(cloudprovider.ProviderConfig{
  157. Vendor: input.Provider,
  158. URL: input.AccessUrl,
  159. Account: input.Account,
  160. Secret: input.Secret,
  161. ProxyFunc: proxyFunc,
  162. Name: input.Name,
  163. RegionId: input.RegionId,
  164. AliyunResourceGroupIds: options.Options.AliyunResourceGroups,
  165. Options: input.Options,
  166. })
  167. if err != nil {
  168. return output, errors.Wrap(err, "factory.GetProvider")
  169. }
  170. iregion, err := provider.GetOnPremiseIRegion()
  171. if err != nil {
  172. return output, errors.Wrap(err, "provider.GetOnPremiseIRegion")
  173. }
  174. // hack
  175. client := iregion.(*esxi.SESXiClient)
  176. return scm.prepareNets(ctx, userCred, client, zoneids, input)
  177. }
  178. func (cam *SCloudaccountManager) prepareNets(ctx context.Context, userCred mcclient.TokenCredential,
  179. client *esxi.SESXiClient, zoneids []string, input api.CloudaccountPerformPrepareNetsInput) (api.CloudaccountPerformPrepareNetsOutput, error) {
  180. var output api.CloudaccountPerformPrepareNetsOutput
  181. obj, err := VpcManager.FetchById(api.DEFAULT_VPC_ID)
  182. if err != nil {
  183. return output, errors.Wrapf(err, "can not fetch vpc %q", api.DEFAULT_VPC_ID)
  184. }
  185. allNetworks, err := obj.(*SVpc).GetNetworks()
  186. if err != nil {
  187. return output, errors.Wrapf(err, "can not get networks of vpc %q", api.DEFAULT_VPC_ID)
  188. }
  189. existedIpPool := newIPPool(len(allNetworks))
  190. for i := range allNetworks {
  191. startIp, _ := netutils.NewIPV4Addr(allNetworks[i].GuestIpStart)
  192. endIp, _ := netutils.NewIPV4Addr(allNetworks[i].GuestIpEnd)
  193. existedIpPool.Insert(startIp, sSimpleNet{
  194. Diff: endIp - startIp,
  195. Vlan: int32(allNetworks[i].VlanId),
  196. Id: allNetworks[i].Id,
  197. })
  198. }
  199. if !input.Dvs {
  200. // fetch all wire candidate
  201. wires, err := cam.fetchWires(ctx, userCred, input.ProjectDomainId, zoneids)
  202. if err != nil {
  203. return output, errors.Wrap(err, "unable to fetch wires")
  204. }
  205. // fetch networks
  206. networks := make([][]SNetwork, len(wires))
  207. for i := range networks {
  208. nets, err := wires[i].getNetworks(ctx, userCred, userCred, rbacscope.ScopeSystem)
  209. if err != nil {
  210. return output, errors.Wrap(err, "wire.getNetwork")
  211. }
  212. networks[i] = nets
  213. }
  214. nInfos, err := cam.hostVMIPsPrepareNets(ctx, client, input)
  215. if err != nil {
  216. return output, err
  217. }
  218. return cam.parseAndSuggestSingleWire(sParseAndSuggest{
  219. NInfos: nInfos,
  220. AccountName: input.Name,
  221. ZoneIds: zoneids,
  222. Wires: wires,
  223. Networks: networks,
  224. ExistedIpPool: existedIpPool,
  225. }), nil
  226. }
  227. nInfo, err := client.HostVmIPsPro(ctx)
  228. if err != nil {
  229. return output, err
  230. }
  231. for name, ips := range nInfo.HostIps {
  232. ipNets := make([]api.CAIPNet, len(ips))
  233. for i, ip := range ips {
  234. var suitNetwork string
  235. if p, ok := existedIpPool.Get(ip); ok {
  236. suitNetwork = p.Id
  237. }
  238. ipNets[i] = api.CAIPNet{
  239. SuitableNetwork: suitNetwork,
  240. IP: ip.String(),
  241. }
  242. }
  243. output.Hosts = append(output.Hosts, api.CAGuestNet{
  244. Name: name,
  245. IPNets: ipNets,
  246. })
  247. }
  248. // output.Guests = cam.parseSimpleVms(nInfo.VMs, existedIpPool)
  249. vsList := nInfo.VsMap.List()
  250. for i := range vsList {
  251. vs := vsList[i]
  252. hosts := make([]api.SimpleHost, len(vs.Hosts))
  253. for i := range hosts {
  254. hosts[i] = api.SimpleHost{
  255. Id: vs.Hosts[i].Id,
  256. Name: vs.Hosts[i].Name,
  257. }
  258. }
  259. wire := api.CAPWire{
  260. Name: vs.Name,
  261. Id: vs.Id,
  262. Distributed: vs.Distributed,
  263. Hosts: hosts,
  264. }
  265. // preparenets for host
  266. for hName, ips := range vs.HostIps {
  267. if len(ips) == 0 {
  268. output.Hosts = append(output.Hosts, api.CAGuestNet{
  269. Name: hName,
  270. })
  271. }
  272. for j := 0; j < len(ips); j++ {
  273. baseNet := ips[j].NetAddr(24)
  274. ipWithSameNet := []netutils.IPV4Addr{ips[j]}
  275. for k := j + 1; k < len(ips); k++ {
  276. net := ips[k].NetAddr(24)
  277. if net != baseNet {
  278. break
  279. }
  280. ipWithSameNet = append(ipWithSameNet, ips[k])
  281. }
  282. ipLimitLow, ipLimitUp := ips[0], ips[len(ips)-1]
  283. simNetConfs := cam.expandIPRange(ips, ipLimitLow, ipLimitUp, func(proc esxi.SIPProc) bool {
  284. return proc.IsHost
  285. }, nInfo.IPPool, existedIpPool)
  286. for k := range simNetConfs {
  287. wire.HostNetworks = append(wire.HostNetworks, api.CANetConf{
  288. Name: fmt.Sprintf("host-network-%d", len(wire.HostNetworks)+1),
  289. CASimpleNetConf: simNetConfs[k],
  290. })
  291. }
  292. }
  293. }
  294. /*for vlan, ips := range vs.Vlans {
  295. simNetConfs := cam.expandIPRange(ips, 0, 0, func(proc esxi.SIPProc) bool {
  296. return proc.VlanId == vlan
  297. }, nInfo.IPPool, existedIpPool)
  298. for j := range simNetConfs {
  299. simNetConfs[j].VlanID = vlan
  300. wire.GuestNetworks = append(wire.GuestNetworks, api.CANetConf{
  301. Name: fmt.Sprintf("guest-network-%d", len(wire.GuestNetworks)+1),
  302. CASimpleNetConf: simNetConfs[j],
  303. })
  304. }
  305. }*/
  306. output.Wires = append(output.Wires, wire)
  307. }
  308. return output, nil
  309. }
  310. func (cam *SCloudaccountManager) parseSimpleVms(vms []esxi.SSimpleVM, existedIpPool *sIPPool) []api.CAGuestNet {
  311. guests := make([]api.CAGuestNet, len(vms))
  312. for i := range guests {
  313. guests[i].Name = vms[i].Name
  314. for _, ipVlan := range vms[i].IPVlans {
  315. var suitableNetwork string
  316. p, ok := existedIpPool.Get(ipVlan.IP)
  317. if ok {
  318. suitableNetwork = p.Id
  319. }
  320. guests[i].IPNets = append(guests[i].IPNets, api.CAIPNet{
  321. IP: ipVlan.IP.String(),
  322. VlanID: ipVlan.VlanId,
  323. SuitableNetwork: suitableNetwork,
  324. })
  325. }
  326. }
  327. return guests
  328. }
  329. func (cam *SCloudaccountManager) expandIPRange(ips []netutils.IPV4Addr, limitLow, limitUp netutils.IPV4Addr,
  330. expand func(esxi.SIPProc) bool, ipPool esxi.SIPPool, existedIpPool *sIPPool) []api.CASimpleNetConf {
  331. ret := make([]api.CASimpleNetConf, 0)
  332. for i := 0; i < len(ips); i++ {
  333. ip := ips[i]
  334. if _, ok := existedIpPool.Get(ip); ok {
  335. continue
  336. }
  337. net := ip.NetAddr(24)
  338. netLimitLow := net + 1
  339. netLimitUp := net + 254
  340. if limitLow != 0 && limitLow > netLimitLow {
  341. netLimitLow = limitLow
  342. }
  343. if limitUp != 0 && limitUp < netLimitUp {
  344. netLimitUp = limitUp
  345. }
  346. // find startip
  347. startIp := ip - 1
  348. for ; startIp >= netLimitLow; startIp-- {
  349. if _, ok := existedIpPool.Get(startIp); ok {
  350. break
  351. }
  352. if _, ok := ipPool.Get(startIp); ok {
  353. break
  354. }
  355. }
  356. endIp := ip + 1
  357. for ; endIp <= netLimitUp; endIp++ {
  358. if _, ok := existedIpPool.Get(endIp); ok {
  359. break
  360. }
  361. if proc, ok := ipPool.Get(endIp); ok {
  362. if expand(proc) {
  363. i++
  364. continue
  365. }
  366. break
  367. }
  368. }
  369. ret = append(ret, api.CASimpleNetConf{
  370. GuestIpStart: (startIp + 1).String(),
  371. GuestIpEnd: (endIp - 1).String(),
  372. GuestIpMask: 24,
  373. GuestGateway: (net + netutils.IPV4Addr(options.Options.DefaultNetworkGatewayAddressEsxi)).String(),
  374. })
  375. // Avoid assigning already assigned ip subnet
  376. existedIpPool.Insert(startIp+1, sSimpleNet{
  377. Diff: endIp - startIp - 2,
  378. })
  379. }
  380. return ret
  381. }
  382. type sParseAndSuggest struct {
  383. NInfos []sNetworkInfo
  384. AccountName string
  385. ZoneIds []string
  386. Wires []SWire
  387. Networks [][]SNetwork
  388. ExistedIpPool *sIPPool
  389. }
  390. type sIPPool struct {
  391. netranges []netutils.IPV4Addr
  392. simpleNetMap map[netutils.IPV4Addr]sSimpleNet
  393. }
  394. func newIPPool(length ...int) *sIPPool {
  395. initLen := 0
  396. if len(length) > 0 {
  397. initLen = length[0]
  398. }
  399. return &sIPPool{
  400. netranges: make([]netutils.IPV4Addr, 0, initLen),
  401. simpleNetMap: make(map[netutils.IPV4Addr]sSimpleNet, initLen),
  402. }
  403. }
  404. type sSimpleNet struct {
  405. Diff netutils.IPV4Addr
  406. Id string
  407. Vlan int32
  408. }
  409. func (pl *sIPPool) Insert(startIp netutils.IPV4Addr, sNet sSimpleNet) {
  410. // TODO:check
  411. index := pl.getIndex(startIp)
  412. pl.netranges = append(pl.netranges, 0)
  413. pl.netranges = append(pl.netranges[:index+1], pl.netranges[index:len(pl.netranges)-1]...)
  414. pl.netranges[index] = startIp
  415. pl.simpleNetMap[startIp] = sNet
  416. }
  417. func (pl *sIPPool) getIndex(ip netutils.IPV4Addr) int {
  418. index := sort.Search(len(pl.netranges), func(n int) bool {
  419. return pl.netranges[n] >= ip
  420. })
  421. return index
  422. }
  423. func (pl *sIPPool) Get(ip netutils.IPV4Addr) (sSimpleNet, bool) {
  424. index := pl.getIndex(ip)
  425. if index >= len(pl.netranges) || index < 0 {
  426. return sSimpleNet{}, false
  427. }
  428. if pl.netranges[index] == ip {
  429. return pl.simpleNetMap[ip], true
  430. }
  431. if index == 0 {
  432. return sSimpleNet{}, false
  433. }
  434. startIp := pl.netranges[index-1]
  435. simpleNet := pl.simpleNetMap[startIp]
  436. if ip-startIp <= simpleNet.Diff {
  437. return simpleNet, true
  438. }
  439. return sSimpleNet{}, false
  440. }
  441. func (scm *SCloudaccountManager) parseAndSuggestSingleWire(params sParseAndSuggest) api.CloudaccountPerformPrepareNetsOutput {
  442. var (
  443. output api.CloudaccountPerformPrepareNetsOutput
  444. nInfos = params.NInfos
  445. wires = params.Wires
  446. networks = params.Networks
  447. )
  448. output.CAWireNets = make([]api.CAWireNet, 0, len(nInfos))
  449. for _, ni := range nInfos {
  450. var (
  451. wireNet api.CAWireNet
  452. hostIps = ni.HostIps
  453. )
  454. // key of ipHosts is host's ip
  455. ipHosts := make(map[netutils.IPV4Addr]string, len(hostIps))
  456. for name, ip := range hostIps {
  457. ipHosts[ip] = name
  458. }
  459. // Find suitable wire and the network containing the Host IP in suitable wire.
  460. var (
  461. tmpSocre int
  462. maxScore = len(ipHosts)
  463. suitableWire *SWire
  464. suitableNetworks map[netutils.IPV4Addr]*SNetwork
  465. )
  466. for i, nets := range networks {
  467. score := 0
  468. tmpSNs := make(map[netutils.IPV4Addr]*SNetwork)
  469. ipRanges := make([]*netutils.IPV4AddrRange, len(nets))
  470. for i2 := range ipRanges {
  471. ipRanges[i2] = nets[i2].GetIPRange()
  472. }
  473. for ip := range ipHosts {
  474. for i := range ipRanges {
  475. if !ipRanges[i].Contains(ip) {
  476. continue
  477. }
  478. tmpSNs[ip] = &nets[i]
  479. score += 1
  480. break
  481. }
  482. }
  483. if score > tmpSocre {
  484. tmpSocre = score
  485. suitableWire = &wires[i]
  486. suitableNetworks = tmpSNs
  487. }
  488. if tmpSocre == maxScore {
  489. break
  490. }
  491. }
  492. if suitableWire != nil {
  493. wireNet.SuitableWire = suitableWire.GetId()
  494. } else {
  495. wireNet.SuggestedWire = api.CAWireConf{
  496. ZoneIds: params.ZoneIds,
  497. Name: ni.prefix + "-wire",
  498. Description: fmt.Sprintf("Auto created Wire for VMware account %q", params.AccountName),
  499. }
  500. }
  501. // Give the suggested network configuration for the Host IP that does not have a corresponding suitable network.
  502. noNetHostIP := make([]netutils.IPV4Addr, 0, len(ipHosts))
  503. for ip, name := range ipHosts {
  504. rnet := api.CAHostNet{
  505. Name: name,
  506. IP: ip.String(),
  507. }
  508. if net, ok := suitableNetworks[ip]; ok {
  509. rnet.SuitableNetwork = net.GetId()
  510. } else {
  511. noNetHostIP = append(noNetHostIP, ip)
  512. }
  513. wireNet.Hosts = append(wireNet.Hosts, rnet)
  514. }
  515. if len(noNetHostIP) > 0 {
  516. sConfs := scm.suggestHostNetworks(noNetHostIP)
  517. confs := make([]api.CANetConf, len(sConfs))
  518. for i := range confs {
  519. confs[i].CASimpleNetConf = sConfs[i]
  520. confs[i].Name = fmt.Sprintf("%s-host-network-%d", ni.prefix, i+1)
  521. }
  522. wireNet.HostSuggestedNetworks = confs
  523. }
  524. for i := range wireNet.HostSuggestedNetworks {
  525. ipStart, _ := netutils.NewIPV4Addr(wireNet.HostSuggestedNetworks[i].GuestIpStart)
  526. ipEnd, _ := netutils.NewIPV4Addr(wireNet.HostSuggestedNetworks[i].GuestIpEnd)
  527. params.ExistedIpPool.Insert(ipStart, sSimpleNet{
  528. Diff: ipEnd - ipStart,
  529. })
  530. }
  531. /* wireNet.Guests = scm.parseSimpleVms(ni.VMs, params.ExistedIpPool)
  532. for vlan, ips := range ni.VlanIps {
  533. simNetConfs := scm.expandIPRange(ips, 0, 0, func(proc esxi.SIPProc) bool {
  534. return proc.VlanId == vlan
  535. }, ni.IPPool, params.ExistedIpPool)
  536. for i := range simNetConfs {
  537. simNetConfs[i].VlanID = vlan
  538. wireNet.GuestSuggestedNetworks = append(wireNet.GuestSuggestedNetworks, api.CANetConf{
  539. Name: fmt.Sprintf("host-network-%d", len(wireNet.GuestSuggestedNetworks)+1),
  540. CASimpleNetConf: simNetConfs[i],
  541. })
  542. }
  543. }*/
  544. output.CAWireNets = append(output.CAWireNets, wireNet)
  545. }
  546. return output
  547. }
  548. func (manager *SCloudaccountManager) fetchWires(ctx context.Context, userCred mcclient.TokenCredential, domainId string, zoneIds []string) ([]SWire, error) {
  549. q := WireManager.Query().In("zone_id", zoneIds)
  550. if len(domainId) > 0 {
  551. ownerId := &db.SOwnerId{}
  552. ownerId.DomainId = domainId
  553. q = WireManager.FilterByOwner(ctx, q, WireManager, userCred, ownerId, rbacscope.ScopeDomain)
  554. } else {
  555. q = WireManager.FilterByOwner(ctx, q, WireManager, userCred, userCred, rbacscope.ScopeDomain)
  556. }
  557. wires := make([]SWire, 0, 1)
  558. err := db.FetchModelObjects(WireManager, q, &wires)
  559. return wires, err
  560. }
  561. func (manager *SCloudaccountManager) defaultZoneId(ctx context.Context, userCred mcclient.TokenCredential) (string, error) {
  562. zone, err := ZoneManager.FetchByName(ctx, userCred, "zone0")
  563. if err != nil {
  564. return "", err
  565. }
  566. return zone.GetId(), nil
  567. }
  568. func (manager *SCloudaccountManager) FetchEsxiZoneIds() ([]string, error) {
  569. q := BaremetalagentManager.Query().Equals("agent_type", "esxiagent").Asc("created_at")
  570. agents := make([]SBaremetalagent, 0, 1)
  571. err := db.FetchModelObjects(BaremetalagentManager, q, &agents)
  572. if err != nil {
  573. return nil, err
  574. }
  575. ids := make([]string, 0, len(agents))
  576. for i := range agents {
  577. if agents[i].Status == api.BAREMETAL_AGENT_ENABLED {
  578. ids = append(ids, agents[i].ZoneId)
  579. }
  580. }
  581. for i := range agents {
  582. if agents[i].Status != api.BAREMETAL_AGENT_ENABLED {
  583. ids = append(ids, agents[i].ZoneId)
  584. }
  585. }
  586. return ids, nil
  587. }
  588. // The suggestHostNetworks give the suggest config of network contains the ip in 'ips'.
  589. // The suggested network mask is 24 and the gateway is x.x.x.1.
  590. // The suggests network is the smallest network segment that meets the above conditions.
  591. func (manager *SCloudaccountManager) suggestHostNetworks(ips []netutils.IPV4Addr) []api.CASimpleNetConf {
  592. if len(ips) == 0 {
  593. return nil
  594. }
  595. sort.Slice(ips, func(i, j int) bool {
  596. return ips[i] < ips[j]
  597. })
  598. var (
  599. mask int8 = 24
  600. lastnetAddr netutils.IPV4Addr
  601. consequent []netutils.IPV4Addr
  602. ret []api.CASimpleNetConf
  603. )
  604. lastnetAddr = ips[0].NetAddr(mask)
  605. consequent = []netutils.IPV4Addr{ips[0]}
  606. for i := 1; i < len(ips); i++ {
  607. ip := ips[i]
  608. netAddr := ip.NetAddr(mask)
  609. if netAddr == lastnetAddr && consequent[len(consequent)-1]+1 == ip {
  610. consequent = append(consequent, ip)
  611. continue
  612. }
  613. if netAddr != lastnetAddr {
  614. lastnetAddr = netAddr
  615. }
  616. gatewayIP := consequent[0].NetAddr(mask) + netutils.IPV4Addr(options.Options.DefaultNetworkGatewayAddressEsxi)
  617. ret = append(ret, api.CASimpleNetConf{
  618. GuestIpStart: consequent[0].String(),
  619. GuestIpEnd: consequent[len(consequent)-1].String(),
  620. GuestIpMask: mask,
  621. GuestGateway: gatewayIP.String(),
  622. })
  623. consequent = []netutils.IPV4Addr{ip}
  624. }
  625. gatewayIp := consequent[0].NetAddr(mask) + netutils.IPV4Addr(options.Options.DefaultNetworkGatewayAddressEsxi)
  626. ret = append(ret, api.CASimpleNetConf{
  627. GuestIpStart: consequent[0].String(),
  628. GuestIpEnd: consequent[len(consequent)-1].String(),
  629. GuestIpMask: mask,
  630. GuestGateway: gatewayIp.String(),
  631. })
  632. return ret
  633. }