server_pod.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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. "fmt"
  17. "strconv"
  18. "strings"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/util/fileutils"
  22. "yunion.io/x/pkg/util/regutils"
  23. "yunion.io/x/onecloud/pkg/apis"
  24. computeapi "yunion.io/x/onecloud/pkg/apis/compute"
  25. "yunion.io/x/onecloud/pkg/mcclient/options"
  26. )
  27. type PodCreateOptions struct {
  28. NAME string `help:"Name of server pod" json:"-"`
  29. ServerCreateCommonConfig `"disk->nargs":"*"`
  30. MEM string `help:"Memory size MB" metavar:"MEM" json:"-"`
  31. VcpuCount int `help:"#CPU cores of VM server, default 1" default:"1" metavar:"<SERVER_CPU_COUNT>" json:"vcpu_count" token:"ncpu"`
  32. AllowDelete *bool `help:"Unlock server to allow deleting" json:"-"`
  33. //PortMapping []string `help:"Port mapping of the pod and the format is: host_port=8080,port=80,protocol=<tcp|udp>,host_port_range=<int>-<int>" short-token:"p"`
  34. Arch string `help:"image arch" choices:"aarch64|x86_64"`
  35. AutoStart bool `help:"Auto start server after it is created"`
  36. ShutdownBehavior string `help:"Behavior after VM server shutdown" metavar:"<SHUTDOWN_BEHAVIOR>" choices:"stop|terminate|stop_release_gpu"`
  37. PodUid int64 `help:"UID of pod" default:"0"`
  38. PodGid int64 `help:"GID of pod" default:"0"`
  39. ContainerCreateCommonOptions
  40. }
  41. func parsePodPortMappingDetails(input string) (*computeapi.PodPortMapping, error) {
  42. pm := &computeapi.PodPortMapping{
  43. Protocol: computeapi.PodPortMappingProtocolTCP,
  44. }
  45. for _, seg := range strings.Split(input, ",") {
  46. info := strings.Split(seg, "=")
  47. if len(info) != 2 {
  48. return nil, errors.Errorf("invalid option %s", seg)
  49. }
  50. key := info[0]
  51. val := info[1]
  52. switch key {
  53. case "host_port":
  54. hp, err := strconv.Atoi(val)
  55. if err != nil {
  56. return nil, errors.Wrapf(err, "invalid host_port %s", val)
  57. }
  58. pm.HostPort = &hp
  59. case "container_port", "port":
  60. cp, err := strconv.Atoi(val)
  61. if err != nil {
  62. return nil, errors.Wrapf(err, "invalid container_port %s", val)
  63. }
  64. pm.ContainerPort = cp
  65. case "proto", "protocol":
  66. pm.Protocol = computeapi.PodPortMappingProtocol(val)
  67. case "host_port_range":
  68. rangeParts := strings.Split(val, "-")
  69. if len(rangeParts) != 2 {
  70. return nil, errors.Errorf("invalid range string %s", val)
  71. }
  72. start, err := strconv.Atoi(rangeParts[0])
  73. if err != nil {
  74. return nil, errors.Wrapf(err, "invalid host_port_range %s", rangeParts[0])
  75. }
  76. end, err := strconv.Atoi(rangeParts[1])
  77. if err != nil {
  78. return nil, errors.Wrapf(err, "invalid host_port_range %s", rangeParts[1])
  79. }
  80. pm.HostPortRange = &computeapi.PodPortMappingPortRange{
  81. Start: start,
  82. End: end,
  83. }
  84. }
  85. }
  86. if pm.ContainerPort == 0 {
  87. return nil, errors.Error("container_port must specified")
  88. }
  89. return pm, nil
  90. }
  91. func ParsePodPortMapping(input string) (*computeapi.PodPortMapping, error) {
  92. pm, err := parsePodPortMapping(input)
  93. if err != nil {
  94. return parsePodPortMappingDetails(input)
  95. }
  96. return pm, nil
  97. }
  98. func parsePodPortMapping(input string) (*computeapi.PodPortMapping, error) {
  99. segs := strings.Split(input, ":")
  100. parseCtrPart := func(ctrPortPart string) (computeapi.PodPortMappingProtocol, int, error) {
  101. ctrPortSegs := strings.Split(ctrPortPart, "/")
  102. if len(ctrPortSegs) > 2 {
  103. return "", 0, errors.Errorf("wrong format: %s", ctrPortPart)
  104. }
  105. ctrPortStr := ctrPortSegs[0]
  106. ctrPort, err := strconv.Atoi(ctrPortStr)
  107. if err != nil {
  108. return "", 0, errors.Wrapf(err, "container_port %s isn't integer", ctrPortStr)
  109. }
  110. var protocol computeapi.PodPortMappingProtocol = computeapi.PodPortMappingProtocolTCP
  111. if len(ctrPortSegs) == 2 {
  112. switch ctrPortSegs[1] {
  113. case "tcp":
  114. protocol = computeapi.PodPortMappingProtocolTCP
  115. case "udp":
  116. protocol = computeapi.PodPortMappingProtocolUDP
  117. //case "sctp":
  118. // protocol = computeapi.PodPortMappingProtocolSCTP
  119. default:
  120. return "", 0, errors.Wrapf(err, "wrong protocol: %s", ctrPortSegs[1])
  121. }
  122. }
  123. return protocol, ctrPort, nil
  124. }
  125. if len(segs) == 1 {
  126. protocol, ctrPort, err := parseCtrPart(segs[0])
  127. if err != nil {
  128. return nil, errors.Wrapf(err, "parse %s", segs[0])
  129. }
  130. return &computeapi.PodPortMapping{
  131. Protocol: protocol,
  132. ContainerPort: ctrPort,
  133. }, nil
  134. } else if len(segs) == 2 {
  135. hostPortStr := segs[0]
  136. hostPort, err := strconv.Atoi(hostPortStr)
  137. if err != nil {
  138. return nil, errors.Wrapf(err, "host_port %s isn't integer", hostPortStr)
  139. }
  140. ctrPortPart := segs[1]
  141. protocol, ctrPort, err := parseCtrPart(ctrPortPart)
  142. if err != nil {
  143. return nil, errors.Wrapf(err, "parse %s", ctrPortPart)
  144. }
  145. return &computeapi.PodPortMapping{
  146. Protocol: protocol,
  147. ContainerPort: ctrPort,
  148. HostPort: &hostPort,
  149. }, nil
  150. } else {
  151. return nil, errors.Errorf("wrong format: %s", input)
  152. }
  153. }
  154. func parseContainerDevice(dev string) (*computeapi.ContainerDevice, error) {
  155. segs := strings.Split(dev, ":")
  156. if len(segs) != 3 {
  157. return nil, errors.Errorf("wrong format: %s", dev)
  158. }
  159. return &computeapi.ContainerDevice{
  160. Type: apis.CONTAINER_DEVICE_TYPE_HOST,
  161. Host: &computeapi.ContainerHostDevice{
  162. ContainerPath: segs[1],
  163. HostPath: segs[0],
  164. Permissions: segs[2],
  165. },
  166. }, nil
  167. }
  168. func (o *PodCreateOptions) Params() (*computeapi.ServerCreateInput, error) {
  169. config, err := o.ServerCreateCommonConfig.Data()
  170. if err != nil {
  171. return nil, errors.Wrapf(err, "get ServerCreateCommonConfig.Data")
  172. }
  173. config.Hypervisor = computeapi.HYPERVISOR_POD
  174. /*portMappings := make([]*computeapi.PodPortMapping, 0)
  175. if len(o.PortMapping) != 0 {
  176. for _, input := range o.PortMapping {
  177. pm, err := ParsePodPortMapping(input)
  178. if err != nil {
  179. return nil, errors.Wrapf(err, "parse port mapping: %s", input)
  180. }
  181. portMappings = append(portMappings, pm)
  182. }
  183. }*/
  184. spec, err := o.getCreateSpec()
  185. if err != nil {
  186. return nil, errors.Wrap(err, "get container create spec")
  187. }
  188. params := &computeapi.ServerCreateInput{
  189. ServerConfigs: config,
  190. VcpuCount: o.VcpuCount,
  191. AutoStart: o.AutoStart,
  192. ShutdownBehavior: o.ShutdownBehavior,
  193. Pod: &computeapi.PodCreateInput{
  194. //PortMappings: portMappings,
  195. Containers: []*computeapi.PodContainerCreateInput{
  196. {
  197. ContainerSpec: *spec,
  198. },
  199. },
  200. SecurityContext: &computeapi.PodSecurityContext{},
  201. },
  202. }
  203. if o.Uid != 0 {
  204. params.Pod.SecurityContext.RunAsUser = &o.Uid
  205. }
  206. if o.Gid != 0 {
  207. params.Pod.SecurityContext.RunAsGroup = &o.Gid
  208. }
  209. if options.BoolV(o.AllowDelete) {
  210. disableDelete := false
  211. params.DisableDelete = &disableDelete
  212. }
  213. if regutils.MatchSize(o.MEM) {
  214. memSize, err := fileutils.GetSizeMb(o.MEM, 'M', 1024)
  215. if err != nil {
  216. return nil, err
  217. }
  218. params.VmemSize = memSize
  219. } else {
  220. return nil, fmt.Errorf("Invalid memory input: %q", o.MEM)
  221. }
  222. for idx := range o.IsolatedDevice {
  223. tmpIdx := idx
  224. params.Pod.Containers[0].Devices = append(
  225. params.Pod.Containers[0].Devices,
  226. &computeapi.ContainerDevice{
  227. Type: apis.CONTAINER_DEVICE_TYPE_ISOLATED_DEVICE,
  228. IsolatedDevice: &computeapi.ContainerIsolatedDevice{Index: &tmpIdx},
  229. })
  230. }
  231. params.OsArch = o.Arch
  232. params.Name = o.NAME
  233. return params, nil
  234. }
  235. type PodExecOptions struct {
  236. ContainerExecOptions
  237. Scope string `help:"Scope of containers query" choices:"system|domain|project"`
  238. Container string `help:"Container name. If omitted, use the first container." short-token:"c"`
  239. }
  240. type PodLogOptions struct {
  241. ContainerLogOptions
  242. Scope string `help:"Scope of containers query" choices:"system|domain|project"`
  243. Container string `help:"Container name. If omitted, use the first container." short-token:"c"`
  244. }
  245. type PodSetPortMappingOptions struct {
  246. ServerIdOptions
  247. PortMapping []string `help:"Port mapping of the pod and the format is: host_port=8080,port=80,protocol=<tcp|udp>,host_port_range=<int>-<int>" short-token:"p"`
  248. }
  249. func (o *PodSetPortMappingOptions) Params() (jsonutils.JSONObject, error) {
  250. portMappings := make([]*computeapi.PodPortMapping, 0)
  251. if len(o.PortMapping) != 0 {
  252. for _, input := range o.PortMapping {
  253. pm, err := ParsePodPortMapping(input)
  254. if err != nil {
  255. return nil, errors.Wrapf(err, "parse port mapping: %s", input)
  256. }
  257. portMappings = append(portMappings, pm)
  258. }
  259. }
  260. return jsonutils.Marshal(&computeapi.GuestSetPortMappingsInput{
  261. PortMappings: portMappings,
  262. }), nil
  263. }