runtime.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  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 guestman
  15. import (
  16. "context"
  17. "fmt"
  18. "io/ioutil"
  19. "path"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/errors"
  23. computeapi "yunion.io/x/onecloud/pkg/apis/compute"
  24. "yunion.io/x/onecloud/pkg/hostman/guestman/desc"
  25. deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
  26. "yunion.io/x/onecloud/pkg/hostman/options"
  27. "yunion.io/x/onecloud/pkg/hostman/storageman"
  28. "yunion.io/x/onecloud/pkg/mcclient"
  29. "yunion.io/x/onecloud/pkg/util/cgrouputils/cpuset"
  30. "yunion.io/x/onecloud/pkg/util/fileutils2"
  31. "yunion.io/x/onecloud/pkg/util/netutils2"
  32. "yunion.io/x/onecloud/pkg/util/procutils"
  33. )
  34. type GuestRuntimeInstance interface {
  35. GetHypervisor() string
  36. GetName() string
  37. GetInitialId() string
  38. GetId() string
  39. IsValid() bool
  40. HomeDir() string
  41. GetDesc() *desc.SGuestDesc
  42. SetDesc(guestDesc *desc.SGuestDesc)
  43. GetSourceDesc() *desc.SGuestDesc
  44. SetSourceDesc(guestDesc *desc.SGuestDesc)
  45. GetDescFilePath() string
  46. NicTrafficRecordPath() string
  47. DeployFs(ctx context.Context, userCred mcclient.TokenCredential, deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error)
  48. GetSourceDescFilePath() string
  49. IsRunning() bool
  50. IsStopped() bool
  51. IsSuspend() bool
  52. IsLoaded() bool
  53. GetNicDescMatch(mac, ip, port, bridge string) *desc.SGuestNetwork
  54. GetIpv6NicMacs(bridge string) []string
  55. CleanGuest(ctx context.Context, params interface{}) (jsonutils.JSONObject, error)
  56. CleanDirtyGuest(ctx context.Context) error
  57. ImportServer(pendingDelete bool)
  58. ExitCleanup(bool)
  59. HandleGuestStatus(ctx context.Context, resp *computeapi.HostUploadGuestStatusInput, isBatch bool) *computeapi.HostUploadGuestStatusInput
  60. GetUploadStatus(ctx context.Context, reason string) (*computeapi.HostUploadGuestStatusInput, error)
  61. PostUploadStatus(resp *computeapi.HostUploadGuestStatusInput, reason string)
  62. HandleGuestStart(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject) (jsonutils.JSONObject, error)
  63. HandleStop(ctx context.Context, timeout int64) error
  64. LoadDesc() error
  65. PostLoad(m *SGuestManager) error
  66. SyncConfig(ctx context.Context, guestDesc *desc.SGuestDesc, fwOnly, setUefiBootOrder bool) (jsonutils.JSONObject, error)
  67. DoSnapshot(ctx context.Context, params *SDiskSnapshot) (jsonutils.JSONObject, error)
  68. DeleteSnapshot(ctx context.Context, params *SDeleteDiskSnapshot) (jsonutils.JSONObject, error)
  69. OnlineResizeDisk(ctx context.Context, disk storageman.IDisk, sizeMB int64)
  70. GetDependsImageIds(storageType string) []string
  71. SetNicDown(mac string) error
  72. SetNicUp(nic *desc.SGuestNetwork) error
  73. }
  74. type sBaseGuestInstance struct {
  75. Id string
  76. manager *SGuestManager
  77. // runtime description, generate from source desc
  78. Desc *desc.SGuestDesc
  79. // source description, input from region
  80. SourceDesc *desc.SGuestDesc
  81. Hypervisor string
  82. }
  83. func newBaseGuestInstance(id string, manager *SGuestManager, hypervisor string) *sBaseGuestInstance {
  84. return &sBaseGuestInstance{
  85. Id: id,
  86. manager: manager,
  87. Hypervisor: hypervisor,
  88. }
  89. }
  90. func (s *sBaseGuestInstance) GetHypervisor() string {
  91. return s.Hypervisor
  92. }
  93. func (s *sBaseGuestInstance) IsValid() bool {
  94. return s.Desc != nil && s.Desc.Uuid != ""
  95. }
  96. func (s *sBaseGuestInstance) GetInitialId() string {
  97. return s.Id
  98. }
  99. func (s *sBaseGuestInstance) GetId() string {
  100. return s.Desc.Uuid
  101. }
  102. func (s *sBaseGuestInstance) GetName() string {
  103. return fmt.Sprintf("%s(%s)", s.Desc.Name, s.Desc.Uuid)
  104. }
  105. func (b *sBaseGuestInstance) HomeDir() string {
  106. return path.Join(b.manager.ServersPath, b.Id)
  107. }
  108. func (s *sBaseGuestInstance) GetDescFilePath() string {
  109. return path.Join(s.HomeDir(), "desc")
  110. }
  111. func (s *sBaseGuestInstance) GetDesc() *desc.SGuestDesc {
  112. return s.Desc
  113. }
  114. func (s *sBaseGuestInstance) SetDesc(guestDesc *desc.SGuestDesc) {
  115. s.Desc = guestDesc
  116. }
  117. func (s *sBaseGuestInstance) GetSourceDesc() *desc.SGuestDesc {
  118. return s.SourceDesc
  119. }
  120. func (s *sBaseGuestInstance) SetSourceDesc(guestDesc *desc.SGuestDesc) {
  121. s.SourceDesc = guestDesc
  122. }
  123. func (s *sBaseGuestInstance) GetSourceDescFilePath() string {
  124. return path.Join(s.HomeDir(), "source-desc")
  125. }
  126. func (s *sBaseGuestInstance) NicTrafficRecordPath() string {
  127. return path.Join(s.HomeDir(), "nic_traffic.json")
  128. }
  129. func (s *sBaseGuestInstance) IsLoaded() bool {
  130. return s.Desc != nil
  131. }
  132. func (s *sBaseGuestInstance) IsDaemon() bool {
  133. return s.Desc.IsDaemon
  134. }
  135. func (s *sBaseGuestInstance) GetNicDescMatch(mac, ip, port, bridge string) *desc.SGuestNetwork {
  136. nics := s.Desc.Nics
  137. for _, nic := range nics {
  138. if bridge == "" && nic.Bridge != "" && nic.Bridge == options.HostOptions.OvnIntegrationBridge {
  139. continue
  140. }
  141. if (len(mac) == 0 || netutils2.MacEqual(nic.Mac, mac)) &&
  142. (len(ip) == 0 || nic.Ip == ip) &&
  143. (len(port) == 0 || nic.Ifname == port) &&
  144. (len(bridge) == 0 || nic.Bridge == bridge) {
  145. return nic
  146. }
  147. }
  148. return nil
  149. }
  150. func (s *sBaseGuestInstance) GetIpv6NicMacs(bridge string) []string {
  151. macs := []string{}
  152. for _, nic := range s.Desc.Nics {
  153. if nic.Bridge == bridge && len(nic.Ip6) > 0 {
  154. macs = append(macs, nic.Mac)
  155. }
  156. }
  157. return macs
  158. }
  159. func LoadGuestCpuset(m *SGuestManager, s GuestRuntimeInstance) error {
  160. guestDesc := s.GetDesc()
  161. if s.IsRunning() {
  162. m.cpuSet.Lock.Lock()
  163. defer m.cpuSet.Lock.Unlock()
  164. m.cpuSet.GuestIds[s.GetId()] = struct{}{}
  165. for _, vcpuPin := range guestDesc.VcpuPin {
  166. pcpuSet, err := cpuset.Parse(vcpuPin.Pcpus)
  167. if err != nil {
  168. log.Errorf("failed parse %s pcpus: %s", s.GetName(), vcpuPin.Pcpus)
  169. continue
  170. }
  171. vcpuSet, err := cpuset.Parse(vcpuPin.Vcpus)
  172. if err != nil {
  173. log.Errorf("failed parse %s vcpus: %s", s.GetName(), vcpuPin.Vcpus)
  174. continue
  175. }
  176. m.cpuSet.LoadCpus(pcpuSet.ToSlice(), vcpuSet.Size())
  177. }
  178. for _, numaCpuset := range guestDesc.CpuNumaPin {
  179. pcpus := make([]int, 0)
  180. vcpus := make([]int, 0)
  181. for i := range numaCpuset.VcpuPin {
  182. pcpus = append(pcpus, numaCpuset.VcpuPin[i].Pcpu)
  183. if numaCpuset.VcpuPin[i].Vcpu >= 0 {
  184. vcpus = append(vcpus, numaCpuset.VcpuPin[i].Vcpu)
  185. }
  186. }
  187. m.cpuSet.LoadNumaCpus(numaCpuset.SizeMB, int(*numaCpuset.NodeId), pcpus, len(vcpus))
  188. }
  189. }
  190. return nil
  191. }
  192. func ReleaseCpuNumaPin(m *SGuestManager, cpuNumaPin []*desc.SCpuNumaPin) {
  193. if !m.hostagentNumaAllocate {
  194. return
  195. }
  196. for _, numaCpus := range cpuNumaPin {
  197. pcpus := make([]int, 0)
  198. vcpus := make([]int, 0)
  199. for i := range numaCpus.VcpuPin {
  200. pcpus = append(pcpus, numaCpus.VcpuPin[i].Pcpu)
  201. if numaCpus.VcpuPin[i].Vcpu >= 0 {
  202. vcpus = append(vcpus, numaCpus.VcpuPin[i].Vcpu)
  203. }
  204. }
  205. m.cpuSet.ReleaseNumaCpus(numaCpus.SizeMB, int(*numaCpus.NodeId), pcpus, len(vcpus))
  206. }
  207. }
  208. func ReleaseGuestCpuset(m *SGuestManager, s GuestRuntimeInstance) {
  209. m.cpuSet.Lock.Lock()
  210. defer m.cpuSet.Lock.Unlock()
  211. delete(m.cpuSet.GuestIds, s.GetId())
  212. guestDesc := s.GetDesc()
  213. ReleaseCpuNumaPin(m, guestDesc.CpuNumaPin)
  214. for _, vcpuPin := range guestDesc.VcpuPin {
  215. pcpuSet, err := cpuset.Parse(vcpuPin.Pcpus)
  216. if err != nil {
  217. log.Errorf("failed parse %s pcpus: %s", s.GetName(), vcpuPin.Pcpus)
  218. continue
  219. }
  220. vcpuSet, err := cpuset.Parse(vcpuPin.Vcpus)
  221. if err != nil {
  222. log.Errorf("failed parse %s vcpus: %s", s.GetName(), vcpuPin.Vcpus)
  223. continue
  224. }
  225. m.cpuSet.ReleaseCpus(pcpuSet.ToSlice(), vcpuSet.Size())
  226. }
  227. guestDesc.VcpuPin = nil
  228. guestDesc.CpuNumaPin = nil
  229. SaveLiveDesc(s, guestDesc)
  230. }
  231. type GuestRuntimeManager struct {
  232. }
  233. func NewGuestRuntimeManager() *GuestRuntimeManager {
  234. return new(GuestRuntimeManager)
  235. }
  236. func (f *GuestRuntimeManager) NewRuntimeInstance(id string, manager *SGuestManager, hypervisor string) GuestRuntimeInstance {
  237. switch hypervisor {
  238. case computeapi.HYPERVISOR_KVM, "":
  239. return NewKVMGuestInstance(id, manager)
  240. case computeapi.HYPERVISOR_POD:
  241. return newPodGuestInstance(id, manager)
  242. }
  243. log.Fatalf("Invalid hypervisor for runtime: %q", hypervisor)
  244. return nil
  245. }
  246. func PrepareDir(s GuestRuntimeInstance) error {
  247. output, err := procutils.NewCommand("mkdir", "-p", s.HomeDir()).Output()
  248. if err != nil {
  249. return errors.Wrapf(err, "mkdir %s failed: %s", s.HomeDir(), output)
  250. }
  251. return nil
  252. }
  253. func (f *GuestRuntimeManager) CreateFromDesc(s GuestRuntimeInstance, desc *desc.SGuestDesc) error {
  254. if err := PrepareDir(s); err != nil {
  255. return errors.Errorf("Failed to create server dir %s", desc.Uuid)
  256. }
  257. return SaveDesc(s, desc)
  258. }
  259. func (s *sBaseGuestInstance) GetVpcNIC() *desc.SGuestNetwork {
  260. for _, nic := range s.Desc.Nics {
  261. if nic.Vpc.Provider == computeapi.VPC_PROVIDER_OVN {
  262. if nic.Ip != "" {
  263. return nic
  264. }
  265. }
  266. }
  267. return nil
  268. }
  269. func (s *sBaseGuestInstance) UpdateLiveDesc(guestDesc *desc.SGuestDesc) {
  270. // update guest live desc, don't be here update cpu and mem
  271. // cpu and memory should update from SGuestHotplugCpuMemTask
  272. s.Desc.SGuestControlDesc = guestDesc.SGuestControlDesc
  273. s.Desc.SGuestProjectDesc = guestDesc.SGuestProjectDesc
  274. s.Desc.SGuestRegionDesc = guestDesc.SGuestRegionDesc
  275. s.Desc.SGuestMetaDesc = guestDesc.SGuestMetaDesc
  276. }
  277. func LoadDesc(s GuestRuntimeInstance) error {
  278. descPath := s.GetDescFilePath()
  279. descStr, err := ioutil.ReadFile(descPath)
  280. if err != nil {
  281. return errors.Wrap(err, "read desc")
  282. }
  283. var (
  284. srcDescStr []byte
  285. srcDescPath = s.GetSourceDescFilePath()
  286. )
  287. if !fileutils2.Exists(srcDescPath) {
  288. err = fileutils2.FilePutContents(srcDescPath, string(descStr), false)
  289. if err != nil {
  290. return errors.Wrap(err, "save source desc")
  291. }
  292. srcDescStr = descStr
  293. } else {
  294. srcDescStr, err = ioutil.ReadFile(srcDescPath)
  295. if err != nil {
  296. return errors.Wrap(err, "read source desc")
  297. }
  298. }
  299. // parse source desc
  300. srcGuestDesc := new(desc.SGuestDesc)
  301. jsonSrcDesc, err := jsonutils.Parse(srcDescStr)
  302. if err != nil {
  303. return errors.Wrap(err, "json parse source desc")
  304. }
  305. err = jsonSrcDesc.Unmarshal(srcGuestDesc)
  306. if err != nil {
  307. return errors.Wrap(err, "unmarshal source desc")
  308. }
  309. s.SetSourceDesc(srcGuestDesc)
  310. // parse desc
  311. guestDesc := new(desc.SGuestDesc)
  312. jsonDesc, err := jsonutils.Parse(descStr)
  313. if err != nil {
  314. return errors.Wrap(err, "json parse desc")
  315. }
  316. err = jsonDesc.Unmarshal(guestDesc)
  317. if err != nil {
  318. return errors.Wrap(err, "unmarshal desc")
  319. }
  320. s.SetDesc(guestDesc)
  321. return nil
  322. }
  323. func SaveDesc(s GuestRuntimeInstance, guestDesc *desc.SGuestDesc) error {
  324. s.SetSourceDesc(guestDesc)
  325. // fill in ovn vpc nic bridge field
  326. for _, nic := range s.GetSourceDesc().Nics {
  327. if nic.Bridge == "" {
  328. nic.Bridge = getNicBridge(nic)
  329. }
  330. }
  331. if err := fileutils2.FilePutContents(
  332. s.GetSourceDescFilePath(), jsonutils.Marshal(s.GetSourceDesc()).String(), false,
  333. ); err != nil {
  334. log.Errorf("save source desc failed %s", err)
  335. return errors.Wrap(err, "source save desc")
  336. }
  337. if !s.IsRunning() { // if guest not running, sync live desc
  338. liveDesc := new(desc.SGuestDesc)
  339. if err := jsonutils.Marshal(s.GetSourceDesc()).Unmarshal(liveDesc); err != nil {
  340. return errors.Wrap(err, "unmarshal live desc")
  341. }
  342. return SaveLiveDesc(s, liveDesc)
  343. }
  344. return nil
  345. }
  346. func SaveLiveDesc(s GuestRuntimeInstance, guestDesc *desc.SGuestDesc) error {
  347. s.SetDesc(guestDesc)
  348. defaultGwCnt := 0
  349. defNics := netutils2.SNicInfoList{}
  350. // fill in ovn vpc nic bridge field
  351. for _, nic := range s.GetDesc().Nics {
  352. if nic.Bridge == "" {
  353. nic.Bridge = getNicBridge(nic)
  354. }
  355. if nic.IsDefault {
  356. defaultGwCnt++
  357. }
  358. defNics = defNics.Add(nic.Mac, nic.Ip, nic.Gateway, nic.Ip6, nic.Gateway6, nic.IsDefault)
  359. }
  360. // there should 1 and only 1 default gateway
  361. if defaultGwCnt != 1 {
  362. // fix is_default
  363. _, defIndex := defNics.FindDefaultNicMac()
  364. for i := range s.GetDesc().Nics {
  365. if i == defIndex {
  366. s.GetDesc().Nics[i].IsDefault = true
  367. } else {
  368. s.GetDesc().Nics[i].IsDefault = false
  369. }
  370. }
  371. }
  372. if err := fileutils2.FilePutContents(
  373. s.GetDescFilePath(), jsonutils.Marshal(s.GetDesc()).String(), false,
  374. ); err != nil {
  375. log.Errorf("save desc failed %s", err)
  376. return errors.Wrap(err, "save desc")
  377. }
  378. return nil
  379. }
  380. func GetPowerStates(s GuestRuntimeInstance) string {
  381. if s.IsRunning() {
  382. return computeapi.VM_POWER_STATES_ON
  383. } else {
  384. return computeapi.VM_POWER_STATES_OFF
  385. }
  386. }
  387. func DeleteHomeDir(s GuestRuntimeInstance) error {
  388. output, err := procutils.NewCommand("rm", "-rf", s.HomeDir()).Output()
  389. if err != nil {
  390. return errors.Wrapf(err, "rm %s failed: %s", s.HomeDir(), output)
  391. }
  392. return nil
  393. }