新资源接入
介绍云平台如何接入一个新资源类型。
本文以阿里云ElasticSearch为例(cloudpods从v3.8开始支持),介绍如何纳管ElasticSearch
git diff 参考(同时会有腾讯云对接)
https://github.com/yunionio/cloudpods/pull/11595/files
提示
自v3.10开始, cloudpods对于各个云的操作都将移至cloudmux仓库, pkg/cloudprovider及pkg/multicloud的改动需要到cloudmux进行
定义 ElasticSearch 接口
编辑 pkg/cloudprovider/resources.go 文件,文件末尾追加。
type ICloudElasticSearch interface {
// 说明: 同步时,可以仅定义一些基础的信息,先将资源同步下来
// 后面再根据资属性,往资源加相应的接口或操作
IVirtualResource
IBillingResource
}
实现阿里云的基础数据结构
创建 pkg/multicloud/aliyun/elastic_search.go 文件,填充阿里云ElasticSearch基础数据结构。
package aliyun
type SElasticSearch struct {
// 这里统一实现了Aliyun标签接口,可以减少一些函数声明
multicloud.AliyunTags
// 同上, 但部分IVirtualResource接口依然需要实现
multicloud.SVirtualResourceBase
// 一些计费的基础方法
multicloud.SBillingBase
// 链式结构, 用于对ElasticSearch进行操作
region *SRegion
// 阿里云 ElasticSearch 属性
...
}
// 实现获取阿里云 ElasticSearch 资源函数
// 获取 ElasticSearch 资源列表
func (self *SRegion) GetElasticSearchs(size, page int) ([]SElasticSearch, int, error) {
...
}
// 获取单个 ElasticSearch 资源
func (self *SRegion) GetElasitcSearch(id string) (*SElasticSearch, error) {
...
}
实现 aliyuncli 命令行(用于快速调试)
创建 pkg/multicloud/aliyun/shell/elk.go 文件。
package shell
func init() {
type ElkListOptions struct {
Page int
Size int
}
shellutils.R(&ElkListOptions{}, "elastic-search-list", "List elastic searchs", func(cli *aliyun.SRegion, args *ElkListOptions) error {
elks, _, err := cli.GetElasticSearchs(args.Size, args.Page)
if err != nil {
return err
}
printList(elks, 0, 0, 0, nil)
return nil
})
type ElkIdOptions struct {
ID string
}
shellutils.R(&ElkIdOptions{}, "elastic-search-show", "Show elasitc search", func(cli *aliyun.SRegion, args *ElkIdOptions) error {
elk, err := cli.GetElasitcSearch(args.ID)
if err != nil {
return err
}
printObject(elk)
return nil
})
}
调试 aliyuncli 命令
# 克隆cloudmux
$ git clone https://github.com/yunionio/cloudmux.git && cd cloudmux
# 编译 aliyuncli 命令
$ make cmd/aliyuncli
# 声明环境变量
$ export ALIYUN_ACCESS_KEY=LTAI5H1wXkXeas1M
$ export ALIYUN_SECRET=cByPBQM9zFVgNBMKNJZMYrKFUkvVk8
# 这里需要根据地域情况自行设置
$ export ALIYUN_REGION=cn-beijing
# 执行列出 ElasticSearch 资源命令
$ ./_output/bin/aliyuncli elastic-search-list
$ ./_output/bin/aliyuncli elastic-search-show es-cn-n6w1ptcb30009****
补充 ElasticSearch 接口
编辑 pkg/multicloud/aliyun/elastic_search.go 文件,实现以下接口。
func (self *SElasticSearch) GetId() string {
...
}
// 此函数返回值将会存储到数据库的external_id字段里面,请确保能和云上资源一一对应
// 若是Azure资源, 请务必返回时strings.ToLower(), 因为Azure资源Id不区分大小写,但id大小写返回不固定,在同步时 会引起资源反复增删问题
func (self *SElasticSearch) GetGlobalId() string {
...
}
// 获取ElasticSearch资源名称
func (self *SElasticSearch) GetName() string {
...
}
// 创建删除或其他操作需要循环获取资源状态, 来判定操作是否结束, 此函数主要是刷新状态字段或其他相关字段
func (self *SElasticSearch) Refresh() error {
...
}
// 获取资源创建时间
func (self *SElasticSearch) GetCreatedAt() time.Time {
...
}
// 获取资源计费方式: 预付费, 后付费?
func (self *SElasticSearch) GetBillingType() string {
...
}
// 获取资源归属项目Id
func (self *SElasticSearch) GetProjectId() string {
...
}
// 获取资源状态
func (self *SElasticSearch) GetStatus() string {
...
}
添加区域获取 ElasticSearch 接口
编辑 pkg/cloudprovider/resources.go 文件,找到 ICloudRegion 定义, 并补充以下两个接口:
type ICloudRegion interface {
...
GetIElasticSearchs() ([]ICloudElasticSearch, error)
GetIElasticSearchById(id string) (ICloudElasticSearch, error)
}
编辑 pkg/multicloud/region_base.go 实现基础的两个方法。
// 这里主要是因为对接往往是从一两个云开始
// 若不实现这两个基础方法,则需要在每一个云的region.go文件实现这两个方法
func (self *SRegion) GetIElasticSearchs() ([]cloudprovider.ICloudElasticSearch, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetIElasticSearchs")
}
func (self *SRegion) GetIElasticSearchById(id string) (cloudprovider.ICloudElasticSearch, error) {
return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetIElasticSearchById")
}
编辑 pkg/multicloud/aliyun/elastic_search.go 文件
// 实现阿里云的这两个方法
// 实现 GetIElasticSearchs 接口
func (self *SRegion) GetIElasticSearchs() ([]cloudprovider.ICloudElasticSearch, error) {
// 获取当前region的所有elasticsearch实例
ess, err := self.GetElasticSearchs(...)
if err != nil {
return err
}
ret := []cloudprovider.ICloudElasticSearch{}
for i := range ess {
// 这里需要赋值,例如删除, 就可以使用 ess[i].region.DeleteElasticSearch(ess[i].InstanceId)
ess[i].region = self
ret = append(ret, &ess[i])
}
return ret, nil
}
// 实现 GetIElasticSearchById 接口
func (self *SRegion) GetIElasticSearchById(id string) (cloudprovider.ICloudElasticSearch, error) {
// 这里没有使用es.region = self,是因为在GetElasitcSearch函数里面已经赋值过了
es, err := self.GetElasitcSearch(id)
if err != nil {
return nil, err
}
return es, nil
}