yunion.io/x/cloudmux@v0.3.10-0-alpha.1/cmd/cmx/shell/helper.go (about)

     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  
    15  package shell
    16  
    17  import (
    18  	"net/http"
    19  	"net/url"
    20  	"os"
    21  
    22  	"golang.org/x/net/http/httpproxy"
    23  
    24  	"yunion.io/x/jsonutils"
    25  	"yunion.io/x/log"
    26  	"yunion.io/x/pkg/errors"
    27  
    28  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    29  	"yunion.io/x/cloudmux/pkg/cloudprovider/generic"
    30  	"yunion.io/x/onecloud/pkg/util/shellutils"
    31  	"yunion.io/x/onecloud/pkg/util/printutils"
    32  )
    33  
    34  var (
    35  	CommandTable    = &shellutils.CommandTable
    36  	R               = shellutils.R
    37  	PrintList       = printutils.PrintInterfaceList
    38  	PrintObject     = printutils.PrintInterfaceObject
    39  	PrintGetterList = printutils.PrintGetterList
    40  )
    41  
    42  type ICloudProvider interface {
    43  	GetProvider() cloudprovider.ICloudProvider
    44  	GetDefaultRegionId() string
    45  }
    46  
    47  type cloudProvider struct {
    48  	provider  cloudprovider.ICloudProvider
    49  	globalOpt *GlobalOptions
    50  }
    51  
    52  func NewCloudProvider(opt *GlobalOptions) (ICloudProvider, error) {
    53  	if len(opt.AccessKey) == 0 {
    54  		return nil, errors.Errorf("Missing accessKey")
    55  	}
    56  
    57  	if len(opt.Secret) == 0 {
    58  		return nil, errors.Errorf("Missing secret")
    59  	}
    60  
    61  	cfg := &httpproxy.Config{
    62  		HTTPProxy:  os.Getenv("HTTP_PROXY"),
    63  		HTTPSProxy: os.Getenv("HTTPS_PROXY"),
    64  		NoProxy:    os.Getenv("NO_PROXY"),
    65  	}
    66  	cfgProxyFunc := cfg.ProxyFunc()
    67  	proxyFunc := func(req *http.Request) (*url.URL, error) {
    68  		return cfgProxyFunc(req.URL)
    69  	}
    70  
    71  	factory, err := cloudprovider.GetProviderFactory(opt.Provider)
    72  	if err != nil {
    73  		return nil, errors.Wrapf(err, "GetProviderFactory")
    74  	}
    75  
    76  	p, err := factory.GetProvider(cloudprovider.ProviderConfig{
    77  		URL:           opt.CloudEnv,
    78  		Account:       opt.AccessKey,
    79  		Secret:        opt.Secret,
    80  		ProxyFunc:     proxyFunc,
    81  		DefaultRegion: opt.Region,
    82  		Debug:         opt.Debug,
    83  	})
    84  
    85  	if err != nil {
    86  		return nil, errors.Wrap(err, "GetProvider")
    87  	}
    88  
    89  	var dr cloudprovider.ICloudRegion = nil
    90  
    91  	if opt.Region != "" {
    92  		dr, _ = generic.GetResourceByIdOrName(p.GetIRegions(), opt.Region)
    93  		if dr == nil {
    94  			rs := p.GetIRegions()
    95  			regions := make([]string, len(rs))
    96  			for i := range rs {
    97  				regions[i] = rs[i].GetId()
    98  			}
    99  			return nil, errors.Errorf("Not found region by %q of %q, choose one of:\n%s", opt.Region, opt.Provider, jsonutils.Marshal(regions).PrettyString())
   100  		}
   101  	}
   102  
   103  	return &cloudProvider{
   104  		provider:  p,
   105  		globalOpt: opt,
   106  	}, nil
   107  }
   108  
   109  func (p *cloudProvider) GetProvider() cloudprovider.ICloudProvider {
   110  	return p.provider
   111  }
   112  
   113  func (p *cloudProvider) GetDefaultRegionId() string {
   114  	return p.globalOpt.Region
   115  }
   116  
   117  func getResources[T cloudprovider.ICloudResource](
   118  	resType string,
   119  	nf func() ([]T, error),
   120  	specifyIdOrName string,
   121  	mustMatch bool) ([]T, error) {
   122  	objs, err := nf()
   123  	if err != nil {
   124  		return nil, errors.Wrapf(err, "get %q resources", resType)
   125  	}
   126  
   127  	if specifyIdOrName == "" {
   128  		if mustMatch {
   129  			return nil, errors.Errorf("Use '--%s' to specify %s", resType, resType)
   130  		} else {
   131  			return objs, nil
   132  		}
   133  	}
   134  	obj, err := generic.GetResourceByIdOrName(objs, specifyIdOrName)
   135  	if err != nil {
   136  		if errors.Cause(err) == cloudprovider.ErrNotFound {
   137  			return nil, errors.Wrapf(err, "%s %s not found", resType, specifyIdOrName)
   138  		}
   139  	}
   140  	return []T{obj}, nil
   141  }
   142  
   143  func iterResources[T cloudprovider.ICloudResource](
   144  	resType string,
   145  	nf func() ([]T, error),
   146  	specifyIdOrName string,
   147  	mustMatch bool,
   148  	ef func(T) error,
   149  ) error {
   150  	op, err := generic.NewOperator(func() ([]T, error) {
   151  		return getResources(resType, nf, specifyIdOrName, mustMatch)
   152  	})
   153  	if err != nil {
   154  		return err
   155  	}
   156  	return op.Iter(func(t T) error {
   157  		log.Infof("With %s %q", resType, t.GetGlobalId())
   158  		return ef(t)
   159  	}, false)
   160  }
   161  
   162  // func regionR[OPT any](opts OPT, command string, desc string, requireDefaultRegion bool, cb func(cloudprovider.ICloudRegion, OPT) error) {
   163  // 	R(opts, command, desc, func(cli ICloudProvider, args OPT) error {
   164  // 		return iterResources(
   165  // 			"region",
   166  // 			func() ([]cloudprovider.ICloudRegion, error) {
   167  // 				return cli.GetProvider().GetIRegions(), nil
   168  // 			},
   169  // 			cli.GetDefaultRegionId(),
   170  // 			requireDefaultRegion,
   171  // 			func(region cloudprovider.ICloudRegion) error {
   172  // 				if err := cb(region, args); err != nil {
   173  // 					return err
   174  // 				}
   175  // 				return nil
   176  // 			},
   177  // 		)
   178  // 	})
   179  // }
   180  //
   181  // func RegionR[T any](opts T, command string, desc string, cb func(cloudprovider.ICloudRegion, T) error) {
   182  // 	regionR(opts, command, desc, true, cb)
   183  // }
   184  //
   185  // func RegionRList[T any](opts T, command string, desc string, cb func(cloudprovider.ICloudRegion, T) error) {
   186  // 	regionR(opts, command, desc, false, cb)
   187  // }
   188  //
   189  // func zoneR[T IZoneBaseOptions](opts T, command string, desc string, requireZone bool, cb func(cloudprovider.ICloudZone, T) error) {
   190  // 	RegionRList(opts, command, desc, func(region cloudprovider.ICloudRegion, opts T) error {
   191  // 		return iterResources(
   192  // 			"zone",
   193  // 			region.GetIZones,
   194  // 			opts.GetZoneId(),
   195  // 			requireZone,
   196  // 			func(zone cloudprovider.ICloudZone) error {
   197  // 				if err := cb(zone, opts); err != nil {
   198  // 					return err
   199  // 				}
   200  // 				return nil
   201  // 			},
   202  // 		)
   203  // 	})
   204  // }
   205  //
   206  // func ZoneRList[T IZoneBaseOptions](opts T, command string, desc string, cb func(cloudprovider.ICloudZone, T) error) {
   207  // 	zoneR(opts, command, desc, false, cb)
   208  // }
   209  //
   210  // func ZoneR[T IZoneBaseOptions](opts T, command string, desc string, cb func(cloudprovider.ICloudZone, T) error) {
   211  // 	zoneR(opts, command, desc, true, cb)
   212  // }
   213  //
   214  // func hostR[T IHostBaseOptions](opts T, command string, desc string, requireHost bool, cb func(cloudprovider.ICloudHost, T) error) {
   215  // 	ZoneRList(opts, command, desc, func(zone cloudprovider.ICloudZone, opts T) error {
   216  // 		return iterResources(
   217  // 			"host",
   218  // 			zone.GetIHosts,
   219  // 			opts.GetHostId(),
   220  // 			requireHost,
   221  // 			func(host cloudprovider.ICloudHost) error {
   222  // 				if err := cb(host, opts); err != nil {
   223  // 					return err
   224  // 				}
   225  // 				return nil
   226  // 			},
   227  // 		)
   228  // 	})
   229  // }
   230  //
   231  // func HostRList[T IHostBaseOptions](opts T, command string, desc string, cb func(cloudprovider.ICloudHost, T) error) {
   232  // 	hostR(opts, command, desc, false, cb)
   233  // }
   234  //
   235  // func HostR[T IHostBaseOptions](opts T, command string, desc string, cb func(cloudprovider.ICloudHost, T) error) {
   236  // 	hostR(opts, command, desc, true, cb)
   237  // }