| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package cmdline
- import (
- "fmt"
- "regexp"
- "strconv"
- "strings"
- "yunion.io/x/jsonutils"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/fileutils"
- "yunion.io/x/pkg/util/netutils"
- "yunion.io/x/pkg/util/osprofile"
- "yunion.io/x/pkg/util/regutils"
- "yunion.io/x/pkg/util/sets"
- "yunion.io/x/pkg/utils"
- billing_api "yunion.io/x/onecloud/pkg/apis/billing"
- "yunion.io/x/onecloud/pkg/apis/compute"
- "yunion.io/x/onecloud/pkg/httperrors"
- )
- var (
- ErrorEmptyDesc = errors.Errorf("Empty description")
- )
- // ParseSchedtagConfig desc format: <schedtagName>:<strategy>:<resource_type>
- func ParseSchedtagConfig(desc string) (*compute.SchedtagConfig, error) {
- if len(desc) == 0 {
- return nil, ErrorEmptyDesc
- }
- parts := strings.Split(desc, ":")
- if len(parts) < 2 {
- return nil, fmt.Errorf("Invalid desc: %s", desc)
- }
- strategy := parts[1]
- if !utils.IsInStringArray(strategy, compute.STRATEGY_LIST) {
- return nil, fmt.Errorf("Invalid strategy: %s", strategy)
- }
- conf := &compute.SchedtagConfig{
- Id: parts[0],
- Strategy: parts[1],
- }
- if len(parts) == 3 {
- conf.ResourceType = parts[2]
- }
- return conf, nil
- }
- // ParseResourceSchedtagConfig desc format: <idx>:<schedtagName>:<strategy>
- func ParseResourceSchedtagConfig(desc string) (int, *compute.SchedtagConfig, error) {
- if len(desc) == 0 {
- return 0, nil, ErrorEmptyDesc
- }
- parts := strings.Split(desc, ":")
- if len(parts) != 3 {
- return 0, nil, fmt.Errorf("Invalid desc: %s", desc)
- }
- idx, err := strconv.Atoi(parts[0])
- if err != nil {
- return 0, nil, err
- }
- tag, err := ParseSchedtagConfig(fmt.Sprintf("%s:%s", parts[1], parts[2]))
- if err != nil {
- return 0, nil, err
- }
- return idx, tag, nil
- }
- func ParseDiskConfig(diskStr string, idx int) (*compute.DiskConfig, error) {
- if len(diskStr) == 0 {
- return nil, ErrorEmptyDesc
- }
- diskConfig := new(compute.DiskConfig)
- diskConfig.Index = idx
- // default backend and medium type
- diskConfig.Backend = "" // STORAGE_LOCAL
- diskConfig.Medium = ""
- diskConfig.SizeMb = -1
- oldPart, newPart := []string{}, []string{}
- for _, d0 := range strings.Split(diskStr, ",") {
- for _, d1 := range strings.Split(d0, ":") {
- if len(d1) == 0 {
- continue
- }
- if strings.Contains(d1, "=") {
- newPart = append(newPart, d1)
- continue
- }
- oldPart = append(oldPart, d1)
- }
- }
- for _, p := range oldPart {
- if regutils.MatchSize(p) {
- diskConfig.SizeMb, _ = fileutils.GetSizeMb(p, 'M', 1024)
- } else if utils.IsInStringArray(p, osprofile.FS_TYPES) {
- diskConfig.Fs = p
- } else if utils.IsInStringArray(p, osprofile.IMAGE_FORMAT_TYPES) {
- diskConfig.Format = p
- } else if utils.IsInStringArray(p, osprofile.DISK_DRIVERS) {
- diskConfig.Driver = p
- } else if utils.IsInStringArray(p, osprofile.DISK_CACHE_MODES) {
- diskConfig.Cache = p
- } else if utils.IsInStringArray(p, compute.DISK_TYPES) {
- diskConfig.Medium = p
- } else if utils.IsInStringArray(p, []string{compute.DISK_TYPE_VOLUME}) {
- diskConfig.DiskType = p
- } else if p[0] == '/' {
- diskConfig.Mountpoint = p
- } else if p == "autoextend" {
- diskConfig.SizeMb = -1
- } else if p == "autoreset" {
- diskConfig.AutoReset = true
- } else if utils.IsInStringArray(p, compute.STORAGE_TYPES) {
- diskConfig.Backend = p
- } else if len(p) > 0 {
- diskConfig.ImageId = p
- }
- }
- for _, p := range newPart {
- info := strings.Split(p, "=")
- if len(info) != 2 {
- return nil, errors.Errorf("invalid disk description %s", p)
- }
- var err error
- desc, str := info[0], info[1]
- switch desc {
- case "size":
- diskConfig.SizeMb, err = fileutils.GetSizeMb(str, 'M', 1024)
- if err != nil {
- return nil, errors.Errorf("invalid disk size %s", str)
- }
- case "fs":
- if !utils.IsInStringArray(str, osprofile.FS_TYPES) {
- return nil, errors.Errorf("invalid disk fs %s, allow choices: %s", str, osprofile.FS_TYPES)
- }
- diskConfig.Fs = str
- case "fs_features":
- if diskConfig.Fs == "" {
- return nil, errors.Errorf("disk fs is required")
- }
- diskConfig.FsFeatures = &compute.DiskFsFeatures{}
- for _, feature := range strings.Split(str, ",") {
- if diskConfig.Fs == "ext4" {
- if diskConfig.FsFeatures.Ext4 == nil {
- diskConfig.FsFeatures.Ext4 = &compute.DiskFsExt4Features{}
- }
- if feature == "casefold" {
- diskConfig.FsFeatures.Ext4.CaseInsensitive = true
- } else {
- return nil, errors.Errorf("invalid feature %s of %s", feature, diskConfig.Fs)
- }
- }
- if diskConfig.Fs == "f2fs" {
- if diskConfig.FsFeatures.F2fs == nil {
- diskConfig.FsFeatures.F2fs = &compute.DiskFsF2fsFeatures{}
- }
- if feature == "casefold" {
- diskConfig.FsFeatures.F2fs.CaseInsensitive = true
- } else {
- return nil, errors.Errorf("invalid feature %s of %s", feature, diskConfig.Fs)
- }
- }
- }
- case "format":
- if !utils.IsInStringArray(str, osprofile.IMAGE_FORMAT_TYPES) {
- return nil, errors.Errorf("invalid disk format %s, allow choices: %s", str, osprofile.IMAGE_FORMAT_TYPES)
- }
- diskConfig.Format = str
- case "driver":
- if !utils.IsInStringArray(str, osprofile.DISK_DRIVERS) {
- return nil, errors.Errorf("invalid disk driver %s, allow choices: %s", str, osprofile.DISK_DRIVERS)
- }
- diskConfig.Driver = str
- case "cache", "cache_mode":
- if !utils.IsInStringArray(str, osprofile.DISK_CACHE_MODES) {
- return nil, errors.Errorf("invalid disk cache mode %s, allow choices: %s", str, osprofile.DISK_CACHE_MODES)
- }
- diskConfig.Cache = str
- case "medium":
- if !utils.IsInStringArray(str, compute.DISK_TYPES) {
- return nil, errors.Errorf("invalid disk medium type %s, allow choices: %s", str, compute.DISK_TYPES)
- }
- diskConfig.Medium = str
- case "type", "disk_type":
- diskTypes := []string{compute.DISK_TYPE_SYS, compute.DISK_TYPE_DATA}
- if !utils.IsInStringArray(str, diskTypes) {
- return nil, errors.Errorf("invalid disk type %s, allow choices: %s", str, diskTypes)
- }
- diskConfig.DiskType = str
- case "mountpoint":
- diskConfig.Mountpoint = str
- case "storage_type", "backend":
- diskConfig.Backend = str
- case "snapshot", "snapshot_id":
- diskConfig.SnapshotId = str
- case "disk", "disk_id":
- diskConfig.DiskId = str
- case "storage", "storage_id":
- diskConfig.Storage = str
- case "image", "image_id":
- diskConfig.ImageId = str
- case "existing_path":
- diskConfig.ExistingPath = str
- case "boot_index":
- bootIndex, err := strconv.Atoi(str)
- if err != nil {
- return nil, errors.Wrapf(err, "parse disk boot index %s", str)
- }
- bootIndex8 := int8(bootIndex)
- diskConfig.BootIndex = &bootIndex8
- case "nvme-device-id":
- diskConfig.NVMEDevice = &compute.IsolatedDeviceConfig{
- Id: str,
- }
- case "nvme-device-model":
- diskConfig.NVMEDevice = &compute.IsolatedDeviceConfig{
- Model: str,
- }
- case "iops":
- diskConfig.Iops, _ = strconv.Atoi(str)
- if err != nil {
- return nil, errors.Wrapf(err, "parse disk iops %s", str)
- }
- case "throughput":
- diskConfig.Throughput, _ = strconv.Atoi(str)
- if err != nil {
- return nil, errors.Wrapf(err, "parse disk iops %s", str)
- }
- case "preallocation":
- if !utils.IsInStringArray(str, compute.DISK_PREALLOCATIONS) {
- return nil, errors.Errorf("invalid preallocation %s, allow choices: %s", str, compute.DISK_PREALLOCATIONS)
- }
- diskConfig.Preallocation = str
- case "auto_delete":
- v, err := strconv.ParseBool(str)
- if err != nil {
- return nil, errors.Wrapf(err, "parse disk auto_delete %s", str)
- }
- diskConfig.AutoDelete = &v
- default:
- return nil, errors.Errorf("invalid disk description %s", p)
- }
- }
- return diskConfig, nil
- }
- func ParseNetworkConfigByJSON(desc jsonutils.JSONObject, idx int) (*compute.NetworkConfig, error) {
- if _, ok := desc.(*jsonutils.JSONString); ok {
- descStr, _ := desc.GetString()
- return ParseNetworkConfig(descStr, idx)
- }
- conf := new(compute.NetworkConfig)
- conf.Index = idx
- err := desc.Unmarshal(conf)
- return conf, err
- }
- func isQuoteChar(ch byte) (bool, string) {
- switch ch {
- case '[':
- return true, "]"
- default:
- return false, ""
- }
- }
- func splitConfig(confStr string) ([]string, error) {
- return utils.FindWords2([]byte(confStr), 0, ":", isQuoteChar)
- }
- func ParseNetworkConfig(desc string, idx int) (*compute.NetworkConfig, error) {
- if len(desc) == 0 {
- return nil, ErrorEmptyDesc
- }
- parts, err := splitConfig(desc)
- if err != nil {
- return nil, errors.Wrap(err, "splitConfig")
- }
- netConfig := new(compute.NetworkConfig)
- netConfig.Index = idx
- for _, p := range parts {
- if len(p) == 0 {
- continue
- }
- if regutils.MatchIP4Addr(p) {
- netConfig.Address = p
- } else if regutils.MatchIP6Addr(p) {
- addr6, err := netutils.NewIPV6Addr(p)
- if err != nil {
- return nil, errors.Wrap(httperrors.ErrInvalidFormat, p)
- }
- netConfig.Address6 = addr6.String()
- } else if regutils.MatchCompactMacAddr(p) {
- netConfig.Mac = netutils.MacUnpackHex(p)
- } else if strings.HasPrefix(p, "wire=") {
- netConfig.Wire = p[len("wire="):]
- } else if strings.HasPrefix(p, "macs=") {
- macSegs := strings.Split(p[len("macs="):], ",")
- macs := make([]string, len(macSegs))
- for i := range macSegs {
- macs[i] = netutils.MacUnpackHex(macSegs[i])
- }
- netConfig.Macs = macs
- } else if strings.HasPrefix(p, "ips=") {
- netConfig.Addresses = strings.Split(p[len("ips="):], ",")
- for _, addr := range netConfig.Addresses {
- _, err := netutils.NewIPV4Addr(addr)
- if err != nil {
- return nil, errors.Wrap(err, p)
- }
- }
- } else if strings.HasPrefix(p, "ip6s=") {
- netConfig.Addresses6 = strings.Split(p[len("ip6s="):], ",")
- for i, addrStr := range netConfig.Addresses6 {
- addr6, err := netutils.NewIPV6Addr(addrStr)
- if err != nil {
- return nil, errors.Wrap(err, p)
- }
- netConfig.Addresses6[i] = addr6.String()
- }
- } else if strings.HasPrefix(p, "secgroups=") {
- netConfig.Secgroups = strings.Split(p[len("secgroups="):], ",")
- } else if p == "require_designated_ip" {
- netConfig.RequireDesignatedIP = true
- } else if p == "random_exit" {
- netConfig.Exit = true
- } else if p == "random" {
- netConfig.Exit = false
- } else if p == "private" {
- netConfig.Private = true
- } else if p == "reserved" {
- netConfig.Reserved = true
- } else if p == "teaming" {
- netConfig.RequireTeaming = true
- } else if p == "try-teaming" {
- netConfig.TryTeaming = true
- } else if p == "defaultgw" {
- netConfig.IsDefault = true
- } else if p == "ipv6" {
- netConfig.RequireIPv6 = true
- } else if p == "strict-ipv6" {
- netConfig.RequireIPv6 = true
- netConfig.StrictIPv6 = true
- } else if strings.HasPrefix(p, "standby-port=") {
- netConfig.StandbyPortCount, _ = strconv.Atoi(p[len("standby-port="):])
- } else if strings.HasPrefix(p, "standby-addr=") {
- netConfig.StandbyAddrCount, _ = strconv.Atoi(p[len("standby-addr="):])
- } else if utils.IsInStringArray(p, []string{"virtio", "e1000", "vmxnet3"}) {
- netConfig.Driver = p
- } else if strings.HasPrefix(p, "num-queues=") {
- netConfig.NumQueues, _ = strconv.Atoi(p[len("num-queues="):])
- } else if strings.HasPrefix(p, "billing-type=") {
- netConfig.BillingType = billing_api.ParseBillingType(p[len("billing-type="):])
- } else if strings.HasPrefix(p, "charge-type=") {
- netConfig.ChargeType = billing_api.ParseNetChargeType(p[len("charge-type="):])
- } else if regutils.MatchSize(p) {
- bw, err := fileutils.GetSizeMb(p, 'M', 1000)
- if err != nil {
- return nil, err
- }
- netConfig.BwLimit = bw
- } else if p == "vip" {
- netConfig.Vip = true
- } else if strings.HasPrefix(p, "sriov-nic-id=") {
- netConfig.SriovDevice = &compute.IsolatedDeviceConfig{
- Id: p[len("sriov-nic-id="):],
- }
- } else if strings.HasPrefix(p, "sriov-nic-model=") {
- netConfig.SriovDevice = &compute.IsolatedDeviceConfig{
- Model: p[len("sriov-nic-model="):],
- }
- } else if strings.HasPrefix(p, "rx-traffic-limit=") {
- var err error
- netConfig.RxTrafficLimit, err = strconv.ParseInt(p[len("rx-traffic-limit="):], 10, 0)
- if err != nil {
- return nil, errors.Wrap(err, "parse rx-traffic-limit")
- }
- } else if strings.HasPrefix(p, "tx-traffic-limit=") {
- var err error
- netConfig.TxTrafficLimit, err = strconv.ParseInt(p[len("tx-traffic-limit="):], 10, 0)
- if err != nil {
- return nil, errors.Wrap(err, "parse tx-traffic-limit")
- }
- } else if compute.IsInNetworkTypes(compute.TNetworkType(p), compute.ALL_NETWORK_TYPES) {
- netConfig.NetType = compute.TNetworkType(p)
- } else {
- netConfig.Network = p
- }
- }
- return netConfig, nil
- }
- func ParseNetworkConfigPortMappings(descs []string) (map[int]compute.GuestPortMappings, error) {
- if len(descs) == 0 {
- return nil, ErrorEmptyDesc
- }
- pms := make(map[int]compute.GuestPortMappings, 0)
- for _, desc := range descs {
- idx, pm, err := parseNetworkConfigPortMapping(desc)
- if err != nil {
- return nil, errors.Wrapf(err, "parse port mapping: %s", desc)
- }
- mappings, ok := pms[idx]
- if !ok {
- mappings = make([]*compute.GuestPortMapping, 0)
- }
- mappings = append(mappings, pm)
- pms[idx] = mappings
- }
- return pms, nil
- }
- func parseNetworkConfigPortMapping(desc string) (int, *compute.GuestPortMapping, error) {
- pm := &compute.GuestPortMapping{
- Protocol: compute.GuestPortMappingProtocolTCP,
- }
- idx := 0
- for _, seg := range strings.Split(desc, ",") {
- info := strings.Split(seg, "=")
- if len(info) != 2 {
- return -1, nil, errors.Errorf("invalid option %s", seg)
- }
- key := info[0]
- val := info[1]
- switch key {
- case "index":
- valIdx, err := strconv.Atoi(val)
- if err != nil {
- return -1, nil, errors.Wrapf(err, "invalid index %s", val)
- }
- idx = valIdx
- case "host_port":
- hp, err := strconv.Atoi(val)
- if err != nil {
- return -1, nil, errors.Wrapf(err, "invalid host_port %s", val)
- }
- pm.HostPort = &hp
- case "container_port", "port":
- cp, err := strconv.Atoi(val)
- if err != nil {
- return -1, nil, errors.Wrapf(err, "invalid container_port %s", val)
- }
- pm.Port = cp
- case "proto", "protocol":
- pm.Protocol = compute.GuestPortMappingProtocol(val)
- case "host_port_range":
- rangeParts := strings.Split(val, "-")
- if len(rangeParts) != 2 {
- return -1, nil, errors.Errorf("invalid range string %s", val)
- }
- start, err := strconv.Atoi(rangeParts[0])
- if err != nil {
- return -1, nil, errors.Wrapf(err, "invalid host_port_range %s", rangeParts[0])
- }
- end, err := strconv.Atoi(rangeParts[1])
- if err != nil {
- return -1, nil, errors.Wrapf(err, "invalid host_port_range %s", rangeParts[1])
- }
- pm.HostPortRange = &compute.GuestPortMappingPortRange{
- Start: start,
- End: end,
- }
- case "remote_ips", "remote_ip":
- ips := strings.Split(val, "|")
- pm.RemoteIps = ips
- }
- }
- if pm.Port == 0 {
- return -1, nil, errors.Error("container_port must specified")
- }
- if idx < 0 {
- return -1, nil, errors.Errorf("invalid index %d", idx)
- }
- return idx, pm, nil
- }
- func ParseIsolatedDevice(desc string, idx int) (*compute.IsolatedDeviceConfig, error) {
- if len(desc) == 0 {
- return nil, ErrorEmptyDesc
- }
- if idx < 0 {
- return nil, fmt.Errorf("Invalid index: %d", idx)
- }
- dev := new(compute.IsolatedDeviceConfig)
- parts := strings.Split(desc, ":")
- devTypes := sets.NewString(compute.VALID_PASSTHROUGH_TYPES...)
- devTypes.Insert(compute.VALID_CONTAINER_DEVICE_TYPES...)
- for _, p := range parts {
- if regutils.MatchUUIDExact(p) {
- dev.Id = p
- } else if devTypes.Has(p) {
- dev.DevType = p
- } else if strings.HasPrefix(p, "vendor=") {
- dev.Vendor = p[len("vendor="):]
- } else if strings.HasPrefix(p, "device_path=") {
- dev.DevicePath = p[len("device_path="):]
- } else {
- dev.Model = p
- }
- }
- return dev, nil
- }
- func ParseBaremetalRootDiskMatcher(line string) (*compute.BaremetalRootDiskMatcher, error) {
- ret := new(compute.BaremetalRootDiskMatcher)
- for _, seg := range strings.Split(line, ",") {
- info := strings.Split(seg, "=")
- if len(info) != 2 {
- return nil, errors.Errorf("invalid option %s", seg)
- }
- key := info[0]
- val := info[1]
- switch key {
- case "size":
- sizeMB, err := fileutils.GetSizeMb(val, 'M', 1024)
- if err != nil {
- return nil, errors.Wrapf(err, "parse size %s", val)
- }
- ret.SizeMB = int64(sizeMB)
- case "device", "dev":
- ret.Device = val
- case "size_start":
- sizeMB, err := fileutils.GetSizeMb(val, 'M', 1024)
- if err != nil {
- return nil, errors.Wrapf(err, "parse size_start %s", val)
- }
- if ret.SizeMBRange == nil {
- ret.SizeMBRange = new(compute.RootDiskMatcherSizeMBRange)
- }
- ret.SizeMBRange.Start = int64(sizeMB)
- case "size_end":
- sizeMB, err := fileutils.GetSizeMb(val, 'M', 1024)
- if err != nil {
- return nil, errors.Wrapf(err, "parse size_end %s", val)
- }
- if ret.SizeMBRange == nil {
- ret.SizeMBRange = new(compute.RootDiskMatcherSizeMBRange)
- }
- ret.SizeMBRange.End = int64(sizeMB)
- }
- }
- return ret, nil
- }
- func ParseBaremetalDiskConfig(desc string) (*compute.BaremetalDiskConfig, error) {
- bdc := new(compute.BaremetalDiskConfig)
- bdc.Type = compute.DISK_TYPE_HYBRID
- bdc.Conf = compute.DISK_CONF_NONE
- bdc.Count = 0
- desc = strings.ToLower(desc)
- if len(desc) == 0 {
- return bdc, nil
- }
- parts := strings.Split(desc, ":")
- drvMap := make(map[string]string)
- for _, drv := range compute.DISK_DRIVERS.List() {
- drvMap[strings.ToLower(drv)] = drv
- }
- for _, p := range parts {
- if len(p) == 0 {
- continue
- } else if utils.IsInStringArray(p, compute.DISK_TYPES) {
- bdc.Type = p
- } else if compute.DISK_CONFS.Has(p) {
- bdc.Conf = p
- } else if drv, ok := drvMap[p]; ok {
- bdc.Driver = drv
- } else if utils.IsMatchInteger(p) {
- bdc.Count, _ = strconv.ParseInt(p, 0, 0)
- } else if len(p) > 2 && p[0] == '[' && p[len(p)-1] == ']' {
- rg, err1 := ParseRange(p[1:(len(p) - 1)])
- if err1 != nil {
- return nil, err1
- }
- bdc.Range = rg
- } else if len(p) > 2 && p[0] == '(' && p[len(p)-1] == ')' {
- bdc.Splits = p[1 : len(p)-1]
- } else if utils.HasPrefix(p, "strip") {
- strip := parseStrip(p[len("strip"):], "k")
- bdc.Strip = &strip
- } else if utils.HasPrefix(p, "adapter") {
- ada, _ := strconv.ParseInt(p[len("adapter"):], 0, 64)
- pada := int(ada)
- bdc.Adapter = &pada
- } else if p == "ra" {
- hasRA := true
- bdc.RA = &hasRA
- } else if p == "nora" {
- noRA := false
- bdc.RA = &noRA
- } else if p == "wt" {
- wt := true
- bdc.WT = &wt
- } else if p == "wb" {
- wt := false
- bdc.WT = &wt
- } else if p == "direct" {
- direct := true
- bdc.Direct = &direct
- } else if p == "cached" {
- direct := false
- bdc.Direct = &direct
- } else if p == "cachedbadbbu" {
- cached := true
- bdc.Cachedbadbbu = &cached
- } else if p == "nocachedbadbbu" {
- cached := false
- bdc.Cachedbadbbu = &cached
- } else {
- return nil, fmt.Errorf("ParseDiskConfig unkown option %q", p)
- }
- }
- return bdc, nil
- }
- func ParseRange(rangeStr string) (ret []int64, err error) {
- rss := regexp.MustCompile(`[\s,]+`).Split(rangeStr, -1)
- intSet := sets.NewInt64()
- for _, rs := range rss {
- r, err1 := _parseRange(rs)
- if err1 != nil {
- err = err1
- return
- }
- intSet.Insert(r...)
- }
- ret = intSet.List()
- return
- }
- // range string should be: "1-3", "3"
- func _parseRange(str string) (ret []int64, err error) {
- if len(str) == 0 {
- return
- }
- // exclude "," symbol
- if len(str) == 1 && !utils.IsMatchInteger(str) {
- return
- }
- // add int string
- if utils.IsMatchInteger(str) {
- i, _ := strconv.ParseInt(str, 10, 64)
- ret = append(ret, i)
- return
- }
- // add rang like string, "2-10" etc.
- ret, err = parseRangeStr(str)
- return
- }
- // return KB
- func parseStrip(stripStr string, defaultSize string) int64 {
- size, _ := utils.GetSize(stripStr, defaultSize, 1024)
- return size / 1024
- }
- func parseRangeStr(str string) (ret []int64, err error) {
- im := utils.IsMatchInteger
- errGen := func(e string) error {
- return fmt.Errorf("Incorrect range str: %q", e)
- }
- rs := strings.Split(str, "-")
- if len(rs) != 2 {
- err = errGen(str)
- return
- }
- bs, es := rs[0], rs[1]
- if !im(bs) {
- err = errGen(str)
- return
- }
- if !im(es) {
- err = errGen(str)
- return
- }
- begin, _ := strconv.ParseInt(bs, 10, 64)
- end, _ := strconv.ParseInt(es, 10, 64)
- if begin > end {
- begin, end = end, begin
- }
- for i := begin; i <= end; i++ {
- ret = append(ret, i)
- }
- return
- }
|