system.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. package hcs
  2. import (
  3. "encoding/json"
  4. "os"
  5. "strconv"
  6. "sync"
  7. "syscall"
  8. "time"
  9. "github.com/Microsoft/hcsshim/internal/interop"
  10. "github.com/Microsoft/hcsshim/internal/logfields"
  11. "github.com/Microsoft/hcsshim/internal/schema1"
  12. "github.com/Microsoft/hcsshim/internal/timeout"
  13. "github.com/sirupsen/logrus"
  14. )
  15. // currentContainerStarts is used to limit the number of concurrent container
  16. // starts.
  17. var currentContainerStarts containerStarts
  18. type containerStarts struct {
  19. maxParallel int
  20. inProgress int
  21. sync.Mutex
  22. }
  23. func init() {
  24. mpsS := os.Getenv("HCSSHIM_MAX_PARALLEL_START")
  25. if len(mpsS) > 0 {
  26. mpsI, err := strconv.Atoi(mpsS)
  27. if err != nil || mpsI < 0 {
  28. return
  29. }
  30. currentContainerStarts.maxParallel = mpsI
  31. }
  32. }
  33. type System struct {
  34. handleLock sync.RWMutex
  35. handle hcsSystem
  36. id string
  37. callbackNumber uintptr
  38. logctx logrus.Fields
  39. }
  40. func newSystem(id string) *System {
  41. return &System{
  42. id: id,
  43. logctx: logrus.Fields{
  44. logfields.ContainerID: id,
  45. },
  46. }
  47. }
  48. func (computeSystem *System) logOperationBegin(operation string) {
  49. logOperationBegin(
  50. computeSystem.logctx,
  51. operation+" - Begin Operation")
  52. }
  53. func (computeSystem *System) logOperationEnd(operation string, err error) {
  54. var result string
  55. if err == nil {
  56. result = "Success"
  57. } else {
  58. result = "Error"
  59. }
  60. logOperationEnd(
  61. computeSystem.logctx,
  62. operation+" - End Operation - "+result,
  63. err)
  64. }
  65. // CreateComputeSystem creates a new compute system with the given configuration but does not start it.
  66. func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (_ *System, err error) {
  67. operation := "hcsshim::CreateComputeSystem"
  68. computeSystem := newSystem(id)
  69. computeSystem.logOperationBegin(operation)
  70. defer func() { computeSystem.logOperationEnd(operation, err) }()
  71. hcsDocumentB, err := json.Marshal(hcsDocumentInterface)
  72. if err != nil {
  73. return nil, err
  74. }
  75. hcsDocument := string(hcsDocumentB)
  76. logrus.WithFields(computeSystem.logctx).
  77. WithField(logfields.JSON, hcsDocument).
  78. Debug("HCS ComputeSystem Document")
  79. var (
  80. resultp *uint16
  81. identity syscall.Handle
  82. createError error
  83. )
  84. syscallWatcher(computeSystem.logctx, func() {
  85. createError = hcsCreateComputeSystem(id, hcsDocument, identity, &computeSystem.handle, &resultp)
  86. })
  87. if createError == nil || IsPending(createError) {
  88. if err = computeSystem.registerCallback(); err != nil {
  89. // Terminate the compute system if it still exists. We're okay to
  90. // ignore a failure here.
  91. computeSystem.Terminate()
  92. return nil, makeSystemError(computeSystem, operation, "", err, nil)
  93. }
  94. }
  95. events, err := processAsyncHcsResult(createError, resultp, computeSystem.callbackNumber, hcsNotificationSystemCreateCompleted, &timeout.SystemCreate)
  96. if err != nil {
  97. if err == ErrTimeout {
  98. // Terminate the compute system if it still exists. We're okay to
  99. // ignore a failure here.
  100. computeSystem.Terminate()
  101. }
  102. return nil, makeSystemError(computeSystem, operation, hcsDocument, err, events)
  103. }
  104. return computeSystem, nil
  105. }
  106. // OpenComputeSystem opens an existing compute system by ID.
  107. func OpenComputeSystem(id string) (_ *System, err error) {
  108. operation := "hcsshim::OpenComputeSystem"
  109. computeSystem := newSystem(id)
  110. computeSystem.logOperationBegin(operation)
  111. defer func() {
  112. if IsNotExist(err) {
  113. computeSystem.logOperationEnd(operation, nil)
  114. } else {
  115. computeSystem.logOperationEnd(operation, err)
  116. }
  117. }()
  118. var (
  119. handle hcsSystem
  120. resultp *uint16
  121. )
  122. err = hcsOpenComputeSystem(id, &handle, &resultp)
  123. events := processHcsResult(resultp)
  124. if err != nil {
  125. return nil, makeSystemError(computeSystem, operation, "", err, events)
  126. }
  127. computeSystem.handle = handle
  128. if err = computeSystem.registerCallback(); err != nil {
  129. return nil, makeSystemError(computeSystem, operation, "", err, nil)
  130. }
  131. return computeSystem, nil
  132. }
  133. // GetComputeSystems gets a list of the compute systems on the system that match the query
  134. func GetComputeSystems(q schema1.ComputeSystemQuery) (_ []schema1.ContainerProperties, err error) {
  135. operation := "hcsshim::GetComputeSystems"
  136. fields := logrus.Fields{}
  137. logOperationBegin(
  138. fields,
  139. operation+" - Begin Operation")
  140. defer func() {
  141. var result string
  142. if err == nil {
  143. result = "Success"
  144. } else {
  145. result = "Error"
  146. }
  147. logOperationEnd(
  148. fields,
  149. operation+" - End Operation - "+result,
  150. err)
  151. }()
  152. queryb, err := json.Marshal(q)
  153. if err != nil {
  154. return nil, err
  155. }
  156. query := string(queryb)
  157. logrus.WithFields(fields).
  158. WithField(logfields.JSON, query).
  159. Debug("HCS ComputeSystem Query")
  160. var (
  161. resultp *uint16
  162. computeSystemsp *uint16
  163. )
  164. syscallWatcher(fields, func() {
  165. err = hcsEnumerateComputeSystems(query, &computeSystemsp, &resultp)
  166. })
  167. events := processHcsResult(resultp)
  168. if err != nil {
  169. return nil, &HcsError{Op: operation, Err: err, Events: events}
  170. }
  171. if computeSystemsp == nil {
  172. return nil, ErrUnexpectedValue
  173. }
  174. computeSystemsRaw := interop.ConvertAndFreeCoTaskMemBytes(computeSystemsp)
  175. computeSystems := []schema1.ContainerProperties{}
  176. if err = json.Unmarshal(computeSystemsRaw, &computeSystems); err != nil {
  177. return nil, err
  178. }
  179. return computeSystems, nil
  180. }
  181. // Start synchronously starts the computeSystem.
  182. func (computeSystem *System) Start() (err error) {
  183. computeSystem.handleLock.RLock()
  184. defer computeSystem.handleLock.RUnlock()
  185. operation := "hcsshim::ComputeSystem::Start"
  186. computeSystem.logOperationBegin(operation)
  187. defer func() { computeSystem.logOperationEnd(operation, err) }()
  188. if computeSystem.handle == 0 {
  189. return makeSystemError(computeSystem, "Start", "", ErrAlreadyClosed, nil)
  190. }
  191. // This is a very simple backoff-retry loop to limit the number
  192. // of parallel container starts if environment variable
  193. // HCSSHIM_MAX_PARALLEL_START is set to a positive integer.
  194. // It should generally only be used as a workaround to various
  195. // platform issues that exist between RS1 and RS4 as of Aug 2018
  196. if currentContainerStarts.maxParallel > 0 {
  197. for {
  198. currentContainerStarts.Lock()
  199. if currentContainerStarts.inProgress < currentContainerStarts.maxParallel {
  200. currentContainerStarts.inProgress++
  201. currentContainerStarts.Unlock()
  202. break
  203. }
  204. if currentContainerStarts.inProgress == currentContainerStarts.maxParallel {
  205. currentContainerStarts.Unlock()
  206. time.Sleep(100 * time.Millisecond)
  207. }
  208. }
  209. // Make sure we decrement the count when we are done.
  210. defer func() {
  211. currentContainerStarts.Lock()
  212. currentContainerStarts.inProgress--
  213. currentContainerStarts.Unlock()
  214. }()
  215. }
  216. var resultp *uint16
  217. syscallWatcher(computeSystem.logctx, func() {
  218. err = hcsStartComputeSystem(computeSystem.handle, "", &resultp)
  219. })
  220. events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemStartCompleted, &timeout.SystemStart)
  221. if err != nil {
  222. return makeSystemError(computeSystem, "Start", "", err, events)
  223. }
  224. return nil
  225. }
  226. // ID returns the compute system's identifier.
  227. func (computeSystem *System) ID() string {
  228. return computeSystem.id
  229. }
  230. // Shutdown requests a compute system shutdown, if IsPending() on the error returned is true,
  231. // it may not actually be shut down until Wait() succeeds.
  232. func (computeSystem *System) Shutdown() (err error) {
  233. computeSystem.handleLock.RLock()
  234. defer computeSystem.handleLock.RUnlock()
  235. operation := "hcsshim::ComputeSystem::Shutdown"
  236. computeSystem.logOperationBegin(operation)
  237. defer func() {
  238. if IsAlreadyStopped(err) {
  239. computeSystem.logOperationEnd(operation, nil)
  240. } else {
  241. computeSystem.logOperationEnd(operation, err)
  242. }
  243. }()
  244. if computeSystem.handle == 0 {
  245. return makeSystemError(computeSystem, "Shutdown", "", ErrAlreadyClosed, nil)
  246. }
  247. var resultp *uint16
  248. syscallWatcher(computeSystem.logctx, func() {
  249. err = hcsShutdownComputeSystem(computeSystem.handle, "", &resultp)
  250. })
  251. events := processHcsResult(resultp)
  252. if err != nil {
  253. return makeSystemError(computeSystem, "Shutdown", "", err, events)
  254. }
  255. return nil
  256. }
  257. // Terminate requests a compute system terminate, if IsPending() on the error returned is true,
  258. // it may not actually be shut down until Wait() succeeds.
  259. func (computeSystem *System) Terminate() (err error) {
  260. computeSystem.handleLock.RLock()
  261. defer computeSystem.handleLock.RUnlock()
  262. operation := "hcsshim::ComputeSystem::Terminate"
  263. computeSystem.logOperationBegin(operation)
  264. defer func() {
  265. if IsPending(err) {
  266. computeSystem.logOperationEnd(operation, nil)
  267. } else {
  268. computeSystem.logOperationEnd(operation, err)
  269. }
  270. }()
  271. if computeSystem.handle == 0 {
  272. return makeSystemError(computeSystem, "Terminate", "", ErrAlreadyClosed, nil)
  273. }
  274. var resultp *uint16
  275. syscallWatcher(computeSystem.logctx, func() {
  276. err = hcsTerminateComputeSystem(computeSystem.handle, "", &resultp)
  277. })
  278. events := processHcsResult(resultp)
  279. if err != nil && err != ErrVmcomputeAlreadyStopped {
  280. return makeSystemError(computeSystem, "Terminate", "", err, events)
  281. }
  282. return nil
  283. }
  284. // Wait synchronously waits for the compute system to shutdown or terminate.
  285. func (computeSystem *System) Wait() (err error) {
  286. operation := "hcsshim::ComputeSystem::Wait"
  287. computeSystem.logOperationBegin(operation)
  288. defer func() { computeSystem.logOperationEnd(operation, err) }()
  289. err = waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, nil)
  290. if err != nil {
  291. return makeSystemError(computeSystem, "Wait", "", err, nil)
  292. }
  293. return nil
  294. }
  295. // WaitExpectedError synchronously waits for the compute system to shutdown or
  296. // terminate, and ignores the passed error if it occurs.
  297. func (computeSystem *System) WaitExpectedError(expected error) (err error) {
  298. operation := "hcsshim::ComputeSystem::WaitExpectedError"
  299. computeSystem.logOperationBegin(operation)
  300. defer func() { computeSystem.logOperationEnd(operation, err) }()
  301. err = waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, nil)
  302. if err != nil && getInnerError(err) != expected {
  303. return makeSystemError(computeSystem, "WaitExpectedError", "", err, nil)
  304. }
  305. return nil
  306. }
  307. // WaitTimeout synchronously waits for the compute system to terminate or the duration to elapse.
  308. // If the timeout expires, IsTimeout(err) == true
  309. func (computeSystem *System) WaitTimeout(timeout time.Duration) (err error) {
  310. operation := "hcsshim::ComputeSystem::WaitTimeout"
  311. computeSystem.logOperationBegin(operation)
  312. defer func() { computeSystem.logOperationEnd(operation, err) }()
  313. err = waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, &timeout)
  314. if err != nil {
  315. return makeSystemError(computeSystem, "WaitTimeout", "", err, nil)
  316. }
  317. return nil
  318. }
  319. func (computeSystem *System) Properties(types ...schema1.PropertyType) (_ *schema1.ContainerProperties, err error) {
  320. computeSystem.handleLock.RLock()
  321. defer computeSystem.handleLock.RUnlock()
  322. operation := "hcsshim::ComputeSystem::Properties"
  323. computeSystem.logOperationBegin(operation)
  324. defer func() { computeSystem.logOperationEnd(operation, err) }()
  325. queryj, err := json.Marshal(schema1.PropertyQuery{types})
  326. if err != nil {
  327. return nil, makeSystemError(computeSystem, "Properties", "", err, nil)
  328. }
  329. logrus.WithFields(computeSystem.logctx).
  330. WithField(logfields.JSON, queryj).
  331. Debug("HCS ComputeSystem Properties Query")
  332. var resultp, propertiesp *uint16
  333. syscallWatcher(computeSystem.logctx, func() {
  334. err = hcsGetComputeSystemProperties(computeSystem.handle, string(queryj), &propertiesp, &resultp)
  335. })
  336. events := processHcsResult(resultp)
  337. if err != nil {
  338. return nil, makeSystemError(computeSystem, "Properties", "", err, events)
  339. }
  340. if propertiesp == nil {
  341. return nil, ErrUnexpectedValue
  342. }
  343. propertiesRaw := interop.ConvertAndFreeCoTaskMemBytes(propertiesp)
  344. properties := &schema1.ContainerProperties{}
  345. if err := json.Unmarshal(propertiesRaw, properties); err != nil {
  346. return nil, makeSystemError(computeSystem, "Properties", "", err, nil)
  347. }
  348. return properties, nil
  349. }
  350. // Pause pauses the execution of the computeSystem. This feature is not enabled in TP5.
  351. func (computeSystem *System) Pause() (err error) {
  352. computeSystem.handleLock.RLock()
  353. defer computeSystem.handleLock.RUnlock()
  354. operation := "hcsshim::ComputeSystem::Pause"
  355. computeSystem.logOperationBegin(operation)
  356. defer func() { computeSystem.logOperationEnd(operation, err) }()
  357. if computeSystem.handle == 0 {
  358. return makeSystemError(computeSystem, "Pause", "", ErrAlreadyClosed, nil)
  359. }
  360. var resultp *uint16
  361. syscallWatcher(computeSystem.logctx, func() {
  362. err = hcsPauseComputeSystem(computeSystem.handle, "", &resultp)
  363. })
  364. events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemPauseCompleted, &timeout.SystemPause)
  365. if err != nil {
  366. return makeSystemError(computeSystem, "Pause", "", err, events)
  367. }
  368. return nil
  369. }
  370. // Resume resumes the execution of the computeSystem. This feature is not enabled in TP5.
  371. func (computeSystem *System) Resume() (err error) {
  372. computeSystem.handleLock.RLock()
  373. defer computeSystem.handleLock.RUnlock()
  374. operation := "hcsshim::ComputeSystem::Resume"
  375. computeSystem.logOperationBegin(operation)
  376. defer func() { computeSystem.logOperationEnd(operation, err) }()
  377. if computeSystem.handle == 0 {
  378. return makeSystemError(computeSystem, "Resume", "", ErrAlreadyClosed, nil)
  379. }
  380. var resultp *uint16
  381. syscallWatcher(computeSystem.logctx, func() {
  382. err = hcsResumeComputeSystem(computeSystem.handle, "", &resultp)
  383. })
  384. events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemResumeCompleted, &timeout.SystemResume)
  385. if err != nil {
  386. return makeSystemError(computeSystem, "Resume", "", err, events)
  387. }
  388. return nil
  389. }
  390. // CreateProcess launches a new process within the computeSystem.
  391. func (computeSystem *System) CreateProcess(c interface{}) (_ *Process, err error) {
  392. computeSystem.handleLock.RLock()
  393. defer computeSystem.handleLock.RUnlock()
  394. operation := "hcsshim::ComputeSystem::CreateProcess"
  395. computeSystem.logOperationBegin(operation)
  396. defer func() { computeSystem.logOperationEnd(operation, err) }()
  397. var (
  398. processInfo hcsProcessInformation
  399. processHandle hcsProcess
  400. resultp *uint16
  401. )
  402. if computeSystem.handle == 0 {
  403. return nil, makeSystemError(computeSystem, "CreateProcess", "", ErrAlreadyClosed, nil)
  404. }
  405. configurationb, err := json.Marshal(c)
  406. if err != nil {
  407. return nil, makeSystemError(computeSystem, "CreateProcess", "", err, nil)
  408. }
  409. configuration := string(configurationb)
  410. logrus.WithFields(computeSystem.logctx).
  411. WithField(logfields.JSON, configuration).
  412. Debug("HCS ComputeSystem Process Document")
  413. syscallWatcher(computeSystem.logctx, func() {
  414. err = hcsCreateProcess(computeSystem.handle, configuration, &processInfo, &processHandle, &resultp)
  415. })
  416. events := processHcsResult(resultp)
  417. if err != nil {
  418. return nil, makeSystemError(computeSystem, "CreateProcess", configuration, err, events)
  419. }
  420. logrus.WithFields(computeSystem.logctx).
  421. WithField(logfields.ProcessID, processInfo.ProcessId).
  422. Debug("HCS ComputeSystem CreateProcess PID")
  423. process := newProcess(processHandle, int(processInfo.ProcessId), computeSystem)
  424. process.cachedPipes = &cachedPipes{
  425. stdIn: processInfo.StdInput,
  426. stdOut: processInfo.StdOutput,
  427. stdErr: processInfo.StdError,
  428. }
  429. if err = process.registerCallback(); err != nil {
  430. return nil, makeSystemError(computeSystem, "CreateProcess", "", err, nil)
  431. }
  432. return process, nil
  433. }
  434. // OpenProcess gets an interface to an existing process within the computeSystem.
  435. func (computeSystem *System) OpenProcess(pid int) (_ *Process, err error) {
  436. computeSystem.handleLock.RLock()
  437. defer computeSystem.handleLock.RUnlock()
  438. // Add PID for the context of this operation
  439. computeSystem.logctx[logfields.ProcessID] = pid
  440. defer delete(computeSystem.logctx, logfields.ProcessID)
  441. operation := "hcsshim::ComputeSystem::OpenProcess"
  442. computeSystem.logOperationBegin(operation)
  443. defer func() { computeSystem.logOperationEnd(operation, err) }()
  444. var (
  445. processHandle hcsProcess
  446. resultp *uint16
  447. )
  448. if computeSystem.handle == 0 {
  449. return nil, makeSystemError(computeSystem, "OpenProcess", "", ErrAlreadyClosed, nil)
  450. }
  451. syscallWatcher(computeSystem.logctx, func() {
  452. err = hcsOpenProcess(computeSystem.handle, uint32(pid), &processHandle, &resultp)
  453. })
  454. events := processHcsResult(resultp)
  455. if err != nil {
  456. return nil, makeSystemError(computeSystem, "OpenProcess", "", err, events)
  457. }
  458. process := newProcess(processHandle, pid, computeSystem)
  459. if err = process.registerCallback(); err != nil {
  460. return nil, makeSystemError(computeSystem, "OpenProcess", "", err, nil)
  461. }
  462. return process, nil
  463. }
  464. // Close cleans up any state associated with the compute system but does not terminate or wait for it.
  465. func (computeSystem *System) Close() (err error) {
  466. computeSystem.handleLock.Lock()
  467. defer computeSystem.handleLock.Unlock()
  468. operation := "hcsshim::ComputeSystem::Close"
  469. computeSystem.logOperationBegin(operation)
  470. defer func() { computeSystem.logOperationEnd(operation, err) }()
  471. // Don't double free this
  472. if computeSystem.handle == 0 {
  473. return nil
  474. }
  475. if err = computeSystem.unregisterCallback(); err != nil {
  476. return makeSystemError(computeSystem, "Close", "", err, nil)
  477. }
  478. syscallWatcher(computeSystem.logctx, func() {
  479. err = hcsCloseComputeSystem(computeSystem.handle)
  480. })
  481. if err != nil {
  482. return makeSystemError(computeSystem, "Close", "", err, nil)
  483. }
  484. computeSystem.handle = 0
  485. return nil
  486. }
  487. func (computeSystem *System) registerCallback() error {
  488. context := &notifcationWatcherContext{
  489. channels: newChannels(),
  490. }
  491. callbackMapLock.Lock()
  492. callbackNumber := nextCallback
  493. nextCallback++
  494. callbackMap[callbackNumber] = context
  495. callbackMapLock.Unlock()
  496. var callbackHandle hcsCallback
  497. err := hcsRegisterComputeSystemCallback(computeSystem.handle, notificationWatcherCallback, callbackNumber, &callbackHandle)
  498. if err != nil {
  499. return err
  500. }
  501. context.handle = callbackHandle
  502. computeSystem.callbackNumber = callbackNumber
  503. return nil
  504. }
  505. func (computeSystem *System) unregisterCallback() error {
  506. callbackNumber := computeSystem.callbackNumber
  507. callbackMapLock.RLock()
  508. context := callbackMap[callbackNumber]
  509. callbackMapLock.RUnlock()
  510. if context == nil {
  511. return nil
  512. }
  513. handle := context.handle
  514. if handle == 0 {
  515. return nil
  516. }
  517. // hcsUnregisterComputeSystemCallback has its own syncronization
  518. // to wait for all callbacks to complete. We must NOT hold the callbackMapLock.
  519. err := hcsUnregisterComputeSystemCallback(handle)
  520. if err != nil {
  521. return err
  522. }
  523. closeChannels(context.channels)
  524. callbackMapLock.Lock()
  525. callbackMap[callbackNumber] = nil
  526. callbackMapLock.Unlock()
  527. handle = 0
  528. return nil
  529. }
  530. // Modify the System by sending a request to HCS
  531. func (computeSystem *System) Modify(config interface{}) (err error) {
  532. computeSystem.handleLock.RLock()
  533. defer computeSystem.handleLock.RUnlock()
  534. operation := "hcsshim::ComputeSystem::Modify"
  535. computeSystem.logOperationBegin(operation)
  536. defer func() { computeSystem.logOperationEnd(operation, err) }()
  537. if computeSystem.handle == 0 {
  538. return makeSystemError(computeSystem, "Modify", "", ErrAlreadyClosed, nil)
  539. }
  540. requestJSON, err := json.Marshal(config)
  541. if err != nil {
  542. return err
  543. }
  544. requestString := string(requestJSON)
  545. logrus.WithFields(computeSystem.logctx).
  546. WithField(logfields.JSON, requestString).
  547. Debug("HCS ComputeSystem Modify Document")
  548. var resultp *uint16
  549. syscallWatcher(computeSystem.logctx, func() {
  550. err = hcsModifyComputeSystem(computeSystem.handle, requestString, &resultp)
  551. })
  552. events := processHcsResult(resultp)
  553. if err != nil {
  554. return makeSystemError(computeSystem, "Modify", requestString, err, events)
  555. }
  556. return nil
  557. }