containers.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  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 compute
  15. import (
  16. "os"
  17. "strconv"
  18. "strings"
  19. "time"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/onecloud/pkg/apis"
  23. computeapi "yunion.io/x/onecloud/pkg/apis/compute"
  24. "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
  25. "yunion.io/x/onecloud/pkg/mcclient/options"
  26. )
  27. type ContainerListOptions struct {
  28. options.BaseListOptions
  29. GuestId string `json:"guest_id" help:"guest(pod) id or name"`
  30. HostId string `json:"host_id" help:"host id or name"`
  31. }
  32. func (o *ContainerListOptions) Params() (jsonutils.JSONObject, error) {
  33. return options.ListStructToParams(o)
  34. }
  35. type ContainerShowOptions struct {
  36. ServerIdOptions
  37. }
  38. type ContainerDeleteOptions struct {
  39. ServerIdsOptions
  40. }
  41. type ContainerCreateCommonOptions struct {
  42. IMAGE string `help:"Image of container" json:"image"`
  43. ImageCredentialId string `help:"Image credential id" json:"image_credential_id"`
  44. Command []string `help:"Command to execute (i.e., entrypoint for docker)" json:"command"`
  45. Args []string `help:"Args for the Command (i.e. command for docker)" json:"args"`
  46. WorkingDir string `help:"Current working directory of the command" json:"working_dir"`
  47. Env []string `help:"List of environment variable to set in the container and the format is: <key>=<value>"`
  48. RootFs string `help:"Root filesystem of the container, e.g.: disk_index=<disk_number>,disk_id=<disk_id>"`
  49. VolumeMount []string `help:"Volume mount of the container and the format is: name=<val>,mount_path=<container_path>,readonly=<true_or_false>,case_insensitive_paths=p1,p2,disk_index=<disk_number>,disk_id=<disk_id>"`
  50. Device []string `help:"Host device: <host_path>:<container_path>:<permissions>, e.g.: /dev/snd:/dev/snd:rwm"`
  51. Privileged bool `help:"Privileged mode"`
  52. Caps string `help:"Container capabilities, e.g.: SETPCAP,AUDIT_WRITE,SYS_CHROOT,CHOWN,DAC_OVERRIDE,FOWNER,SETGID,SETUID,SYSLOG,SYS_ADMIN,WAKE_ALARM,SYS_PTRACE,BLOCK_SUSPEND,MKNOD,KILL,SYS_RESOURCE,NET_RAW,NET_ADMIN,NET_BIND_SERVICE,SYS_NICE"`
  53. DropCaps string `help:"Container dropped capabilities, split by ','"`
  54. EnableLxcfs bool `help:"Enable lxcfs"`
  55. PostStartExec string `help:"Post started execution command"`
  56. CgroupDeviceAllow []string `help:"Cgroup devices.allow, e.g.: 'c 13:* rwm'"`
  57. SimulateCpu bool `help:"Simulating /sys/devices/system/cpu files"`
  58. ShmSizeMb int `help:"Shm size MB"`
  59. Uid int64 `help:"UID of container" default:"0"`
  60. Gid int64 `help:"GID of container" default:"0"`
  61. DisableNoNewPrivs bool `help:"Disable no_new_privs flag of the container"`
  62. Apparmor string `help:"Apparmor profile for container"`
  63. }
  64. func (o ContainerCreateCommonOptions) getCreateSpec() (*computeapi.ContainerSpec, error) {
  65. req := &computeapi.ContainerSpec{
  66. ContainerSpec: apis.ContainerSpec{
  67. Image: o.IMAGE,
  68. ImageCredentialId: o.ImageCredentialId,
  69. Command: o.Command,
  70. Args: o.Args,
  71. WorkingDir: o.WorkingDir,
  72. EnableLxcfs: o.EnableLxcfs,
  73. Privileged: o.Privileged,
  74. Capabilities: &apis.ContainerCapability{},
  75. CgroupDevicesAllow: o.CgroupDeviceAllow,
  76. SimulateCpu: o.SimulateCpu,
  77. DisableNoNewPrivs: o.DisableNoNewPrivs,
  78. SecurityContext: &apis.ContainerSecurityContext{
  79. RunAsUser: nil,
  80. RunAsGroup: nil,
  81. },
  82. },
  83. }
  84. if o.ShmSizeMb > 0 {
  85. req.ContainerSpec.ShmSizeMB = o.ShmSizeMb
  86. }
  87. if o.Uid > 0 {
  88. req.ContainerSpec.SecurityContext.RunAsUser = &o.Uid
  89. }
  90. if o.Gid > 0 {
  91. req.ContainerSpec.SecurityContext.RunAsGroup = &o.Gid
  92. }
  93. if o.Apparmor != "" {
  94. req.ContainerSpec.SecurityContext.ApparmorProfile = o.Apparmor
  95. }
  96. if len(o.PostStartExec) != 0 {
  97. req.Lifecyle = &apis.ContainerLifecyle{
  98. PostStart: &apis.ContainerLifecyleHandler{
  99. Type: apis.ContainerLifecyleHandlerTypeExec,
  100. Exec: &apis.ContainerLifecyleHandlerExecAction{
  101. Command: strings.Split(o.PostStartExec, " "),
  102. },
  103. },
  104. }
  105. }
  106. if len(o.Caps) != 0 {
  107. req.Capabilities.Add = strings.Split(o.Caps, ",")
  108. }
  109. if len(o.DropCaps) != 0 {
  110. req.Capabilities.Drop = strings.Split(o.DropCaps, ",")
  111. }
  112. for _, env := range o.Env {
  113. e, err := parseContainerEnv(env)
  114. if err != nil {
  115. return nil, errors.Wrapf(err, "parseContainerEnv %s", env)
  116. }
  117. req.Envs = append(req.Envs, e)
  118. }
  119. if len(o.RootFs) != 0 {
  120. rootFs, err := parseContainerRootFs(o.RootFs)
  121. if err != nil {
  122. return nil, errors.Wrapf(err, "parseContainerRootFs %s", o.RootFs)
  123. }
  124. req.RootFs = rootFs
  125. }
  126. for _, vmStr := range o.VolumeMount {
  127. vm, err := parseContainerVolumeMount(vmStr)
  128. if err != nil {
  129. return nil, errors.Wrapf(err, "parseContainerVolumeMount %s", vmStr)
  130. }
  131. req.VolumeMounts = append(req.VolumeMounts, vm)
  132. }
  133. devs := make([]*computeapi.ContainerDevice, len(o.Device))
  134. for idx, devStr := range o.Device {
  135. dev, err := parseContainerDevice(devStr)
  136. if err != nil {
  137. return nil, errors.Wrap(err, "parseContainerDevice")
  138. }
  139. devs[idx] = dev
  140. }
  141. req.Devices = devs
  142. return req, nil
  143. }
  144. type ContainerCreateOptions struct {
  145. ContainerCreateCommonOptions
  146. AutoStart bool `help:"Auto start container" json:"auto_start"`
  147. PODID string `help:"Name or id of server pod" json:"-"`
  148. NAME string `help:"Name of container" json:"-"`
  149. }
  150. func (o *ContainerCreateOptions) Params() (jsonutils.JSONObject, error) {
  151. spec, err := o.getCreateSpec()
  152. if err != nil {
  153. return nil, errors.Wrap(err, "get container create spec")
  154. }
  155. req := computeapi.ContainerCreateInput{
  156. GuestId: o.PODID,
  157. Spec: *spec,
  158. AutoStart: o.AutoStart,
  159. }
  160. req.Name = o.NAME
  161. return jsonutils.Marshal(req), nil
  162. }
  163. func parseContainerEnv(env string) (*apis.ContainerKeyValue, error) {
  164. kv := strings.Split(env, "=")
  165. if len(kv) != 2 {
  166. return nil, errors.Errorf("invalid env: %q", env)
  167. }
  168. return &apis.ContainerKeyValue{
  169. Key: kv[0],
  170. Value: kv[1],
  171. }, nil
  172. }
  173. func parseContainerRootFs(rootFs string) (*apis.ContainerRootfs, error) {
  174. out := &apis.ContainerRootfs{
  175. Type: apis.CONTAINER_VOLUME_MOUNT_TYPE_DISK,
  176. Disk: &apis.ContainerVolumeMountDisk{},
  177. }
  178. for _, seg := range strings.Split(rootFs, ",") {
  179. info := strings.Split(seg, "=")
  180. if len(info) != 2 {
  181. return nil, errors.Errorf("invalid option %s", seg)
  182. }
  183. key := info[0]
  184. val := info[1]
  185. switch key {
  186. case "disk_index":
  187. index, err := strconv.Atoi(val)
  188. if err != nil {
  189. return nil, errors.Wrapf(err, "wrong disk_index %s", val)
  190. }
  191. out.Disk.Index = &index
  192. case "disk_id":
  193. out.Disk.Id = val
  194. case "sub_dir", "sub_directory":
  195. out.Disk.SubDirectory = val
  196. }
  197. }
  198. return out, nil
  199. }
  200. func parseContainerVolumeMount(vmStr string) (*apis.ContainerVolumeMount, error) {
  201. vm := &apis.ContainerVolumeMount{}
  202. for _, seg := range strings.Split(vmStr, ",") {
  203. info := strings.Split(seg, "=")
  204. if len(info) != 2 {
  205. return nil, errors.Errorf("invalid option %s", seg)
  206. }
  207. key := info[0]
  208. val := info[1]
  209. switch key {
  210. case "read_only", "ro", "readonly":
  211. if strings.ToLower(val) == "true" {
  212. vm.ReadOnly = true
  213. }
  214. case "fs_user":
  215. uId, err := strconv.Atoi(val)
  216. if err != nil {
  217. return nil, errors.Wrapf(err, "invalid fs_user %s", val)
  218. }
  219. uId64 := int64(uId)
  220. vm.FsUser = &uId64
  221. case "fs_group":
  222. gId, err := strconv.Atoi(val)
  223. if err != nil {
  224. return nil, errors.Wrapf(err, "invalid fs_group %s", val)
  225. }
  226. gId64 := int64(gId)
  227. vm.FsGroup = &gId64
  228. case "mount_path", "mount":
  229. vm.MountPath = val
  230. case "host_path":
  231. if vm.HostPath == nil {
  232. vm.HostPath = &apis.ContainerVolumeMountHostPath{}
  233. }
  234. vm.Type = apis.CONTAINER_VOLUME_MOUNT_TYPE_HOST_PATH
  235. vm.HostPath.Path = val
  236. case "host_type":
  237. if vm.HostPath == nil {
  238. vm.HostPath = &apis.ContainerVolumeMountHostPath{}
  239. }
  240. vm.HostPath.Type = apis.ContainerVolumeMountHostPathType(val)
  241. case "disk_index":
  242. vm.Type = apis.CONTAINER_VOLUME_MOUNT_TYPE_DISK
  243. if vm.Disk == nil {
  244. vm.Disk = &apis.ContainerVolumeMountDisk{}
  245. }
  246. index, err := strconv.Atoi(val)
  247. if err != nil {
  248. return nil, errors.Wrapf(err, "wrong disk_index %s", val)
  249. }
  250. vm.Disk.Index = &index
  251. case "disk_id":
  252. vm.Type = apis.CONTAINER_VOLUME_MOUNT_TYPE_DISK
  253. if vm.Disk == nil {
  254. vm.Disk = &apis.ContainerVolumeMountDisk{}
  255. }
  256. vm.Disk.Id = val
  257. case "disk_subdir", "disk_sub_dir", "disk_sub_directory":
  258. vm.Type = apis.CONTAINER_VOLUME_MOUNT_TYPE_DISK
  259. if vm.Disk == nil {
  260. vm.Disk = &apis.ContainerVolumeMountDisk{}
  261. }
  262. vm.Disk.SubDirectory = val
  263. case "disk_storage_size_file", "disk_ssf":
  264. vm.Type = apis.CONTAINER_VOLUME_MOUNT_TYPE_DISK
  265. if vm.Disk == nil {
  266. vm.Disk = &apis.ContainerVolumeMountDisk{}
  267. }
  268. vm.Disk.StorageSizeFile = val
  269. case "case_insensitive_paths", "casefold_paths":
  270. vm.Disk.CaseInsensitivePaths = strings.Split(val, ",")
  271. case "overlay":
  272. if vm.Disk == nil {
  273. vm.Disk = &apis.ContainerVolumeMountDisk{}
  274. }
  275. vm.Disk.Overlay = &apis.ContainerVolumeMountDiskOverlay{
  276. LowerDir: strings.Split(val, ":"),
  277. }
  278. case "overlay_disk_image":
  279. if strings.ToLower(val) == "true" {
  280. if vm.Disk == nil {
  281. vm.Disk = &apis.ContainerVolumeMountDisk{}
  282. }
  283. vm.Disk.Overlay = &apis.ContainerVolumeMountDiskOverlay{
  284. UseDiskImage: true,
  285. }
  286. }
  287. case "text_file":
  288. content, err := os.ReadFile(val)
  289. if err != nil {
  290. return nil, errors.Wrapf(err, "read file %s", val)
  291. }
  292. vm.Type = apis.CONTAINER_VOLUME_MOUNT_TYPE_TEXT
  293. vm.Text = &apis.ContainerVolumeMountText{
  294. Content: string(content),
  295. }
  296. case "cephfs":
  297. vm.Type = apis.CONTAINER_VOLUME_MOUNT_TYPE_CEPHF_FS
  298. vm.CephFS = &apis.ContainerVolumeMountCephFS{
  299. Id: val,
  300. }
  301. }
  302. }
  303. return vm, nil
  304. }
  305. type ContainerIdsOptions struct {
  306. ID []string `help:"ID of containers to operate" metavar:"CONTAINER" json:"-"`
  307. }
  308. func (o *ContainerIdsOptions) GetIds() []string {
  309. return o.ID
  310. }
  311. func (o *ContainerIdsOptions) Params() (jsonutils.JSONObject, error) {
  312. return nil, nil
  313. }
  314. type ContainerStopOptions struct {
  315. ContainerIdsOptions
  316. Timeout int `help:"Stopping timeout" json:"timeout"`
  317. Force bool `help:"Force stop container" json:"force"`
  318. }
  319. func (o *ContainerStopOptions) Params() (jsonutils.JSONObject, error) {
  320. return jsonutils.Marshal(o), nil
  321. }
  322. type ContainerStartOptions struct {
  323. ContainerIdsOptions
  324. }
  325. type ContainerRestartOptions struct {
  326. ContainerIdsOptions
  327. Timeout int `help:"Stopping timeout" json:"timeout"`
  328. Force bool `help:"Force stop container" json:"force"`
  329. }
  330. func (o *ContainerRestartOptions) Params() (jsonutils.JSONObject, error) {
  331. return jsonutils.Marshal(o), nil
  332. }
  333. type ContainerSaveVolumeMountImage struct {
  334. options.ResourceIdOptions
  335. IMAGENAME string `help:"Image name"`
  336. INDEX int `help:"Index of volume mount"`
  337. GenerateName string `help:"Generate image name automatically"`
  338. Notes string `help:"Extra notes of the image"`
  339. UsedByPostOverlay bool `help:"Used by voluem mount post-overlay"`
  340. Dirs []string `help:"Internal directories"`
  341. }
  342. func (o ContainerSaveVolumeMountImage) Params() (jsonutils.JSONObject, error) {
  343. return jsonutils.Marshal(&computeapi.ContainerSaveVolumeMountToImageInput{
  344. Name: o.IMAGENAME,
  345. GenerateName: o.GenerateName,
  346. Notes: o.Notes,
  347. Index: o.INDEX,
  348. Dirs: o.Dirs,
  349. UsedByPostOverlay: o.UsedByPostOverlay,
  350. }), nil
  351. }
  352. type ContainerExecOptions struct {
  353. ServerIdOptions
  354. // Tty bool `help:"Using tty" short-token:"t"`
  355. COMMAND string
  356. Args []string
  357. }
  358. func (o *ContainerExecOptions) ToAPIInput() *compute.ContainerExecInput {
  359. cmd := []string{o.COMMAND}
  360. cmd = append(cmd, o.Args...)
  361. return &compute.ContainerExecInput{
  362. Command: cmd,
  363. Tty: true,
  364. Stdin: os.Stdin,
  365. Stdout: os.Stdout,
  366. Stderr: os.Stderr,
  367. }
  368. }
  369. func (o *ContainerExecOptions) Params() (jsonutils.JSONObject, error) {
  370. return jsonutils.Marshal(o.ToAPIInput()), nil
  371. }
  372. type ContainerSetResourcesLimitOptions struct {
  373. ContainerIdsOptions
  374. DisableLimitCheck bool `help:"disable limit check"`
  375. CpuCfsQuota float64 `help:"cpu cfs quota. e.g.:0.5 equals 0.5*100000"`
  376. //MemoryLimitMb int64 `help:"memory limit MB"`
  377. PidsMax int `help:"pids max"`
  378. DeviceAllow []string `help:"devices allow"`
  379. }
  380. func (o *ContainerSetResourcesLimitOptions) Params() (jsonutils.JSONObject, error) {
  381. limit := &computeapi.ContainerResourcesSetInput{}
  382. if o.CpuCfsQuota > 0 {
  383. limit.CpuCfsQuota = &o.CpuCfsQuota
  384. }
  385. //if o.MemoryLimitMb > 0 {
  386. // limit.MemoryLimitMB = &o.MemoryLimitMb
  387. //}
  388. if o.PidsMax > 0 {
  389. limit.PidsMax = &o.PidsMax
  390. }
  391. if len(o.DeviceAllow) > 0 {
  392. limit.DevicesAllow = o.DeviceAllow
  393. }
  394. limit.DisableLimitCheck = o.DisableLimitCheck
  395. return jsonutils.Marshal(limit), nil
  396. }
  397. type ContainerExecSyncOptions struct {
  398. ServerIdOptions
  399. COMMAND string
  400. Args []string
  401. Timeout int64
  402. }
  403. func (o *ContainerExecSyncOptions) Params() (jsonutils.JSONObject, error) {
  404. cmd := []string{o.COMMAND}
  405. cmd = append(cmd, o.Args...)
  406. return jsonutils.Marshal(&computeapi.ContainerExecSyncInput{
  407. Command: cmd,
  408. Timeout: o.Timeout,
  409. }), nil
  410. }
  411. type ContainerLogOptions struct {
  412. ServerIdOptions
  413. Since string `help:"Only return logs newer than a relative duration like 5s, 2m, or 3h" json:"since"`
  414. Follow bool `help:"Follow log output" short-token:"f" json:"follow"`
  415. Tail int64 `help:"Lines of recent log file to display" json:"tail"`
  416. Timestamps bool `help:"Show timestamps on each line in the log output" json:"timestamps"`
  417. LimitBytes int64 `help:"Maximum amount of bytes that can be used." json:"limitBytes"`
  418. }
  419. func (o *ContainerLogOptions) Params() (jsonutils.JSONObject, error) {
  420. input, err := o.ToAPIInput()
  421. if err != nil {
  422. return nil, err
  423. }
  424. return jsonutils.Marshal(input), nil
  425. }
  426. func (o *ContainerLogOptions) ToAPIInput() (*computeapi.PodLogOptions, error) {
  427. opt := &computeapi.PodLogOptions{
  428. Follow: o.Follow,
  429. Timestamps: o.Timestamps,
  430. }
  431. if o.LimitBytes > 0 {
  432. opt.LimitBytes = &o.LimitBytes
  433. }
  434. if o.Tail > 0 {
  435. opt.TailLines = &o.Tail
  436. }
  437. if len(o.Since) > 0 {
  438. dur, err := time.ParseDuration(o.Since)
  439. if err != nil {
  440. return nil, errors.Wrapf(err, "invalid time duration: %s, shoud like 300ms, 1.5h or 2h45m", o.Since)
  441. }
  442. sec := int64(dur.Round(time.Second).Seconds())
  443. opt.SinceSeconds = &sec
  444. }
  445. return opt, nil
  446. }
  447. type ContainerCommitOptions struct {
  448. ServerIdOptions
  449. RegistryId string `help:"Registry ID from kubeserver"`
  450. ImageName string `help:"Image name"`
  451. Tag string `help:"Tag"`
  452. ExternalRegistryUrl string `help:"External registry URL, e.g.: registry.cn-beijing.aliyuncs.com/yunionio"`
  453. ExternalRegistryUsername string `help:"External registry username"`
  454. ExternalRegistryPassword string `help:"External registry password"`
  455. }
  456. func (o *ContainerCommitOptions) Params() (jsonutils.JSONObject, error) {
  457. input := &computeapi.ContainerCommitInput{
  458. RegistryId: o.RegistryId,
  459. ImageName: o.ImageName,
  460. Tag: o.Tag,
  461. ExternalRegistry: &computeapi.ContainerCommitExternalRegistry{
  462. Auth: &apis.ContainerPullImageAuthConfig{},
  463. },
  464. }
  465. if o.ExternalRegistryUrl != "" {
  466. input.ExternalRegistry.Url = o.ExternalRegistryUrl
  467. }
  468. if o.ExternalRegistryUsername != "" {
  469. input.ExternalRegistry.Auth.Username = o.ExternalRegistryUsername
  470. }
  471. if o.ExternalRegistryPassword != "" {
  472. input.ExternalRegistry.Auth.Password = o.ExternalRegistryPassword
  473. }
  474. return jsonutils.Marshal(input), nil
  475. }
  476. type ContainerAddVolumeMountPostOverlayOptions struct {
  477. ServerIdOptions
  478. INDEX int `help:"INDEX of volume mount"`
  479. MountDesc []string `help:"Mount description, <host_lower_dir>:<container_target_dir>" short-token:"m"`
  480. Image []string `help:"Image name or id"`
  481. }
  482. func (o *ContainerAddVolumeMountPostOverlayOptions) Params() (jsonutils.JSONObject, error) {
  483. input := &computeapi.ContainerVolumeMountAddPostOverlayInput{
  484. Index: o.INDEX,
  485. PostOverlay: make([]*apis.ContainerVolumeMountDiskPostOverlay, 0),
  486. }
  487. for _, md := range o.MountDesc {
  488. segs := strings.Split(md, ":")
  489. if len(segs) != 2 {
  490. return nil, errors.Errorf("invalid mount description: %s", md)
  491. }
  492. lowerDir := segs[0]
  493. containerTargetDir := segs[1]
  494. input.PostOverlay = append(input.PostOverlay, &apis.ContainerVolumeMountDiskPostOverlay{
  495. HostLowerDir: []string{lowerDir},
  496. ContainerTargetDir: containerTargetDir,
  497. })
  498. }
  499. if len(o.Image) != 0 {
  500. for _, img := range o.Image {
  501. input.PostOverlay = append(input.PostOverlay, &apis.ContainerVolumeMountDiskPostOverlay{
  502. Image: &apis.ContainerVolumeMountDiskPostImageOverlay{
  503. Id: img,
  504. },
  505. })
  506. }
  507. }
  508. return jsonutils.Marshal(input), nil
  509. }
  510. type ContainerRemoveVolumeMountPostOverlayOptions struct {
  511. ContainerAddVolumeMountPostOverlayOptions
  512. ClearLayers bool `help:"clear overlay upper and work layers"`
  513. UseLazy bool `help:"use lazy umount"`
  514. }
  515. func (o *ContainerRemoveVolumeMountPostOverlayOptions) Params() (jsonutils.JSONObject, error) {
  516. params, err := o.ContainerAddVolumeMountPostOverlayOptions.Params()
  517. if err != nil {
  518. return nil, err
  519. }
  520. if o.ClearLayers {
  521. params.(*jsonutils.JSONDict).Add(jsonutils.JSONTrue, "clear_layers")
  522. }
  523. if o.UseLazy {
  524. params.(*jsonutils.JSONDict).Add(jsonutils.JSONTrue, "use_lazy")
  525. }
  526. return params, nil
  527. }
  528. type ContainerCopyOptions struct {
  529. SRC string `help:"Local path or file name, or cotnainer:path, e.g. /etc/hots or ctr-0:/etc/hosts"`
  530. DST string `help:"Local path or file name, or cotnainer:path, e.g. /etc/hots or ctr-0:/etc/hosts"`
  531. RawFile bool `help:"copy the file as raw data, if false, requires tar in executive path in container and host"`
  532. }
  533. type ContainerCopyFromOptions struct {
  534. CONTAINER_ID_PATH string `help:"container id and the file path in the container, separated by ':', e.g. ctr-0:/etc/hosts"`
  535. DST_PATH string `help:"Local destination path or file name"`
  536. RawFile bool `help:"copy the file as raw data, if false, requires tar in executive path in container and host"`
  537. }