diff --git a/README.md b/README.md index 34a72d89..6d46b89b 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ bce-sdk-go | |--bbc //物理服务器 | |--bcc //云服务器 | |--bie //百度边缘计算 +| |--bls //日志服务 | |--bos //BOS服务目录 | | |--bos_client.go //BOS客户端入口 | | |--api //BOS相关API目录 @@ -231,6 +232,7 @@ myLogger.Info("this is my own logger from the sdk") 云服务器 | BCC | github.com/baidubce/bce-sdk-go/services/bcc | [BCC.md](./doc/BCC.md) 百度边缘计算 | BIE | github.com/baidubce/bce-sdk-go/services/bie | 负载均衡 | BLB | github.com/baidubce/bce-sdk-go/services/blb | [BLB.md](./doc/BLB.md) +日志服务 | BLS | github.com/baidubce/bce-sdk-go/services/bls | [BLS.md](./doc/BLS.md) 百度对象存储 | BOS | github.com/baidubce/bce-sdk-go/services/bos | [BOS.md](./doc/BOS.md) 容器引擎 | CCE | github.com/baidubce/bce-sdk-go/services/cce | [CCE.md](./doc/CCE.md) 内容分布网络 | CDN | github.com/baidubce/bce-sdk-go/services/cdn | [CDN.md](./doc/CDN.md) diff --git a/doc/BBC.md b/doc/BBC.md index be1f6cbe..7030a810 100644 --- a/doc/BBC.md +++ b/doc/BBC.md @@ -39,7 +39,7 @@ import "github.com/baidubce/bce-sdk-go/services/bbc" func main() { // 用户的Access Key ID和Secret Access Key - ACCESS_KEY_ID, SECRET_ACCESS_KEY := , + AK, SK := , // 用户指定的Endpoint ENDPOINT := @@ -48,7 +48,7 @@ func main() { bbcClient, err := bbc.NewClient(AK, SK, ENDPOINT) } ``` -在上面代码中,`ACCESS_KEY_ID`对应控制台中的“Access Key ID”,`SECRET_ACCESS_KEY`对应控制台中的“Access Key Secret”, +在上面代码中,`AK`对应控制台中的“Access Key ID”,`SK`对应控制台中的“Access Key Secret”, 获取方式请参考[获取AKSK](https://cloud.baidu.com/doc/Reference/s/9jwvz2egb)。 第三个参数`ENDPOINT`支持用户自己指定域名,如果设置为空字符串,会使用默认域名作为BBC的服务地址。 @@ -466,6 +466,22 @@ if err := bbcClient.ModifyInstancePassword(instanceId, modifyInstancePasswordArg } ``` +### 查询实例VNC地址 + +如下代码可以查询实例的VNC地址 +```go +result, err := client.GetInstanceVNC(instanceId) +if err != nil { + fmt.Println("get instance VNC url failed:", err) +} else { + fmt.Println("get instance VNC url success: ", result) +} +``` + +> **提示:** +> - VNC地址一次使用后即失效 +> - URL地址有效期为10分钟 + > **注意:** >BBC 实例密码要求: >- 8-16位字符,英文,数字和符号必须同时存在,符号仅限!@#$%^*() diff --git a/doc/BCC.md b/doc/BCC.md index 7f7a010e..f4567eb8 100644 --- a/doc/BCC.md +++ b/doc/BCC.md @@ -35,7 +35,7 @@ import ( func main() { // 用户的Access Key ID和Secret Access Key - ACCESS_KEY_ID, SECRET_ACCESS_KEY := , + AK, SK := , // 用户指定的Endpoint ENDPOINT := @@ -45,7 +45,7 @@ func main() { } ``` -在上面代码中,`ACCESS_KEY_ID`对应控制台中的“Access Key ID”,`SECRET_ACCESS_KEY`对应控制台中的“Access Key Secret”,获取方式请参考《操作指南 [管理ACCESSKEY](https://cloud.baidu.com/doc/BCC/s/ojwvynrqn)》。第三个参数`ENDPOINT`支持用户自己指定域名,如果设置为空字符串,会使用默认域名作为BCC的服务地址。 +在上面代码中,`AK`对应控制台中的“Access Key ID”,`SK`对应控制台中的“Access Key Secret”,获取方式请参考《操作指南 [管理ACCESSKEY](https://cloud.baidu.com/doc/BCC/s/ojwvynrqn)》。第三个参数`ENDPOINT`支持用户自己指定域名,如果设置为空字符串,会使用默认域名作为BCC的服务地址。 > **注意:**`ENDPOINT`参数需要用指定区域的域名来进行定义,如服务所在区域为北京,则为`bcc.bj.baidubce.com`。 @@ -2692,6 +2692,19 @@ if res, err := BCC_CLIENT.ListTypeZones(args); err != nil { fmt.Println("Get the specific zone flavor success, result: ", res) } ``` + +### 查询bcc、bbc套餐库存 +同时查询bcc、bbc套餐的最大库存。 +只查询用户在console界面上可见的套餐库存。 +查询时需要用户开启查询库存白名单。 +```go +if res, err := BCC_CLIENT.GetAllStocks(); err != nil { + fmt.Println("get all stocks failed: ", err) +} else { + fmt.Println("get all stocks success, result: ", res) +} +``` + ### 查询实例套餐库存 查询实例资源套餐规格对应的库存。 ```go diff --git a/doc/BLS.md b/doc/BLS.md new file mode 100644 index 00000000..ee915279 --- /dev/null +++ b/doc/BLS.md @@ -0,0 +1,675 @@ +# BLS服务 + +# 概述 + +本文档主要介绍BLS GO SDK的使用。在使用本文档前,您需要先了解BLS的一些基本知识,并已开通了BLS服务。若您还不了解BLS,可以参考[产品描述](https://cloud.baidu.com/doc/BLS/index.html)和[入门指南](https://cloud.baidu.com/doc/BLS/s/Gjwvyjbvg)。 + +# 初始化 + +## 确认Endpoint + +在确认您使用SDK时配置的Endpoint时,可先阅读开发人员指南中关于[BLS访问域名](https://cloud.baidu.com/doc/BLS/s/4k8qysj2z)的部分,理解Endpoint相关的概念。百度云目前开放了多区域支持,请参考[区域选择说明](https://cloud.baidu.com/doc/Reference/s/2jwvz23xx)。 + +目前支持“华北-北京”和“华南-广州”两个区域。北京区域:`bls-log.bj.baidubce.com`广州区域:`bls-log.gz.baidubce.com`。对应信息为: + +| 访问区域 | 对应Endpoint | Protocol | +| --------- | ----------------------- | ---------- | +| 华北-北京 | bls-log.bj.baidubce.com | HTTP/HTTPS | +| 华南-广州 | bls-log.gz.baidubce.com | HTTP/HTTPS | + +## 获取密钥 + +要使用百度云BLS,您需要拥有一个有效的AK(Access Key ID)和SK(Secret Access Key)用来进行签名认证。AK/SK是由系统分配给用户的,均为字符串,用于标识用户,为访问BLS做签名验证。 + +可以通过如下步骤获得并了解您的AK/SK信息: + +[注册百度云账号](https://login.bce.baidu.com/reg.html?tpl=bceplat&from=portal) + +[创建AK/SK](https://console.bce.baidu.com/iam/?_=1513940574695#/iam/accesslist) + +## 新建BLS Client + +BLS Client是BLS服务的客户端,为开发者与BLS服务进行交互提供了一系列的方法。 + +### 使用AK/SK新建BLS Client + +通过AK/SK方式访问BLS,用户可以参考如下代码新建一个BLS Client: + +```go +import ( + "github.com/baidubce/bce-sdk-go/services/bls" +) + +func main() { + // 用户的Access Key ID和Secret Access Key + AK, SK := , + + // 用户指定的Endpoint + ENDPOINT := + + // 初始化一个BLSClient + blsClient, err := bls.NewClient(AK, SK, ENDPOINT) +} +``` + +在上面代码中,`AK`对应控制台中的“Access Key ID”,`SK`对应控制台中的“Secret Access Key”,获取方式请参考《通用参考 [获取AKSK](https://cloud.baidu.com/doc/Reference/s/jjwvz2e3p)》。第三个参数`ENDPOINT`支持用户自己指定域名,如果设置为空字符串,会使用默认域名作为BLS的服务地址。 + +> **注意:**`ENDPOINT`参数需要用指定区域的域名来进行定义,如服务所在区域为北京,则为`http://bls-log.bj.baidubce.com`。 + +### 使用STS创建BLS Client + +**申请STS token** + +BLS可以通过STS机制实现第三方的临时授权访问。STS(Security Token Service)是百度云提供的临时授权服务。通过STS,您可以为第三方用户颁发一个自定义时效和权限的访问凭证。第三方用户可以使用该访问凭证直接调用百度云的API或SDK访问百度云资源。 + +通过STS方式访问BLS,用户需要先通过STS的client申请一个认证字符串,申请方式可参见[百度云STS使用介绍](https://cloud.baidu.com/doc/IAM/s/gjwvyc7n7)。 + +**用STS token新建BLS Client** + +申请好STS后,可将STS Token配置到BLS Client中,从而实现通过STS Token创建BLS Client。 + +**代码示例** + +GO SDK实现了STS服务的接口,用户可以参考如下完整代码,实现申请STS Token和创建BLS Client对象: + +```go +import ( + "fmt" + + "github.com/baidubce/bce-sdk-go/auth" //导入认证模块 + "github.com/baidubce/bce-sdk-go/services/bls" //导入BLS服务模块 + "github.com/baidubce/bce-sdk-go/services/sts" //导入STS服务模块 +) + +func main() { + // 创建STS服务的Client对象,Endpoint使用默认值 + AK, SK := , + stsClient, err := sts.NewClient(AK, SK) + if err != nil { + fmt.Println("create sts client object :", err) + return + } + + // 获取临时认证token,有效期为60秒,ACL为空 + stsObj, err := stsClient.GetSessionToken(60, "") + if err != nil { + fmt.Println("get session token failed:", err) + return + } + fmt.Println("GetSessionToken result:") + fmt.Println(" accessKeyId:", stsObj.AccessKeyId) + fmt.Println(" secretAccessKey:", stsObj.SecretAccessKey) + fmt.Println(" sessionToken:", stsObj.SessionToken) + fmt.Println(" createTime:", stsObj.CreateTime) + fmt.Println(" expiration:", stsObj.Expiration) + fmt.Println(" userId:", stsObj.UserId) + + // 使用申请的临时STS创建BLS服务的Client对象,Endpoint使用默认值 + blsClient, err := bls.NewClient(stsObj.AccessKeyId, stsObj.SecretAccessKey, "") + if err != nil { + fmt.Println("create bls client failed:", err) + return + } + stsCredential, err := auth.NewSessionBceCredentials( + stsObj.AccessKeyId, + stsObj.SecretAccessKey, + stsObj.SessionToken) + if err != nil { + fmt.Println("create sts credential object failed:", err) + return + } + blsClient.Config.Credentials = stsCredential +} +``` + +> 注意: +> 目前使用STS配置BLS Client时,无论对应BLS服务的Endpoint在哪里,STS的Endpoint都需配置为http://sts.bj.baidubce.com。上述代码中创建STS对象时使用此默认值。 + +## 配置HTTPS协议访问BLS + +BLS支持HTTPS传输协议,您可以通过在创建BLS Client对象时指定的Endpoint中指明HTTPS的方式,在BLS GO SDK中使用HTTPS访问BLS服务: + +```go +// import "github.com/baidubce/bce-sdk-go/services/bls" + +ENDPOINT := "https://bls-log.bj.baidubce.com" //指明使用HTTPS协议 +AK, SK := , +blsClient, _ := bls.NewClient(AK, SK, ENDPOINT) +``` + +## 配置BLS Client + +如果用户需要配置BLS Client的一些细节的参数,可以在创建BLS Client对象之后,使用该对象的导出字段`Config`进行自定义配置,可以为客户端配置代理,最大连接数等参数。 + +### 使用代理 + +下面一段代码可以让客户端使用代理访问BLS服务: + +```go +// import "github.com/baidubce/bce-sdk-go/services/bls" + +//创建BLS Client对象 +AK, SK := , +ENDPOINT := "bls-log.bj.baidubce.com" +blsClient, _ := bls.NewClient(AK, SK, ENDPOINT) + +//代理使用本地的8080端口 +blsClient.Config.ProxyUrl = "127.0.0.1:8080" +``` + +### 设置网络参数 + +用户可以通过如下的示例代码进行网络参数的设置: + +```go +// import "github.com/baidubce/bce-sdk-go/services/bls" + +AK, SK := , +ENDPOINT := "bls-log.bj.baidubce.com" +blsClient, _ := bls.NewClient(AK, SK, ENDPOINT) + +// 配置不进行重试,默认为Back Off重试 +blsClient.Config.Retry = bce.NewNoRetryPolicy() + +// 配置连接超时时间为30秒 +blsClient.Config.ConnectionTimeoutInMillis = 30 * 1000 +``` + +### 配置生成签名字符串选项 + +```go +// import "github.com/baidubce/bce-sdk-go/services/bls" + +AK, SK := , +ENDPOINT := "bls-log.bj.baidubce.com" +blsClient, _ := bls.NewClient(AK, SK, ENDPOINT) + +// 配置签名使用的HTTP请求头为`Host` +headersToSign := map[string]struct{}{"Host": struct{}{}} +blsClient.Config.SignOption.HeadersToSign = HeadersToSign + +// 配置签名的有效期为30秒 +blsClient.Config.SignOption.ExpireSeconds = 30 +``` + +**参数说明** + +用户使用GO SDK访问BLS时,创建的BLS Client对象的`Config`字段支持的所有参数如下表所示: + +| 配置项名称 | 类型 | 含义 | +| ------------------------- | --------------------- | -------------------------------------- | +| Endpoint | string | 请求服务的域名 | +| ProxyUrl | string | 客户端请求的代理地址 | +| Region | string | 请求资源的区域 | +| UserAgent | string | 用户名称,HTTP请求的User-Agent头 | +| Credentials | \*auth.BceCredentials | 请求的鉴权对象,分为普通AK/SK与STS两种 | +| SignOption | \*auth.SignOptions | 认证字符串签名选项 | +| Retry | RetryPolicy | 连接重试策略 | +| ConnectionTimeoutInMillis | int | 连接超时时间,单位毫秒,默认20分钟 | + +> 说明: +> +> 1. `Credentials`字段使用`auth.NewBceCredentials`与`auth.NewSessionBceCredentials`函数创建,默认使用前者,后者为使用STS鉴权时使用,详见“使用STS创建BLS Client”小节。 +> 2. `SignOption`字段为生成签名字符串时的选项,详见下表说明: +> +> | 名称 | 类型 | 含义 | +> | ------------- | ------------------- | ------------------------------------------------------ | +> | HeadersToSign | map[string]struct{} | 生成签名字符串时使用的HTTP头 | +> | Timestamp | int64 | 生成的签名字符串中使用的时间戳,默认使用请求发送时的值 | +> | ExpireSeconds | int | 签名字符串的有效期 | +> +> 其中,HeadersToSign默认为`Host`,`Content-Type`,`Content-Length`,`Content-MD5`;TimeStamp一般为零值,表示使用调用生成认证字符串时的时间戳,用户一般不应该明确指定该字段的值;ExpireSeconds默认为1800秒即30分钟。 +> +> 3. `Retry`字段指定重试策略,目前支持两种:`NoRetryPolicy`和`BackOffRetryPolicy`。默认使用后者,该重试策略是指定最大重试次数、最长重试时间和重试基数,按照重试基数乘以2的指数级增长的方式进行重试,直到达到最大重试测试或者最长重试时间为止。 + +# 主要接口 + +用户可以通过 API 的方式管理 BLS 日志集、写入、下载、查询和分析日志数据等操作。 + +## LogStore操作 + +### 创建LogStore + +创建日志集,命名日志组时,需遵循以下准则: + +- 每个账户每个区域日志集名称不能重复 +- 日志集名称长度不能超过 128 个字符 +- 日志集名称包含的字符仅限于: `a-z, A-Z, 0-9, '_', '-', '.'` + +通过以下代码,创建一个LogStore并指定其存储期限。 + +```go +err := blsClient.CreateLogStore("demo", 3) +if err != nil { + fmt.Println("Create logStore failed: ", err) +} else { + fmt.Println("Create logStore success.") +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[CreateLogStore](https://cloud.baidu.com/doc/BLS/s/pk8to0k59) + +### 更新指定LogStore + +通过以下代码,更新指定的日志集,目前仅支持更改与日志集关联的存储期限。 + +```go +err := blsClient.UpdateLogStore("demo", 5) +if err != nil { + fmt.Println("Update logStore failed: ", err) +} else { + fmt.Println("Update logStore success.") +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[UpdateLogStore](https://cloud.baidu.com/doc/BLS/s/ok8to0kla) + +### 查询指定LogStore + +通过以下代码,获取指定日志集的详情信息。 + +```go +res, err := blsClient.DescribeLogStore("demo") +if err != nil { + fmt.Println("Get logStore failed: ", err) +} else { + fmt.Println("LogStore info: ", res) +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[DescribeLogStore](https://cloud.baidu.com/doc/BLS/s/Bk8to0jp3) + +### 获取LogStore列表 + +通过以下代码,获取当前用户的日志集列表。 + +```go +// 可选参数列表 +args := &api.QueryConditions{ + NamePattern: "bls-log", + Order: "asc", + OrderBy: "creationDateTime", + PageNo: 1, + PageSize: 10} +res, err := blsClient.ListLogStore(args) +if err != nil { + fmt.Println("Get logStore list failed: ", err) +} else { + fmt.Println("List logStore success: ", res) +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[ListLogStore](https://cloud.baidu.com/doc/BLS/s/Hk8to0kda) + +### 删除LogStore + +通过以下代码,删除指定的日志集,并且会永久删除与其关联的所有已存储日志记录。 + +```go +err := blsClient.DeleteLogStore("demo") +if err != nil { + fmt.Println("Delete logStore failed: ", err) +} else { + fmt.Println("Delete logStore success.") +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[DeleteLogStore](https://cloud.baidu.com/doc/BLS/s/ak8to0jx8) + +## LogStream操作 + +LogStream会随着LogStore的创建自动创建,目前暂不支持对LogStream的删除操作。 + +### 获取LogStream列表 + +通过以下代码,获取指定日志集的日志流列表。 + +```go +// 可选参数列表 +args := &api.QueryConditions{ + NamePattern: "bls-log", + Order: "desc", + OrderBy: "creationDateTime", + PageNo: 1, + PageSize: 20, +} +res, err := blsClient.ListLogStore(args) +if err != nil { + fmt.Println("Get logStream list failed: ", err) +} else { + fmt.Println("List logStore success: ", res) +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[ListLogStream](https://cloud.baidu.com/doc/BLS/s/dk8to0lhy) + +## LogRecord操作 + +### 推送LogRecord + +支持批量推送日志记录到 BLS 平台,日志记录的格式可以是 TEXT,也可以是 JSON 格式。如果是 TEXT,则不对日志进行解析;如果是 JSON 格式,可以自动发现 JSON 字段(仅支持首层字段发现,暂不支持嵌套类型字段的自动发现)。 + +如果既想上传日志原文,又想上传解析出的具体字段,可以使用 JSON 格式进行上传,并在 JSON 中包含日志原文(使用 @raw 作为key,日志原文作为 value)。 BLS 解析到 @raw 的时候,会将其内容作为日志原文处理。 + +通过以下代码,可以批量推送JSON日志记录到指定日志集的指定日志流中。 + +```go +// 推送JSON格式日志记录 +jsonRecords := []api.LogRecord{ + { + Message: "{\"body_bytes_sent\":184,\"bytes_sent\":398,\"client_ip\":\"120.193.204.39\"}", + Timestamp: time.Now().UnixNano() / 1e6, + Sequence: 1, + }, + { + Message: "{\"body_bytes_sent\":14,\"bytes_sent\":408,\"client_ip\":\"120.193.222.39\"}", + Timestamp: time.Now().UnixNano() / 1e6, + Sequence: 2, + }, +} +// 指定logRecord类型为JSON,并将日志记录推送到日志集demo中的日志流json-logStream中 +// 若没有该日志流,则自动创建 +err := blsClient.PushLogRecord("demo", "json-logStream", "JSON", jsonRecords) +if err != nil { + fmt.Println("Push logRecords failed: ", err) +} else { + fmt.Println("Push logRecords success") +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[PushLogRecord](https://cloud.baidu.com/doc/BLS/s/dk8to0ktn) + +### 查看指定LogRecord + +通过以下代码,查看指定日志流中的日志记录,您可以获取最近的日志记录或使用时间范围进行过滤。 + +```go +args := &api.PullLogRecordArgs{ + // 必须指定日志流名称 + LogStreamName: "json-logStream", + // 可选参数 + StartDateTime: "2021-01-01T10:11:44Z", + EndDateTime: "2021-12-10T16:11:44Z", + Limit: 500, // 返回最大条目数 + Marker: "", // 指定查看的位置标记 +} +res, err := blsClient.PullLogRecord("demo", args) +if err != nil { + fmt.Println("Pull logRecord failed: ", err) +} else { + fmt.Println("LogRecords result: ", res) +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[PullLogRecord](https://cloud.baidu.com/doc/BLS/s/Ek8to0l1o) + +### 查询指定LogRecord + +用户通过提交 Query 检索或分析指定日志集中的数据,每次只能查询一个日志集的内容。 + +Query 语句格式支持 检索 + SQL分析,通过竖线分隔,即在检索的结果集上执行 SQL,形如:`Search | SQL`。 + +例如 `method:GET and status >= 400 | select host, count(*) group by host` + +注: + +- 如果只需要检索原日志,不需要执行 SQL 分析,可以省略竖线和 SQL 语句。 +- 如果不需要检索,只需要 SQL 分析,那么检索语句可以写为 `*`,表示匹配所有记录。即 `* | SQL`。如果查询的日志集没有开启索引,也可以省略检索语句和竖线,只写 SQL 语句。 + +查询相关限制如下: + +- 每个账户支持最多的查询并发数是 15 个 +- 限制返回的结果集大小不超过 1MB 或 1000 条记录。 + +检索语法请参考 [检索语法](https://cloud.baidu.com/doc/BLS/s/Okbta3asp) + +SQL 语句中可以不包括 from 子句,语法详情可以参考 [SQL 语法](https://cloud.baidu.com/doc/BLS/s/xk5cc9piu) + +通过以下代码,您可以在指定日志集中查询满足条件的日志记录。 + +```go +args := &api.QueryLogRecordArgs{ + // 必选参数 + Query: "select count(*)", // 查询SQL + StartDateTime: "2021-01-01T10:11:44Z", + EndDateTime: "2021-12-10T16:11:44Z", + // 可选参数 + LogStreamName: "json-logStream", // 不指定则在日志集所有日志流中查询 + Limit: 100, +} +res, err := blsClient.QueryLogRecord("demo", args) +if err != nil { + fmt.Println("Query logRecord failed: ", err) +} else { + fmt.Println("LogRecords result: ", res) +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[QueryLogRecord](https://cloud.baidu.com/doc/BLS/s/hk8to0l9o) + +## FastQuery操作 + +### 创建FastQuery + +创建快速查询的实例名称必须遵循以下准则: + +- 每个账户每个区域快速查询名称不能相同 +- 快速查询名称长度不能超过128个字符 +- 快速查询名称包含的字符仅限于:`a-z, A-Z, 0-9, '_', '-', '.'` + +通过以下代码,可以创建一个快速查询。 + +```go +args := &api.CreateFastQueryBody{ + FastQueryName: "macro", + Query: "select count(*)", + LogStoreName: "demo", + // 可选参数 + Description: "calculate record number", + LogStreamName: "json-logStream", +} +err := blsClient.CreateFastQuery(args) +if err != nil { + fmt.Println("Create fastQuery failed: ", err) +} else { + fmt.Println('Create fastQuery success.') +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[CreateFastQuery](https://cloud.baidu.com/doc/BLS/s/kk8to0m6g) + +### 获取指定FastQuery + +通过以下代码,获取指定名称的快速查询的详细信息。 + +```go +res, err := blsClient.DescribeFastQuery("macro") +if err != nil { + fmt.Println("Get fastQuery failed: ", err) +} else { + fmt.Println("Fastquery info: ", res) +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[DescribeFastQuery](https://cloud.baidu.com/doc/BLS/s/Zk8to0mmn) + +### 更新指定FastQuery + +通过以下代码,更新指定名称的快速查询实例信息。 + +```go +args := &api.UpdateFastQueryBody{ + LogStoreName: "demo", + // 可选参数 + Query: "select * limit 3", + Description: "Top 3", + LogStreamName: "", +} +err := blsClient.UpdateFastQuery("macro", args) +if err != nil { + fmt.Println("Update fastQuery failed: ", err) +} else { + fmt.Println("Update fastQuery success.") +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[UpdateFastQuery](https://cloud.baidu.com/doc/BLS/s/Ik8to0mei) + +### 获取FastQuery列表 + +通过以下代码,获取当前用户保存的快速查询列表。 + +```go +// 可选参数列表 +args := &api.QueryConditions{ + NamePattern: "m", + Order: "desc", + OrderBy: "", + PageNo: 1, + PageSize: 20, +} +res, err := blsClient.ListFastQuery(args) +if err != nil { + fmt.Println("List fastQuery failed: ", err) +} else { + fmt.Println("FastQuery list: ", res) +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[ListFastQuery](https://cloud.baidu.com/doc/BLS/s/0k8to0lyf) + +### 删除指定FastQuery + +通过以下代码,删除指定名称的快速查询示例。 + +```go +err := blsClient.DeleteFastQuery("macro") +if err != nil { + fmt.Println("Delete fastQuery failed: ", err) +} else { + fmt.Println("Delete fastQuery success.") +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[DeleteFastQuery](https://cloud.baidu.com/doc/BLS/s/Uk8to0lqd) + +## Index操作 + +### 创建Index + +通过以下代码,为指定的日志集创建索引。 + +```go +indexMappings := map[string]api.LogField{ + "age": { + Type: "long", + }, + "salary": { + Type: "text", + }, + "name": { + Type: "text", + }, +} +err := blsClient.CreateIndex("demo", true, indexMappings) // true表示索引开启状态 +if err != nil { + fmt.Println("Create index failed: ", err) +} else { + fmt.Println("Create index success.") +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[CreateIndex](https://cloud.baidu.com/doc/BLS/s/dkbt4q6ps) + +### 更新指定Index + +通过以下代码,更新指定日志集的索引结构。 + +```go +indexMappings := map[string]api.LogField{ + "age": { + Type: "long", + }, + "wage": { + Type: "float", + }, + "name": { + Type: "text", + }, +} +err := blsClient.UdpateIndex("demo", true, indexMappings) +if err != nil { + fmt.Println("Update index failed: ", err) +} else { + fmt.Println("Update index success.") +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[UpdateIndex](https://cloud.baidu.com/doc/BLS/s/bkbt4w0fe) + +### 获取指定Index + +通过以下代码,获取指定日志集的索引结构。 + +```go +res, err := blsClient.DescribeIndex("demo") +if err != nil { + fmt.Println("Get index failed: ", err) +} else { + fmt.Println("Index info: ", res) +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[DescribeIndex](https://cloud.baidu.com/doc/BLS/s/1kbt4yem2) + +### 删除指定Index + +通过以下代码,删除指定日志集的索引,该操作会将索引数据清空。 + +```go +res, err := blsClient.DeleteIndex("demo") +if err != nil { + fmt.Println("Delete index failed: ", err) +} else { + fmt.Println("Delete index success.") +} +``` + +> **提示:** +> +> - 详细的参数配置及限制条件,可以参考BLS API 文档[DeleteIndex](https://cloud.baidu.com/doc/BLS/s/bkbt56uvu) + diff --git a/services/bbc/client.go b/services/bbc/client.go index 7c5b0940..181ce7eb 100644 --- a/services/bbc/client.go +++ b/services/bbc/client.go @@ -257,6 +257,17 @@ func (c *Client) RebuildInstance(instanceId string, isPreserveData bool, args *R return RebuildInstance(c, instanceId, body) } +// GetInstanceVNC - get an instance's VNC url +// +// PARAMS: +// - instanceId: the specific instance ID +// RETURNS: +// - *api.GetInstanceVNCResult: the result of get instance's VNC url +// - error: nil if success otherwise the specific error +func (c *Client) GetInstanceVNC(instanceId string) (*GetInstanceVNCResult, error) { + return GetInstanceVNC(c, instanceId) +} + // RebuildBatchInstance - batch rebuild instances // // PARAMS: diff --git a/services/bbc/client_test.go b/services/bbc/client_test.go index 09e99465..879575f7 100644 --- a/services/bbc/client_test.go +++ b/services/bbc/client_test.go @@ -46,6 +46,7 @@ func init() { conf := filepath.Join(f, "config.json") fp, err := os.Open(conf) if err != nil { + fmt.Println("config json file of ak/sk not given: ", conf) log.Fatal("config json file of ak/sk not given:", conf) os.Exit(1) } @@ -480,7 +481,7 @@ func TestGetInstanceEni(t *testing.T) { } func TestGetInstanceStock(t *testing.T) { - args := &CreateInstanceStockArgs { + args := &CreateInstanceStockArgs{ FlavorId: "BBC-G4-PDDAS", ZoneName: "cn-su-a", } @@ -698,3 +699,9 @@ func TestRecoveryInstances(t *testing.T) { fmt.Println("recovery instance success") } } + +func TestGetInstanceVnc(t *testing.T) { + res, err := BBC_CLIENT.GetInstanceVNC(BBC_TestBbcId) + ExpectEqual(t.Errorf, err, nil) + fmt.Println("get instance vnc success: ", res.VNCUrl) +} diff --git a/services/bbc/instance.go b/services/bbc/instance.go index 8a78eb63..7dbb6182 100644 --- a/services/bbc/instance.go +++ b/services/bbc/instance.go @@ -194,6 +194,7 @@ func GetInstanceDetail(cli bce.Client, instanceId string) (*InstanceModel, error req.SetUri(getInstanceUriWithId(instanceId)) req.SetMethod(http.GET) req.SetParam("isDeploySet", "false") + // Send request and get response resp := &bce.BceResponse{} if err := cli.SendRequest(req, resp); err != nil { @@ -820,6 +821,36 @@ func GetInstanceEni(cli bce.Client, instanceId string) (*GetInstanceEniResult, e return jsonBody, nil } +// GetInstanceVNC - get VNC address of the specified instance +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - instanceId: id of the instance +// RETURNS: +// - *GetInstanceVNCResult: result of the VNC address of the instance +// - error: nil if success otherwise the specific error +func GetInstanceVNC(cli bce.Client, instanceId string) (*GetInstanceVNCResult, error) { + // Build the request + req := &bce.BceRequest{} + req.SetUri(getInstanceVNCUri(instanceId)) + req.SetMethod(http.GET) + + // Send request and get response + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + + jsonBody := &GetInstanceVNCResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + // BatchCreateAutoRenewRules - Batch Create AutoRenew Rules // // PARAMS: @@ -874,6 +905,10 @@ func BatchDeleteAutoRenewRules(cli bce.Client, reqBody *bce.Body) error { return nil } +func getInstanceVNCUri(instanceId string) string { + return URI_PREFIX_V1 + REQUEST_INSTANCE_URI + "/" + instanceId + "/vnc" +} + func getInstanceEniUri(instanceId string) string { return URI_PREFIX_V1 + REQUEST_INSTANCE_PORT_URI + "/" + instanceId } diff --git a/services/bbc/model.go b/services/bbc/model.go index 187cbec0..fb1c2575 100644 --- a/services/bbc/model.go +++ b/services/bbc/model.go @@ -414,6 +414,10 @@ type GetOperationLogResult struct { OperationLogs []OperationLogModel `json:"operationLogs"` } +type GetInstanceVNCResult struct { + VNCUrl string `json:"vncUrl"` +} + type OperationLogModel struct { OperationStatus bool `json:"operationStatus"` OperationTime string `json:"operationTime"` diff --git a/services/bbc/operationLog.go b/services/bbc/operationLog.go index 81afb834..0163baa5 100644 --- a/services/bbc/operationLog.go +++ b/services/bbc/operationLog.go @@ -18,6 +18,7 @@ package bbc import ( + "fmt" "github.com/baidubce/bce-sdk-go/bce" "github.com/baidubce/bce-sdk-go/http" ) @@ -41,7 +42,7 @@ func GetOperationLog(cli bce.Client, args *GetOperationLogArgs) (*GetOperationLo } if args.MaxKeys != 0 { - req.SetParam("maxKeys", string(args.MaxKeys)) + req.SetParam("maxKeys", fmt.Sprintf("%d", args.MaxKeys)) } if args.StartTime != "" { diff --git a/services/bbc/securityGroup.go b/services/bbc/securityGroup.go index f85cfe6f..7753cfae 100644 --- a/services/bbc/securityGroup.go +++ b/services/bbc/securityGroup.go @@ -36,8 +36,6 @@ func BindSecurityGroups(cli bce.Client, reqBody *bce.Body) error { return nil } - - // UnBindSecurityGroups - UnBind Security Groups // // PARAMS: @@ -66,10 +64,10 @@ func UnBindSecurityGroups(cli bce.Client, reqBody *bce.Body) error { return nil } -func getBindSecurityGroupsUri() string { +func getBindSecurityGroupsUri() string { return URI_PREFIX_V1 + REQUEST_INSTANCE_URI + SECURITY_GROUP_URI } -func getUnBindSecurityGroupsUri() string { +func getUnBindSecurityGroupsUri() string { return URI_PREFIX_V1 + REQUEST_INSTANCE_URI + SECURITY_GROUP_URI -} \ No newline at end of file +} diff --git a/services/bcc/api/instance.go b/services/bcc/api/instance.go index bb07547e..0ec5b7ed 100644 --- a/services/bcc/api/instance.go +++ b/services/bcc/api/instance.go @@ -1250,6 +1250,35 @@ func GetInstanceResizeStock(cli bce.Client, args *ResizeInstanceStockArgs) (*Ins return jsonBody, nil } +// GetAllStocks - get the bcc and bbc's stock +// +// PARAMS: +// - cli: the client agent which can perform sending request +// RETURNS: +// - *GetAllStocksResult: the result of the bcc and bbc's stock +// - error: nil if success otherwise the specific error +func GetAllStocks(cli bce.Client) (*GetAllStocksResult, error) { + // Build the request + req := &bce.BceRequest{} + req.SetUri(getAllStocks()) + req.SetMethod(http.GET) + + // Send request and get response + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + + jsonBody := &GetAllStocksResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + func GetInstanceCreateStock(cli bce.Client, args *CreateInstanceStockArgs) (*InstanceStockResult, error) { // Build the request req := &bce.BceRequest{} diff --git a/services/bcc/api/model.go b/services/bcc/api/model.go index 438dec15..e81ce89d 100644 --- a/services/bcc/api/model.go +++ b/services/bcc/api/model.go @@ -133,6 +133,28 @@ type InstanceModel struct { NicInfo NicInfo `json:"nicInfo"` } +type GetAllStocksResult struct { + BccStocks []BccStock `json:"bccStocks"` + BbcStocks []BbcStock `json:"bbcStocks"` +} + +type BccStock struct { + Spec string `json:"spec"` + SpecId string `json:"specId"` + InventoryQuantity int `json:"inventoryQuantity"` + UpdatedTime string `json:"updatedTime"` + CollectionTime string `json:"collectionTime"` + ZoneName string `json:"logicalZone"` +} + +type BbcStock struct { + FlavorId string `json:"flavorId"` + InventoryQuantity int `json:"inventoryQuantity"` + UpdatedTime string `json:"updatedTime"` + CollectionTime string `json:"collectionTime"` + ZoneName string `json:"logicalZone"` +} + type NicInfo struct { Status string `json:"status"` MacAddress string `json:"macAddress"` diff --git a/services/bcc/api/util.go b/services/bcc/api/util.go index 89c48e24..0e94e3e7 100644 --- a/services/bcc/api/util.go +++ b/services/bcc/api/util.go @@ -69,6 +69,7 @@ const ( REQUEST_CANCEL_BIDORDER_URI = "/cancelBidOrder" REQUEST_BATCH_CREATE_AUTORENEW_RULES_URI = "/batchCreateAutoRenewRules" REQUEST_BATCH_Delete_AUTORENEW_RULES_URI = "/batchDeleteAutoRenewRules" + REQUEST_GET_ALL_STOCKS = "/getAllStocks" ) func getInstanceUri() string { @@ -227,6 +228,10 @@ func getKeypairWithId(id string) string { return URI_PREFIXV2 + REQUEST_KEYPAIR_URI + "/" + id } +func getAllStocks() string { + return URI_PREFIXV2 + REQUEST_INSTANCE_URI + REQUEST_GET_ALL_STOCKS +} + func getCreateInstanceStock() string { return URI_PREFIXV2 + REQUEST_INSTANCE_URI + "/stock/createInstance" } diff --git a/services/bcc/client.go b/services/bcc/client.go index 038cce98..d5441119 100644 --- a/services/bcc/client.go +++ b/services/bcc/client.go @@ -1420,6 +1420,15 @@ func (c *Client) UpdateKeypairDescription(args *api.KeypairUpdateDescArgs) error return api.UpdateKeypairDescription(c, args) } +// GetAllStocks - get the bcc and bbc's stock +// +// RETURNS: +// - *GetAllStocksResult: the result of the bcc and bbc's stock +// - error: nil if success otherwise the specific error +func (c *Client) GetAllStocks() (*api.GetAllStocksResult, error) { + return api.GetAllStocks(c) +} + func (c *Client) GetInstanceCreateStock(args *api.CreateInstanceStockArgs) (*api.InstanceStockResult, error) { return api.GetInstanceCreateStock(c, args) } diff --git a/services/bcc/client_test.go b/services/bcc/client_test.go index 514dedc3..e4fe9f53 100644 --- a/services/bcc/client_test.go +++ b/services/bcc/client_test.go @@ -1062,3 +1062,11 @@ func TestRecoveryInstance(t *testing.T) { fmt.Println("recovery instance success") } } + +func TestGetAllStocks(t *testing.T) { + if res, err := BCC_CLIENT.GetAllStocks(); err != nil { + fmt.Println("get all stocks failed: ", err) + } else { + fmt.Println("get all stocks success, result: ", res) + } +} diff --git a/services/bls/api/fastquery.go b/services/bls/api/fastquery.go new file mode 100644 index 00000000..7c2c6111 --- /dev/null +++ b/services/bls/api/fastquery.go @@ -0,0 +1,163 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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. + */ + +// fastquery.go - the fastQuery APIs definition supported by the BLS service + +package api + +import ( + "strconv" + + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" +) + +// CreateFastQuery - create a fastQuery +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - body: the fastQuery body +// RETURNS: +// - error: nil if success otherwise the specific error +func CreateFastQuery(cli bce.Client, body *bce.Body) error { + req := &bce.BceRequest{} + req.SetUri(FASTQUERY_PREFIX) + req.SetMethod(http.POST) + req.SetBody(body) + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// DescribeFastQuery - get specific fastQuery info +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - fastQueryName: fastQuery name to get +// RETURNS: +// - *FastQuery: target fastQuery info +// - error: nil if success otherwise the specific error +func DescribeFastQuery(cli bce.Client, fastQueryName string) (*FastQuery, error) { + req := &bce.BceRequest{} + req.SetUri(getFastQueryUri(fastQueryName)) + req.SetMethod(http.GET) + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &FastQuery{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// UpdateFastQuery - update specific fastQuery info +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - body: update fastQuery body +// - fastQueryName: fastQuery to update +// RETURNS: +// - error: nil if success otherwise the specific error +func UpdateFastQuery(cli bce.Client, body *bce.Body, fastQueryName string) error { + req := &bce.BceRequest{} + req.SetUri(getFastQueryUri(fastQueryName)) + req.SetMethod(http.PUT) + req.SetBody(body) + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// DeleteFastQuery - delete specific fastQuery +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - fastQueryName: fastQuery name to delete +// RETURNS: +// - error: nil if success otherwise the specific error +func DeleteFastQuery(cli bce.Client, fastQueryName string) error { + req := &bce.BceRequest{} + req.SetUri(getFastQueryUri(fastQueryName)) + req.SetMethod(http.DELETE) + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// ListFastQuery - get all fastQuery info +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - args: query args to get pattern-match fastQuery +// RETURNS: +// - *ListFastQueryResult: pattern-match fastQuery result +// - error: nil if success otherwise the specific error +func ListFastQuery(cli bce.Client, args *QueryConditions) (*ListFastQueryResult, error) { + req := &bce.BceRequest{} + req.SetUri(FASTQUERY_PREFIX) + req.SetMethod(http.GET) + // Set optional args + if args != nil { + if args.NamePattern != "" { + req.SetParam("namePattern", args.NamePattern) + } + if args.Order != "" { + req.SetParam("order", args.Order) + } + if args.OrderBy != "" { + req.SetParam("orderBy", args.OrderBy) + } + if args.PageNo > 0 { + req.SetParam("pageNo", strconv.Itoa(args.PageNo)) + } + if args.PageSize > 0 { + req.SetParam("pageSize", strconv.Itoa(args.PageSize)) + } + } + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &ListFastQueryResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} diff --git a/services/bls/api/index.go b/services/bls/api/index.go new file mode 100644 index 00000000..e05d8ec8 --- /dev/null +++ b/services/bls/api/index.go @@ -0,0 +1,118 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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. + */ + +// index.go - the Index APIs definition supported by the BLS service + +package api + +import ( + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" +) + +// CreateIndex - create index for logStore +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - logStoreName: logStore needs to be indexed +// - body: index mappings body +// RETURNS: +// - error: nil if success otherwise the specific error +func CreateIndex(cli bce.Client, logStoreName string, body *bce.Body) error { + req := &bce.BceRequest{} + req.SetUri(getIndexUri(logStoreName)) + req.SetMethod(http.POST) + req.SetBody(body) + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// UpdateIndex - update index info +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - logStoreName: logStore needs to be updated +// - body: index mappings body +// RETURNS: +// - error: nil if success otherwise the specific error +func UpdateIndex(cli bce.Client, logStoreName string, body *bce.Body) error { + req := &bce.BceRequest{} + req.SetUri(getIndexUri(logStoreName)) + req.SetMethod(http.PUT) + req.SetBody(body) + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// DeleteIndex - delete index for logStore +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - logStoreName: logStore to be deleted +// RETURNS: +// - error: nil if success otherwise the specific error +func DeleteIndex(cli bce.Client, logStoreName string) error { + req := &bce.BceRequest{} + req.SetUri(getIndexUri(logStoreName)) + req.SetMethod(http.DELETE) + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// DescribeIndex - get specific logStore index info +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - logStoreName: logStore needs to be get +// RETURNS: +// - *IndexFields: index mappings info +// - error: nil if success otherwise the specific error +func DescribeIndex(cli bce.Client, logStoreName string) (*IndexFields, error) { + req := &bce.BceRequest{} + req.SetUri(getIndexUri(logStoreName)) + req.SetMethod(http.GET) + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &IndexFields{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} diff --git a/services/bls/api/logrecord.go b/services/bls/api/logrecord.go new file mode 100644 index 00000000..091e2f77 --- /dev/null +++ b/services/bls/api/logrecord.go @@ -0,0 +1,128 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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. + */ + +// logrecord.go - the logRecord APIs definition supported by the BLS service + +package api + +import ( + "strconv" + + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" +) + +// PushLogRecord - push logRecords into logStore +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - logStore: target logStore to store logRecords +// - body: logRecord body +// RETURNS: +// - error: nil if success otherwise the specific error +func PushLogRecord(cli bce.Client, logStore string, body *bce.Body) error { + req := &bce.BceRequest{} + req.SetUri(getLogRecordUri(logStore)) + req.SetMethod(http.POST) + req.SetBody(body) + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// PullLogRecord - get logRecords from logStore +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - logStore: target logStore to get logRecords +// - args: pull logRecords limitation args +// RETURNS: +// - *PullLogRecordResult: pull logRecord result set +// - error: nil if success otherwise the specific error +func PullLogRecord(cli bce.Client, logStore string, args *PullLogRecordArgs) (*PullLogRecordResult, error) { + req := &bce.BceRequest{} + req.SetUri(getLogRecordUri(logStore)) + req.SetMethod(http.GET) + if args != nil { + if args.LogStreamName != "" { + req.SetParam("logStreamName", args.LogStreamName) + } + if len(args.StartDateTime) != 0 { + req.SetParam("startDateTime", string(args.StartDateTime)) + } + if len(args.EndDateTime) != 0 { + req.SetParam("endDateTime", string(args.EndDateTime)) + } + if args.Limit > 0 && args.Limit <= 1000 { + req.SetParam("limit", strconv.Itoa(args.Limit)) + } + if len(args.Marker) != 0 { + req.SetParam("marker", args.Marker) + } + } + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &PullLogRecordResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// QueryLogRecord - retrieve logRecords from logStore +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - logStore: target logStore to retrieve logRecords +// - args: query logRecords conditions args +// RETURNS: +// - *QueryLogResult: query logRecord result set +// - error: nil if success otherwise the specific error +func QueryLogRecord(cli bce.Client, logStore string, args *QueryLogRecordArgs) (*QueryLogResult, error) { + req := &bce.BceRequest{} + req.SetUri(getLogRecordUri(logStore)) + req.SetMethod(http.GET) + if args != nil { + req.SetParam("logStreamName", args.LogStreamName) + req.SetParam("query", args.Query) + req.SetParam("startDateTime", string(args.StartDateTime)) + req.SetParam("endDateTime", string(args.EndDateTime)) + if args.Limit > 0 { + req.SetParam("limit", strconv.Itoa(args.Limit)) + } + } + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &QueryLogResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} diff --git a/services/bls/api/logstore.go b/services/bls/api/logstore.go new file mode 100644 index 00000000..1bce58cd --- /dev/null +++ b/services/bls/api/logstore.go @@ -0,0 +1,165 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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. + */ + +// logstore.go - the logStore APIs definition supported by the BLS service + +package api + +import ( + "strconv" + + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" +) + +// CreateLogStore - create logStore +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - body: logStore parameters body +// RETURNS: +// - error: nil if success otherwise the specific error +func CreateLogStore(cli bce.Client, body *bce.Body) error { + req := &bce.BceRequest{} + req.SetUri(DEFAULT_PREFIX) + req.SetMethod(http.POST) + if body != nil { + req.SetBody(body) + } + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// UpdateLogStore - update logStore retention +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - logStore: logStore to update +// - body: logStore parameters body +// RETURNS: +// - error: nil if success otherwise the specific error +func UpdateLogStore(cli bce.Client, logStore string, body *bce.Body) error { + req := &bce.BceRequest{} + req.SetUri(getLogStoreUri(logStore)) + req.SetMethod(http.PUT) + req.SetBody(body) + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// DescribeLogStore - get logStore info +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - logStore: logStore to get +// RETURNS: +// - *LogStore: logStore info +// - error: nil if success otherwise the specific error +func DescribeLogStore(cli bce.Client, logStore string) (*LogStore, error) { + req := &bce.BceRequest{} + req.SetUri(getLogStoreUri(logStore)) + req.SetMethod(http.GET) + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &LogStore{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} + +// DeleteLogStore - delete logStore +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - logStore: logStore to delete +// RETURNS: +// - error: nil if success otherwise the specific error +func DeleteLogStore(cli bce.Client, logStore string) error { + req := &bce.BceRequest{} + req.SetUri(getLogStoreUri(logStore)) + req.SetMethod(http.DELETE) + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +// ListLogStore - get all pattern-match logStore info +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - args: conditions logStore should match +// RETURNS: +// - *ListLogStoreResult: logStore result set +// - error: nil if success otherwise the specific error +func ListLogStore(cli bce.Client, args *QueryConditions) (*ListLogStoreResult, error) { + req := &bce.BceRequest{} + req.SetUri(DEFAULT_PREFIX) + req.SetMethod(http.GET) + // Set optional args + if args != nil { + if args.NamePattern != "" { + req.SetParam("namePattern", args.NamePattern) + } + if args.Order != "" { + req.SetParam("order", args.Order) + } + if args.OrderBy != "" { + req.SetParam("orderBy", args.OrderBy) + } + if args.PageNo > 0 { + req.SetParam("pageNo", strconv.Itoa(args.PageNo)) + } + if args.PageSize > 0 { + req.SetParam("pageSize", strconv.Itoa(args.PageSize)) + } + } + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &ListLogStoreResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} diff --git a/services/bls/api/logstream.go b/services/bls/api/logstream.go new file mode 100644 index 00000000..7afce6b6 --- /dev/null +++ b/services/bls/api/logstream.go @@ -0,0 +1,69 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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. + */ + +// logstream.go - the logStream APIs definition supported by the BLS service + +package api + +import ( + "strconv" + + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" +) + +// ListLogStream - get all pattern-match logStream in logStore +// +// PARAMS: +// - cli: the client agent which can perform sending request +// - logStore: logStore to parse +// - args: conditions logStream should match +// RETURNS: +// - *ListLogStreamResult: pattern-match logStream result set +// - error: nil if success otherwise the specific error +func ListLogStream(cli bce.Client, logStore string, args *QueryConditions) (*ListLogStreamResult, error) { + req := &bce.BceRequest{} + req.SetUri(getLogStreamName(logStore)) + req.SetMethod(http.GET) + // Set optional args + if args != nil { + if args.NamePattern != "" { + req.SetParam("namePattern", args.NamePattern) + } + if args.Order != "" { + req.SetParam("order", args.Order) + } + if args.OrderBy != "" { + req.SetParam("orderBy", args.OrderBy) + } + if args.PageNo > 0 { + req.SetParam("pageNo", strconv.Itoa(args.PageNo)) + } + if args.PageSize > 0 { + req.SetParam("pageSize", strconv.Itoa(args.PageSize)) + } + } + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + result := &ListLogStreamResult{} + if err := resp.ParseJsonBody(result); err != nil { + return nil, err + } + return result, nil +} diff --git a/services/bls/api/model.go b/services/bls/api/model.go new file mode 100644 index 00000000..e7d4bae2 --- /dev/null +++ b/services/bls/api/model.go @@ -0,0 +1,167 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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. + */ + +// model.go - definitions of the request arguments and results data structure model + +package api + +type DateTime string + +type LogRecord struct { + Message string `json:"message"` + Timestamp int64 `json:"timestamp"` + Sequence int `json:"sequence"` +} + +type LogStream struct { + CreationDateTime DateTime `json:"creationDateTime"` + LogStreamName string `json:"logStreamName"` +} + +type LogStore struct { + CreationDateTime DateTime `json:"creationDateTime"` + LastModifiedTime DateTime `json:"lastModifiedTime"` + LogStoreName string `json:"logStoreName"` + Retention int `json:"retention"` +} + +type QueryConditions struct { + NamePattern string `json:"namePattern"` + Order string `json:"order"` + OrderBy string `json:"orderBy"` + PageNo int `json:"pageNo"` + PageSize int `json:"pageSize"` +} + +type PushLogRecordBody struct { + LogStreamName string `json:"logStreamName"` + Type string `json:"type"` + LogRecords []LogRecord `json:"logRecords"` +} + +type QueryLogRecordArgs struct { + LogStreamName string `json:"logStreamName"` + Query string `json:"query"` + StartDateTime DateTime `json:"startDatetime"` + EndDateTime DateTime `json:"endDateTime"` + Limit int `json:"limit"` +} + +type PullLogRecordArgs struct { + LogStreamName string `json:"logStreamName"` + StartDateTime DateTime `json:"startDatetime"` + EndDateTime DateTime `json:"endDateTime"` + Limit int `json:"limit"` + Marker string `json:"marker"` +} + +type PullLogRecordResult struct { + Result []LogRecord `json:"result"` + IsTruncated bool `json:"isTruncated"` + Marker string `json:"marker"` + NextMarker string `json:"nextMarker"` +} + +type Histogram struct { + Interval int `json:"interval"` + StartDateTime DateTime `json:"startDatetime"` + EndDateTime DateTime `json:"endDateTime"` + Counts []int `json:"counts"` +} + +type Statistics struct { + ExecutionTimeInMs int `json:"executionTimeInMs"` + ScanCount int `json:"scanCount"` + Histogram *Histogram `json:"histogram"` +} + +type DataSetScanInfo struct { + IsTruncated bool `json:"isTruncated"` + TruncatedReason string `json:"truncatedReason"` + Statistics *Statistics `json:"statistics"` +} + +type ResultSet struct { + Columns []string `json:"columns"` + Rows [][]interface{} `json:"rows"` + IsTruncated bool `json:"isTruncated"` + TruncatedReason string `json:"truncatedReason"` +} + +type QueryLogResult struct { + ResultSet *ResultSet `json:"resultSet"` + DataSetScanInfo *DataSetScanInfo `json:"dataScanInfo"` +} + +type ListLogStreamResult struct { + Order string `json:"order"` + OrderBy string `json:"orderBy"` + PageNumebr int `json:"pageNo"` + PageSize int `json:"pageSize"` + TotalCount int `json:"totalCount"` + Result []LogStream `json:"result"` +} + +type ListLogStoreResult struct { + Order string `json:"order"` + OrderBy string `json:"orderBy"` + PageNo int `json:"pageNo"` + PageSize int `json:"pageSize"` + TotalCount int `json:"totalCount"` + Result []LogStore `json:"result"` +} + +type FastQuery struct { + CreationDateTime DateTime `json:"creationDateTime"` + LastModifiedTime DateTime `json:"lastModifiedTime"` + FastQueryName string `json:"fastQueryName"` + Description string `json:"description"` + Query string `json:"query"` + LogStoreName string `json:"logStoreName"` + LogStreamName string `json:"logStreamName"` +} + +type CreateFastQueryBody struct { + FastQueryName string `json:"fastQueryName"` + Query string `json:"query"` + Description string `json:"description"` + LogStoreName string `json:"logStoreName"` + LogStreamName string `json:"logStreamName"` +} + +type UpdateFastQueryBody struct { + Query string `json:"query"` + Description string `json:"description"` + LogStoreName string `json:"logStoreName"` + LogStreamName string `json:"logStreamName"` +} + +type ListFastQueryResult struct { + Order string `json:"order"` + OrderBy string `json:"orderBy"` + PageNo int `json:"pageNo"` + PageSize int `json:"pageSize"` + TotalCount int `json:"totalCount"` + Result []FastQuery `json:"result"` +} + +type LogField struct { + Type string `json:"type"` + Fields map[string]LogField `json:"fields,omitempty"` +} + +type IndexFields struct { + FullText bool `json:"fulltext"` + Fields map[string]LogField `json:"fields"` +} diff --git a/services/bls/api/utils.go b/services/bls/api/utils.go new file mode 100644 index 00000000..5f0f0516 --- /dev/null +++ b/services/bls/api/utils.go @@ -0,0 +1,46 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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. + */ + +// util.go - define the utilities for api package of BLS service + +package api + +import ( + "github.com/baidubce/bce-sdk-go/bce" +) + +const ( + DEFAULT_PREFIX = bce.URI_PREFIX + "v1" + bce.URI_PREFIX + "logstore" + FASTQUERY_PREFIX = bce.URI_PREFIX + "v1" + bce.URI_PREFIX + "fastquery" +) + +func getLogStoreUri(logStoreName string) string { + return DEFAULT_PREFIX + bce.URI_PREFIX + logStoreName +} + +func getLogStreamName(logStoreName string) string { + return getLogStoreUri(logStoreName) + bce.URI_PREFIX + "logstream" +} + +func getLogRecordUri(logStoreName string) string { + return getLogStoreUri(logStoreName) + bce.URI_PREFIX + "logrecord" +} + +func getFastQueryUri(fastQuery string) string { + return FASTQUERY_PREFIX + bce.URI_PREFIX + fastQuery +} + +func getIndexUri(logStoreName string) string { + return getLogStoreUri(logStoreName) + bce.URI_PREFIX + "index" +} \ No newline at end of file diff --git a/services/bls/client.go b/services/bls/client.go new file mode 100644 index 00000000..922187d0 --- /dev/null +++ b/services/bls/client.go @@ -0,0 +1,207 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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. + */ + +// client.go - define the client for BLS service + +// Package bls defines the BLS services of BCE. The supported APIs are all defined in sub-package +// model with five types: 5 LogStore APIs, 1 LogStream API, 3 logRecord APIs, 5 FastQuery APIs +// and 3 index APIs. + +package bls + +import ( + "encoding/json" + + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/services/bls/api" +) + +const ( + DEFAULT_SERVICE_DOMAIN = "bls-log.bj.baidubce.com" +) + +type Client struct { + *bce.BceClient +} + +type BlsClientConfiguration struct { + Ak string + Sk string + Endpoint string +} + +func NewClient(ak, sk, endpoint string) (*Client, error) { + return NewClientWithConfig(&BlsClientConfiguration{ + Ak: ak, + Sk: sk, + Endpoint: endpoint, + }) +} + +func NewClientWithConfig(config *BlsClientConfiguration) (*Client, error) { + ak, sk, endpoint := config.Ak, config.Sk, config.Endpoint + if len(endpoint) == 0 { + endpoint = DEFAULT_SERVICE_DOMAIN + } + client, _ := bce.NewBceClientWithAkSk(ak, sk, endpoint) + return &Client{client}, nil +} + +// LogStore opts +func (c *Client) CreateLogStore(logStore string, retention int) error { + params, jsonErr := json.Marshal(&api.LogStore{ + LogStoreName: logStore, + Retention: retention, + }) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromString(string(params)) + if err != nil { + return err + } + return api.CreateLogStore(c, body) +} + +func (c *Client) UpdateLogStore(logStore string, retention int) error { + param, jsonErr := json.Marshal(&api.LogStore{ + Retention: retention, + }) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromString(string(param)) + if err != nil { + return err + } + return api.UpdateLogStore(c, logStore, body) +} + +func (c *Client) DescribeLogStore(logStore string) (*api.LogStore, error) { + return api.DescribeLogStore(c, logStore) +} + +func (c *Client) DeleteLogStore(logStore string) error { + return api.DeleteLogStore(c, logStore) +} + +func (c *Client) ListLogStore(args *api.QueryConditions) (*api.ListLogStoreResult, error) { + return api.ListLogStore(c, args) +} + +// LogStream opt +func (c *Client) ListLogStream(logStore string, args *api.QueryConditions) (*api.ListLogStreamResult, error) { + return api.ListLogStream(c, logStore, args) +} + +// LogRecord opts +func (c *Client) PushLogRecord(logStore string, logStream string, logType string, logRecords []api.LogRecord) error { + params, jsonErr := json.Marshal(&api.PushLogRecordBody{ + LogStreamName: logStream, + Type: logType, + LogRecords: logRecords, + }) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromString(string(params)) + if err != nil { + return err + } + return api.PushLogRecord(c, logStore, body) +} + +func (c *Client) PullLogRecord(logStore string, args *api.PullLogRecordArgs) (*api.PullLogRecordResult, error) { + return api.PullLogRecord(c, logStore, args) +} + +func (c *Client) QueryLogRecord(logStore string, args *api.QueryLogRecordArgs) (*api.QueryLogResult, error) { + return api.QueryLogRecord(c, logStore, args) +} + +// FastQuery opts +func (c *Client) CreateFastQuery(args *api.CreateFastQueryBody) error { + params, jsonErr := json.Marshal(args) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromString(string(params)) + if err != nil { + return nil + } + return api.CreateFastQuery(c, body) +} + +func (c *Client) DescribeFastQuery(fastQueryName string) (*api.FastQuery, error) { + return api.DescribeFastQuery(c, fastQueryName) +} + +func (c *Client) UpdateFastQuery(fastQueryName string, args *api.UpdateFastQueryBody) error { + params, jsonErr := json.Marshal(args) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromString(string(params)) + if err != nil { + return nil + } + return api.UpdateFastQuery(c, body, fastQueryName) +} + +func (c *Client) DeleteFastQuery(fastQueryName string) error { + return api.DeleteFastQuery(c, fastQueryName) +} + +func (c *Client) ListFastQuery(args *api.QueryConditions) (*api.ListFastQueryResult, error) { + return api.ListFastQuery(c, args) +} + +// Index opts +func (c *Client) CreateIndex(logStore string, fulltext bool, fields map[string]api.LogField) error { + params, jsonErr := json.Marshal(&api.IndexFields{ + FullText: fulltext, + Fields: fields, + }) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromString(string(params)) + if err != nil { + return err + } + return api.CreateIndex(c, logStore, body) +} + +func (c *Client) UpdateIndex(logStore string, fulltext bool, fields map[string]api.LogField) error { + params, jsonErr := json.Marshal(&api.IndexFields{ + FullText: fulltext, + Fields: fields, + }) + if jsonErr != nil { + return jsonErr + } + body, err := bce.NewBodyFromString(string(params)) + if err != nil { + return err + } + return api.UpdateIndex(c, logStore, body) +} + +func (c *Client) DeleteIndex(logStore string) error { + return api.DeleteIndex(c, logStore) +} + +func (c *Client) DescribeIndex(logStore string) (*api.IndexFields, error) { + return api.DescribeIndex(c, logStore) +} diff --git a/services/bls/client_test.go b/services/bls/client_test.go new file mode 100644 index 00000000..ae2d8e91 --- /dev/null +++ b/services/bls/client_test.go @@ -0,0 +1,405 @@ +package bls + +import ( + "encoding/json" + "fmt" + "net/http" + "os" + "path/filepath" + "reflect" + "runtime" + "testing" + "time" + + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/services/bls/api" + "github.com/baidubce/bce-sdk-go/util/log" +) + +var ( + BLS_CLIENT *Client + EXIST_LOGSTORE = "bls-rd-wzy" + LOGSTREAM_PATTERN = "wzy" + JSON_LOGSTREAM = LOGSTREAM_PATTERN + "-JSON" + TEXT_LOGSTREAM = LOGSTREAM_PATTERN + "-TEXT" + FASTQUERY_NAME = "speedo" + DEFAULT_TEST_DOMAIN = "10.132.106.242" +) + +func init() { + _, f, _, _ := runtime.Caller(0) + for i := 0; i < 7; i++ { + f = filepath.Dir(f) + } + conf := filepath.Join(f, "config.json") + fp, err := os.Open(conf) + if err != nil { + fmt.Printf("config json file of ak/sk not given: %+v\n", conf) + os.Exit(1) + } + decoder := json.NewDecoder(fp) + confObj := &BlsClientConfiguration{} + err = decoder.Decode(confObj) + if err != nil { + fmt.Println(err) + return + } + // default use http protocol + BLS_CLIENT, _ = NewClient(confObj.Ak, confObj.Sk, DEFAULT_TEST_DOMAIN) + //log.SetLogHandler(log.STDERR | log.FILE) + //log.SetRotateType(log.ROTATE_SIZE) + log.SetLogLevel(log.WARN) + //log.SetLogHandler(log.STDERR) + //log.SetLogLevel(log.DEBUG) +} + +// ExpectEqual is the helper function for test each case +func ExpectEqual(alert func(format string, args ...interface{}), + actual interface{}, expected interface{}) bool { + expectedValue, actualValue := reflect.ValueOf(expected), reflect.ValueOf(actual) + equal := false + switch { + case expected == nil && actual == nil: + return true + case expected != nil && actual == nil: + equal = expectedValue.IsNil() + case expected == nil && actual != nil: + equal = actualValue.IsNil() + default: + if actualType := reflect.TypeOf(actual); actualType != nil { + if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) { + equal = reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) + } + } + } + if !equal { + _, file, line, _ := runtime.Caller(1) + alert("%s:%d: missmatch, expect %v but %v", file, line, expected, actual) + return false + } + return true +} + +// LogStore test +func TestCreateLogStore(t *testing.T) { + err := BLS_CLIENT.CreateLogStore(EXIST_LOGSTORE, 3) + ExpectEqual(t.Errorf, err, nil) + err = BLS_CLIENT.CreateLogStore(EXIST_LOGSTORE, 36) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusConflict) + } + res, err := BLS_CLIENT.DescribeLogStore(EXIST_LOGSTORE) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, res.LogStoreName, EXIST_LOGSTORE) + ExpectEqual(t.Errorf, res.Retention, 3) +} + +func TestUpdateLogStore(t *testing.T) { + err := BLS_CLIENT.UpdateLogStore(EXIST_LOGSTORE, 8) + ExpectEqual(t.Errorf, err, nil) + res, err := BLS_CLIENT.DescribeLogStore(EXIST_LOGSTORE) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, res.LogStoreName, EXIST_LOGSTORE) + ExpectEqual(t.Errorf, res.Retention, 8) + err = BLS_CLIENT.UpdateLogStore("not"+EXIST_LOGSTORE, 22) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusNotFound) + } +} + +func TestDescribeLogStore(t *testing.T) { + res, err := BLS_CLIENT.DescribeLogStore(EXIST_LOGSTORE) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, res.LogStoreName, EXIST_LOGSTORE) + ExpectEqual(t.Errorf, res.Retention, 8) + res, err = BLS_CLIENT.DescribeLogStore("not" + EXIST_LOGSTORE) + ExpectEqual(t.Errorf, res, nil) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusNotFound) + } +} + +func TestListLogStore(t *testing.T) { + args := &api.QueryConditions{ + NamePattern: "bls-rd", + Order: "asc", + OrderBy: "creationDateTime", + PageNo: 1, + PageSize: 10} + res, err := BLS_CLIENT.ListLogStore(args) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, len(res.Result) > 0, true) +} + +// LogRecord test +func TestPushLogRecord(t *testing.T) { + jsonRecords := []api.LogRecord{ + { + Message: "{\"body_bytes_sent\":184,\"bytes_sent\":398,\"client_ip\":\"120.193.204.39\",\"connection\":915958195,\"hit\":1,\"host\":\"cdbb.wonter.net\"}", + Timestamp: time.Now().UnixNano() / 1e6, + Sequence: 1, + }, + { + Message: "{\"body_bytes_sent\":14,\"bytes_sent\":408,\"client_ip\":\"120.193.222.39\",\"connection\":91567195,\"hit\":1,\"host\":\"cdbb.wonter.net\"}", + Timestamp: time.Now().UnixNano() / 1e6, + Sequence: 2, + }, + } + err := BLS_CLIENT.PushLogRecord(EXIST_LOGSTORE, JSON_LOGSTREAM, "JSON", jsonRecords) + ExpectEqual(t.Errorf, err, nil) + textRecords := []api.LogRecord{ + { + Message: "You know, for test", + Timestamp: time.Now().UnixNano() / 1e6, + Sequence: 3, + }, + { + Message: "Baidu Log Service", + Timestamp: time.Now().UnixNano() / 1e6, + Sequence: 4, + }, + } + err = BLS_CLIENT.PushLogRecord(EXIST_LOGSTORE, TEXT_LOGSTREAM, "TEXT", textRecords) + ExpectEqual(t.Errorf, err, nil) + tooNewRecord := []api.LogRecord{ + { + "LogRecord from future", + time.Now().UnixNano() / 1e4, + 12, + }, + } + err = BLS_CLIENT.PushLogRecord(EXIST_LOGSTORE, TEXT_LOGSTREAM, "TEXT", tooNewRecord) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusBadRequest) + } + err = BLS_CLIENT.PushLogRecord("not"+EXIST_LOGSTORE, TEXT_LOGSTREAM, "TEXT", textRecords) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusNotFound) + } +} + +func TestPullLogRecord(t *testing.T) { + args := &api.PullLogRecordArgs{ + LogStreamName: JSON_LOGSTREAM, + StartDateTime: "2021-01-01T10:11:44Z", + EndDateTime: "2021-12-10T16:11:44Z", + Limit: 500, + Marker: "", + } + res, err := BLS_CLIENT.PullLogRecord(EXIST_LOGSTORE, args) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, len(res.Result) >= 2, true) + res, err = BLS_CLIENT.PullLogRecord("not"+EXIST_LOGSTORE, args) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusNotFound) + ExpectEqual(t.Errorf, res, nil) + } +} + +func TestQueryLogRecord(t *testing.T) { + args := &api.QueryLogRecordArgs{ + LogStreamName: JSON_LOGSTREAM, + Query: "select count(*)", + StartDateTime: "2021-01-01T10:11:44Z", + EndDateTime: "2021-12-10T16:11:44Z", + } + res, err := BLS_CLIENT.QueryLogRecord(EXIST_LOGSTORE, args) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, res.ResultSet.Columns[0], "count(*)") +} + +// LogStream test +func TestListLogStream(t *testing.T) { + args := &api.QueryConditions{ + NamePattern: LOGSTREAM_PATTERN, + Order: "asc", + OrderBy: "creationDateTime", + PageNo: 1, + PageSize: 23, + } + res, err := BLS_CLIENT.ListLogStream(EXIST_LOGSTORE, args) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, res.PageSize, 23) + res, err = BLS_CLIENT.ListLogStream("not"+EXIST_LOGSTORE, args) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusNotFound) + ExpectEqual(t.Errorf, res, nil) + } +} + +// FastQuery test +func TestCreateFastQuery(t *testing.T) { + args := &api.CreateFastQueryBody{ + FastQueryName: FASTQUERY_NAME, + Query: "select count(*)", + Description: "calculate record number", + LogStoreName: EXIST_LOGSTORE, + LogStreamName: JSON_LOGSTREAM, + } + err := BLS_CLIENT.CreateFastQuery(args) + ExpectEqual(t.Errorf, err, nil) + // Not specify logStream + err = BLS_CLIENT.CreateFastQuery(&api.CreateFastQueryBody{ + FastQueryName: FASTQUERY_NAME, + Query: "select count(*)", + Description: "duplicate", + LogStoreName: EXIST_LOGSTORE, + LogStreamName: "", + }) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusConflict) + } +} + +func TestDescribeFastQuery(t *testing.T) { + res, err := BLS_CLIENT.DescribeFastQuery(FASTQUERY_NAME) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, res.FastQueryName, FASTQUERY_NAME) + res, err = BLS_CLIENT.DescribeFastQuery("not" + FASTQUERY_NAME) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusNotFound) + ExpectEqual(t.Errorf, res, nil) + } +} + +func TestUpdateFastQuery(t *testing.T) { + args := &api.UpdateFastQueryBody{ + Query: "select * limit 3", + Description: "Top 3", + LogStoreName: EXIST_LOGSTORE, + LogStreamName: JSON_LOGSTREAM, + } + err := BLS_CLIENT.UpdateFastQuery(FASTQUERY_NAME, args) + ExpectEqual(t.Errorf, err, nil) + res, err := BLS_CLIENT.DescribeFastQuery(FASTQUERY_NAME) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, res.Query, "select * limit 3") + err = BLS_CLIENT.UpdateFastQuery("not"+FASTQUERY_NAME, &api.UpdateFastQueryBody{ + Query: "select * limit 3", + Description: "return top 3 records", + LogStoreName: EXIST_LOGSTORE, + LogStreamName: "", + }) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusNotFound) + } +} + +func TestListFastQuery(t *testing.T) { + args := &api.QueryConditions{ + NamePattern: "s", + } + res, err := BLS_CLIENT.ListFastQuery(args) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, len(res.Result) >= 1, true) +} + +func TestDeleteFastQuery(t *testing.T) { + err := BLS_CLIENT.DeleteFastQuery(FASTQUERY_NAME) + ExpectEqual(t.Errorf, err, nil) + res, err := BLS_CLIENT.DescribeFastQuery(FASTQUERY_NAME) + ExpectEqual(t.Errorf, res, nil) + err = BLS_CLIENT.DeleteFastQuery("not" + FASTQUERY_NAME) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusNotFound) + } +} + +// Index test +func TestCreateIndex(t *testing.T) { + fields := map[string]api.LogField{ + "age": { + Type: "long", + }, + "salary": { + Type: "text", + }, + "name": { + Type: "object", + Fields: map[string]api.LogField{ + "firstName": { + Type: "text", + }, + "lastName": { + Type: "text", + }, + }, + }, + } + err := BLS_CLIENT.CreateIndex(EXIST_LOGSTORE, true, fields) + ExpectEqual(t.Errorf, err, nil) + err = BLS_CLIENT.CreateIndex(EXIST_LOGSTORE, true, fields) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusConflict) + } +} + +func TestUpdateIndex(t *testing.T) { + fields := map[string]api.LogField{ + "age": { + Type: "long", + }, + "wage": { + Type: "float", + }, + "name": { + Type: "object", + Fields: map[string]api.LogField{ + "firstName": { + Type: "text", + }, + "midName": { + Type: "text", + }, + "lastName": { + Type: "text", + }, + }, + }, + } + err := BLS_CLIENT.UpdateIndex(EXIST_LOGSTORE, false, fields) + ExpectEqual(t.Errorf, err, nil) + err = BLS_CLIENT.UpdateIndex("not"+EXIST_LOGSTORE, false, fields) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusNotFound) + } +} + +func TestDescribeIndex(t *testing.T) { + res, err := BLS_CLIENT.DescribeIndex(EXIST_LOGSTORE) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, res.Fields["name"].Fields["midName"].Type, "text") + ExpectEqual(t.Errorf, res.Fields["wage"].Type, "float") + res, err = BLS_CLIENT.DescribeIndex("not" + EXIST_LOGSTORE) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusNotFound) + ExpectEqual(t.Errorf, res, nil) + } +} + +func TestDeleteIndex(t *testing.T) { + err := BLS_CLIENT.DeleteIndex(EXIST_LOGSTORE) + ExpectEqual(t.Errorf, err, nil) + res, _ := BLS_CLIENT.DescribeIndex(EXIST_LOGSTORE) + ExpectEqual(t.Errorf, res, nil) + err = BLS_CLIENT.DeleteIndex(EXIST_LOGSTORE) // delete twice + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusNotFound) + } +} + +func TestDeleteLogStore(t *testing.T) { + res, err := BLS_CLIENT.DescribeLogStore(EXIST_LOGSTORE) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, res.LogStoreName, EXIST_LOGSTORE) + ExpectEqual(t.Errorf, res.Retention, 8) + err = BLS_CLIENT.DeleteLogStore(EXIST_LOGSTORE) + ExpectEqual(t.Errorf, err, nil) + res, err = BLS_CLIENT.DescribeLogStore(EXIST_LOGSTORE) + ExpectEqual(t.Errorf, res, nil) + res, err = BLS_CLIENT.DescribeLogStore("not" + EXIST_LOGSTORE) + ExpectEqual(t.Errorf, res, nil) + if realErr, ok := err.(*bce.BceServiceError); ok { + ExpectEqual(t.Errorf, realErr.StatusCode, http.StatusNotFound) + } +} diff --git a/services/iam/api/constants.go b/services/iam/api/constants.go new file mode 100644 index 00000000..ea3b718b --- /dev/null +++ b/services/iam/api/constants.go @@ -0,0 +1,25 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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 api + +const ( + URI_PREFIX = "/v1" + URI_USER = "/user" + URI_GROUP = "/group" + URI_POLICY = "/policy" + + POLICY_TYPE_SYSTEM = "System" + POLICY_TYPE_CUSTOM = "Custom" +) diff --git a/services/iam/api/group.go b/services/iam/api/group.go new file mode 100644 index 00000000..d238a827 --- /dev/null +++ b/services/iam/api/group.go @@ -0,0 +1,187 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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 api + +import ( + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" +) + +func CreateGroup(cli bce.Client, body *bce.Body) (*CreateGroupResult, error) { + req := &bce.BceRequest{} + req.SetUri(URI_PREFIX + URI_GROUP) + req.SetMethod(http.POST) + req.SetBody(body) + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &CreateGroupResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func GetGroup(cli bce.Client, name string) (*GetGroupResult, error) { + req := &bce.BceRequest{} + req.SetUri(getGroupUri(name)) + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &GetGroupResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func UpdateGroup(cli bce.Client, name string, body *bce.Body) (*UpdateGroupResult, error) { + req := &bce.BceRequest{} + req.SetUri(getGroupUri(name)) + req.SetMethod(http.PUT) + req.SetBody(body) + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &UpdateGroupResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func DeleteGroup(cli bce.Client, name string) error { + req := &bce.BceRequest{} + req.SetUri(getGroupUri(name)) + req.SetMethod(http.DELETE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + return nil +} + +func ListGroup(cli bce.Client) (*ListGroupResult, error) { + req := &bce.BceRequest{} + req.SetUri(URI_PREFIX + URI_GROUP) + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &ListGroupResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func AddUserToGroup(cli bce.Client, userName string, groupName string) error { + req := &bce.BceRequest{} + req.SetUri(URI_PREFIX + URI_GROUP + "/" + groupName + URI_USER + "/" + userName) + req.SetMethod(http.PUT) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + return nil +} + +func DeleteUserFromGroup(cli bce.Client, userName string, groupName string) error { + req := &bce.BceRequest{} + req.SetUri(URI_PREFIX + URI_GROUP + "/" + groupName + URI_USER + "/" + userName) + req.SetMethod(http.DELETE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + return nil +} + +func ListUsersInGroup(cli bce.Client, name string) (*ListUsersInGroupResult, error) { + req := &bce.BceRequest{} + req.SetUri(getGroupUri(name) + URI_USER) + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &ListUsersInGroupResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func ListGroupsForUser(cli bce.Client, name string) (*ListGroupsForUserResult, error) { + req := &bce.BceRequest{} + req.SetUri(getUserUri(name) + URI_GROUP) + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &ListGroupsForUserResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func getGroupUri(name string) string { + return URI_PREFIX + URI_GROUP + "/" + name +} diff --git a/services/iam/api/model.go b/services/iam/api/model.go new file mode 100644 index 00000000..05760bd9 --- /dev/null +++ b/services/iam/api/model.go @@ -0,0 +1,152 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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 api + +import "time" + +type UserModel struct { + Id string `json:"id"` + Name string `json:"name"` + CreateTime time.Time `json:"createTime"` + Description string `json:"description"` + Enabled bool `json:"enabled"` +} + +type CreateUserArgs struct { + Name string `json:"name"` + Description string `json:"description"` +} + +type CreateUserResult UserModel + +type GetUserResult UserModel + +type UpdateUserArgs struct { + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` +} + +type UpdateUserResult UserModel + +type ListUserResult struct { + Users []UserModel `json:"users"` +} + +type LoginProfileModel struct { + Password string `json:"password,omitempty"` + NeedResetPassword bool `json:"needResetPassword"` + EnabledLoginMfa bool `json:"enabledLoginMfa"` + LoginMfaType string `json:"loginMfaType,omitempty"` + ThirdPartyType bool `json:"thirdPartyType,omitempty"` + ThirdPartyAccount bool `json:"thirdPartyAccount,omitempty"` +} + +type UpdateUserLoginProfileArgs LoginProfileModel + +type UpdateUserLoginProfileResult LoginProfileModel + +type GetUserLoginProfileResult LoginProfileModel + +type GroupModel struct { + Id string `json:"id"` + Name string `json:"name"` + CreateTime time.Time `json:"createTime"` + Description string `json:"description"` +} + +type CreateGroupArgs struct { + Name string `json:"name"` + Description string `json:"description"` +} + +type CreateGroupResult GroupModel + +type GetGroupResult GroupModel + +type UpdateGroupArgs struct { + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` +} + +type UpdateGroupResult GroupModel + +type ListGroupResult struct { + Groups []GroupModel `json:"groups"` +} + +type ListUsersInGroupResult ListUserResult + +type ListGroupsForUserResult ListGroupResult + +type AclEntry struct { + Eid string `json:"eid,omitempty"` + Service string `json:"service"` + Region string `json:"region"` + Permission []string `json:"permission"` + Resource []string `json:"resource"` + Effect string `json:"effect"` +} + +type Acl struct { + Id string `json:"id,omitempty"` + AccessControlList []AclEntry `json:"accessControlList"` +} + +type PolicyModel struct { + Id string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + CreateTime time.Time `json:"createTime"` + Description string `json:"description"` + Document string `json:"document"` +} + +type CreatePolicyArgs struct { + Name string `json:"name"` + Description string `json:"description,omitempty"` + Document string `json:"document"` +} + +type CreatePolicyResult PolicyModel + +type GetPolicyResult PolicyModel + +type ListPolicyResult struct { + Policies []PolicyModel `json:"policies"` +} + +type AttachPolicyToUserArgs struct { + UserName string `json:"userName"` + PolicyName string `json:"policyName"` + PolicyType string `json:"policyType,omitempty"` +} + +type DetachPolicyFromUserArgs struct { + UserName string `json:"userName"` + PolicyName string `json:"policyName"` + PolicyType string `json:"policyType,omitempty"` +} + +type AttachPolicyToGroupArgs struct { + GroupName string `json:"groupName"` + PolicyName string `json:"policyName"` + PolicyType string `json:"policyType,omitempty"` +} + +type DetachPolicyFromGroupArgs struct { + GroupName string `json:"groupName"` + PolicyName string `json:"policyName"` + PolicyType string `json:"policyType,omitempty"` +} diff --git a/services/iam/api/policy.go b/services/iam/api/policy.go new file mode 100644 index 00000000..67f3cdd2 --- /dev/null +++ b/services/iam/api/policy.go @@ -0,0 +1,217 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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 api + +import ( + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" +) + +func CreatePolicy(cli bce.Client, body *bce.Body) (*CreatePolicyResult, error) { + req := &bce.BceRequest{} + req.SetUri(URI_PREFIX + URI_POLICY) + req.SetMethod(http.POST) + req.SetBody(body) + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &CreatePolicyResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func GetPolicy(cli bce.Client, name, policyType string) (*GetPolicyResult, error) { + req := &bce.BceRequest{} + req.SetUri(getPolicyUri(name)) + if policyType != "" { + req.SetParam("policyType", policyType) + } + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &GetPolicyResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func DeletePolicy(cli bce.Client, name string) error { + req := &bce.BceRequest{} + req.SetUri(getPolicyUri(name)) + req.SetMethod(http.DELETE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + return nil +} + +func ListPolicy(cli bce.Client, nameFilter, policyType string) (*ListPolicyResult, error) { + req := &bce.BceRequest{} + req.SetUri(URI_PREFIX + URI_POLICY) + if nameFilter != "" { + req.SetParam("nameFilter", nameFilter) + } + if policyType != "" { + req.SetParam("policyType", policyType) + } + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &ListPolicyResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func AttachPolicyToUser(cli bce.Client, args *AttachPolicyToUserArgs) error { + req := &bce.BceRequest{} + req.SetUri(getUserUri(args.UserName) + URI_POLICY + "/" + args.PolicyName) + if args.PolicyType != "" { + req.SetParam("policyType", args.PolicyType) + } + req.SetMethod(http.PUT) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + return nil +} + +func DetachPolicyFromUser(cli bce.Client, args *DetachPolicyFromUserArgs) error { + req := &bce.BceRequest{} + req.SetUri(getUserUri(args.UserName) + URI_POLICY + "/" + args.PolicyName) + if args.PolicyType != "" { + req.SetParam("policyType", args.PolicyType) + } + req.SetMethod(http.DELETE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + return nil +} + +func ListUserAttachedPolicies(cli bce.Client, name string) (*ListPolicyResult, error) { + req := &bce.BceRequest{} + req.SetUri(getUserUri(name) + URI_POLICY) + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &ListPolicyResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func AttachPolicyToGroup(cli bce.Client, args *AttachPolicyToGroupArgs) error { + req := &bce.BceRequest{} + req.SetUri(getGroupUri(args.GroupName) + URI_POLICY + "/" + args.PolicyName) + if args.PolicyType != "" { + req.SetParam("policyType", args.PolicyType) + } + req.SetMethod(http.PUT) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + return nil +} + +func DetachPolicyFromGroup(cli bce.Client, args *DetachPolicyFromGroupArgs) error { + req := &bce.BceRequest{} + req.SetUri(getGroupUri(args.GroupName) + URI_POLICY + "/" + args.PolicyName) + if args.PolicyType != "" { + req.SetParam("policyType", args.PolicyType) + } + req.SetMethod(http.DELETE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + return nil +} + +func ListGroupAttachedPolicies(cli bce.Client, name string) (*ListPolicyResult, error) { + req := &bce.BceRequest{} + req.SetUri(getGroupUri(name) + URI_POLICY) + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &ListPolicyResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func getPolicyUri(name string) string { + return URI_PREFIX + URI_POLICY + "/" + name +} diff --git a/services/iam/api/user.go b/services/iam/api/user.go new file mode 100644 index 00000000..dc454287 --- /dev/null +++ b/services/iam/api/user.go @@ -0,0 +1,174 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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 api + +import ( + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" +) + +func CreateUser(cli bce.Client, body *bce.Body) (*CreateUserResult, error) { + req := &bce.BceRequest{} + req.SetUri(URI_PREFIX + URI_USER) + req.SetMethod(http.POST) + req.SetBody(body) + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &CreateUserResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func GetUser(cli bce.Client, name string) (*GetUserResult, error) { + req := &bce.BceRequest{} + req.SetUri(getUserUri(name)) + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &GetUserResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func DeleteUser(cli bce.Client, name string) error { + req := &bce.BceRequest{} + req.SetUri(getUserUri(name)) + req.SetMethod(http.DELETE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + return nil +} + +func UpdateUser(cli bce.Client, name string, body *bce.Body) (*UpdateUserResult, error) { + req := &bce.BceRequest{} + req.SetUri(getUserUri(name)) + req.SetMethod(http.PUT) + req.SetBody(body) + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &UpdateUserResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func ListUser(cli bce.Client) (*ListUserResult, error) { + req := &bce.BceRequest{} + req.SetUri(URI_PREFIX + URI_USER) + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &ListUserResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func UpdateUserLoginProfile(cli bce.Client, name string, body *bce.Body) (*UpdateUserLoginProfileResult, error) { + req := &bce.BceRequest{} + req.SetUri(getUserUri(name) + "/loginProfile") + req.SetMethod(http.PUT) + req.SetBody(body) + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &UpdateUserLoginProfileResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func GetUserLoginProfile(cli bce.Client, name string) (*GetUserLoginProfileResult, error) { + req := &bce.BceRequest{} + req.SetUri(getUserUri(name) + "/loginProfile") + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &GetUserLoginProfileResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + return jsonBody, nil +} + +func DeleteUserLoginProfile(cli bce.Client, name string) error { + req := &bce.BceRequest{} + req.SetUri(getUserUri(name) + "/loginProfile") + req.SetMethod(http.DELETE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + return nil +} + +func getUserUri(name string) string { + return URI_PREFIX + URI_USER + "/" + name +} diff --git a/services/iam/client.go b/services/iam/client.go new file mode 100644 index 00000000..db548655 --- /dev/null +++ b/services/iam/client.go @@ -0,0 +1,207 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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. + */ + +// client.go - define the client for IAM service which is derived from BceClient + +// Package iam defines the IAM service of BCE. +// It contains the model sub package to implement the concrete request and response of the +// IAM user/accessKey/policy API +package iam + +import ( + "encoding/json" + "github.com/baidubce/bce-sdk-go/auth" + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/services/iam/api" +) + +const ( + DEFAULT_SERVICE_DOMAIN = "iam." + bce.DEFAULT_REGION + ".baidubce.com" +) + +// Client of IAM service is a kind of BceClient, so derived from BceClient +type Client struct { + *bce.BceClient +} + +func NewClient(ak, sk string) (*Client, error) { + return NewClientWithEndpoint(ak, sk, DEFAULT_SERVICE_DOMAIN) +} + +func NewClientWithEndpoint(ak, sk, endpoint string) (*Client, error) { + credentials, err := auth.NewBceCredentials(ak, sk) + if err != nil { + return nil, err + } + defaultSignOptions := &auth.SignOptions{ + HeadersToSign: auth.DEFAULT_HEADERS_TO_SIGN, + ExpireSeconds: auth.DEFAULT_EXPIRE_SECONDS} + defaultConf := &bce.BceClientConfiguration{ + Endpoint: endpoint, + Region: bce.DEFAULT_REGION, + UserAgent: bce.DEFAULT_USER_AGENT, + Credentials: credentials, + SignOption: defaultSignOptions, + Retry: bce.DEFAULT_RETRY_POLICY, + ConnectionTimeoutInMillis: bce.DEFAULT_CONNECTION_TIMEOUT_IN_MILLIS} + v1Signer := &auth.BceV1Signer{} + + client := &Client{bce.NewBceClient(defaultConf, v1Signer)} + return client, nil +} + +func (c *Client) CreateUser(args *api.CreateUserArgs) (*api.CreateUserResult, error) { + body, err := NewBodyFromStruct(args) + if err != nil { + return nil, err + } + return api.CreateUser(c, body) +} + +func (c *Client) GetUser(name string) (*api.GetUserResult, error) { + return api.GetUser(c, name) +} + +func (c *Client) UpdateUser(name string, args *api.UpdateUserArgs) (*api.UpdateUserResult, error) { + body, err := NewBodyFromStruct(args) + if err != nil { + return nil, err + } + return api.UpdateUser(c, name, body) +} + +func (c *Client) DeleteUser(name string) error { + return api.DeleteUser(c, name) +} + +func (c *Client) ListUser() (*api.ListUserResult, error) { + return api.ListUser(c) +} + +func (c *Client) UpdateUserLoginProfile(name string, args *api.UpdateUserLoginProfileArgs) ( + *api.UpdateUserLoginProfileResult, error) { + body, err := NewBodyFromStruct(args) + if err != nil { + return nil, err + } + return api.UpdateUserLoginProfile(c, name, body) +} + +func (c *Client) GetUserLoginProfile(name string) (*api.GetUserLoginProfileResult, error) { + return api.GetUserLoginProfile(c, name) +} + +func (c *Client) DeleteUserLoginProfile(name string) error { + return api.DeleteUserLoginProfile(c, name) +} + +func (c *Client) CreateGroup(args *api.CreateGroupArgs) (*api.CreateGroupResult, error) { + body, err := NewBodyFromStruct(args) + if err != nil { + return nil, err + } + return api.CreateGroup(c, body) +} + +func (c *Client) GetGroup(name string) (*api.GetGroupResult, error) { + return api.GetGroup(c, name) +} + +func (c *Client) UpdateGroup(name string, args *api.UpdateGroupArgs) (*api.UpdateGroupResult, error) { + body, err := NewBodyFromStruct(args) + if err != nil { + return nil, err + } + return api.UpdateGroup(c, name, body) +} + +func (c *Client) DeleteGroup(name string) error { + return api.DeleteGroup(c, name) +} + +func (c *Client) ListGroup() (*api.ListGroupResult, error) { + return api.ListGroup(c) +} + +func (c *Client) AddUserToGroup(userName string, groupName string) error { + return api.AddUserToGroup(c, userName, groupName) +} + +func (c *Client) DeleteUserFromGroup(userName string, groupName string) error { + return api.DeleteUserFromGroup(c, userName, groupName) +} + +func (c *Client) ListUsersInGroup(name string) (*api.ListUsersInGroupResult, error) { + return api.ListUsersInGroup(c, name) +} + +func (c *Client) ListGroupsForUser(name string) (*api.ListGroupsForUserResult, error) { + return api.ListGroupsForUser(c, name) +} + +func (c *Client) CreatePolicy(args *api.CreatePolicyArgs) (*api.CreatePolicyResult, error) { + body, err := NewBodyFromStruct(args) + if err != nil { + return nil, err + } + return api.CreatePolicy(c, body) +} + +func (c *Client) GetPolicy(name, policyType string) (*api.GetPolicyResult, error) { + return api.GetPolicy(c, name, policyType) +} + +func (c *Client) DeletePolicy(name string) error { + return api.DeletePolicy(c, name) +} + +func (c *Client) ListPolicy(nameFilter, policyType string) (*api.ListPolicyResult, error) { + return api.ListPolicy(c, nameFilter, policyType) +} + +func (c *Client) AttachPolicyToUser(args *api.AttachPolicyToUserArgs) error { + return api.AttachPolicyToUser(c, args) +} + +func (c *Client) DetachPolicyFromUser(args *api.DetachPolicyFromUserArgs) error { + return api.DetachPolicyFromUser(c, args) +} + +func (c *Client) ListUserAttachedPolicies(name string) (*api.ListPolicyResult, error) { + return api.ListUserAttachedPolicies(c, name) +} + +func (c *Client) AttachPolicyToGroup(args *api.AttachPolicyToGroupArgs) error { + return api.AttachPolicyToGroup(c, args) +} + +func (c *Client) DetachPolicyFromGroup(args *api.DetachPolicyFromGroupArgs) error { + return api.DetachPolicyFromGroup(c, args) +} + +func (c *Client) ListGroupAttachedPolicies(name string) (*api.ListPolicyResult, error) { + return api.ListGroupAttachedPolicies(c, name) +} + +func NewBodyFromStruct(args interface{}) (*bce.Body, error) { + jsonBytes, err := json.Marshal(args) + if err != nil { + return nil, err + } + body, err := bce.NewBodyFromBytes(jsonBytes) + if err != nil { + return nil, err + } + return body, nil +} diff --git a/services/iam/client_test.go b/services/iam/client_test.go new file mode 100644 index 00000000..252cb183 --- /dev/null +++ b/services/iam/client_test.go @@ -0,0 +1,377 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * 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 iam + +import ( + "encoding/json" + "fmt" + "github.com/baidubce/bce-sdk-go/services/iam/api" + "github.com/baidubce/bce-sdk-go/util/log" + "os" + "path/filepath" + "reflect" + "runtime" + "testing" +) + +// For security reason, ak/sk should not hard write here. +type Conf struct { + AK string + SK string +} + +var IAM_CLIENT *Client + +func init() { + _, f, _, _ := runtime.Caller(0) + for i := 0; i < 7; i++ { + f = filepath.Dir(f) + } + conf := filepath.Join(f, "config.json") + fp, err := os.Open(conf) + if err != nil { + fmt.Printf("config json file of ak/sk not given: %+v\n", conf) + os.Exit(1) + } + decoder := json.NewDecoder(fp) + confObj := &Conf{} + decoder.Decode(confObj) + IAM_CLIENT, _ = NewClient(confObj.AK, confObj.SK) + log.SetLogLevel(log.DEBUG) +} + +// ExpectEqual is the helper function for test each case +func ExpectEqual(alert func(format string, args ...interface{}), + expected interface{}, actual interface{}) bool { + expectedValue, actualValue := reflect.ValueOf(expected), reflect.ValueOf(actual) + equal := false + switch { + case expected == nil && actual == nil: + return true + case expected != nil && actual == nil: + equal = expectedValue.IsNil() + case expected == nil && actual != nil: + equal = actualValue.IsNil() + default: + if actualType := reflect.TypeOf(actual); actualType != nil { + if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) { + equal = reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) + } + } + } + if !equal { + _, file, line, _ := runtime.Caller(1) + alert("%s:%d: missmatch, expect %v but %v", file, line, expected, actual) + return false + } + return true +} + +func TestCreateListUpdateDeleteUser(t *testing.T) { + name := "test-user-sdk-go" + args := &api.CreateUserArgs{ + Name: name, + Description: "description", + } + res, err := IAM_CLIENT.CreateUser(args) + ExpectEqual(t.Errorf, err, nil) + jsonRes, _ := json.Marshal(res) + t.Logf(string(jsonRes)) + ExpectEqual(t.Errorf, res.Name, args.Name) + ExpectEqual(t.Errorf, res.Description, args.Description) + + users, err := IAM_CLIENT.ListUser() + ExpectEqual(t.Errorf, err, nil) + if users == nil || len(users.Users) == 0 { + t.Errorf("list user return no result") + } + jsonRes, _ = json.Marshal(users) + t.Logf(string(jsonRes)) + + updateArgs := &api.UpdateUserArgs{ + Description: "updated description", + } + updated, err := IAM_CLIENT.UpdateUser(name, updateArgs) + ExpectEqual(t.Errorf, err, nil) + jsonRes, _ = json.Marshal(updated) + t.Logf(string(jsonRes)) + ExpectEqual(t.Errorf, updated.Name, name) + ExpectEqual(t.Errorf, updated.Description, updateArgs.Description) + + err = IAM_CLIENT.DeleteUser(name) + ExpectEqual(t.Errorf, err, nil) +} + +func TestUpdateGetDeleteUserLoginProfile(t *testing.T) { + name := "test-user-sdk-go-login-profile" + args := &api.CreateUserArgs{ + Name: name, + } + _, err := IAM_CLIENT.CreateUser(args) + ExpectEqual(t.Errorf, err, nil) + + updateArgs := &api.UpdateUserLoginProfileArgs{ + Password: "1@3Qwe4f", + EnabledLoginMfa: true, + LoginMfaType: "PHONE", + } + updateRes, err := IAM_CLIENT.UpdateUserLoginProfile(name, updateArgs) + ExpectEqual(t.Errorf, err, nil) + jsonRes, _ := json.Marshal(updateRes) + t.Logf(string(jsonRes)) + ExpectEqual(t.Errorf, updateRes.EnabledLoginMfa, true) + ExpectEqual(t.Errorf, updateRes.LoginMfaType, "PHONE") + + getRes, err := IAM_CLIENT.GetUserLoginProfile(name) + ExpectEqual(t.Errorf, err, nil) + jsonRes, _ = json.Marshal(getRes) + t.Logf(string(jsonRes)) + ExpectEqual(t.Errorf, updateRes.EnabledLoginMfa, true) + ExpectEqual(t.Errorf, updateRes.LoginMfaType, "PHONE") + + err = IAM_CLIENT.DeleteUser(name) + ExpectEqual(t.Errorf, err, nil) +} + +func TestCreateGroupUpdateGetListDeleteGroup(t *testing.T) { + name := "test_sdk_go_group" + args := &api.CreateUserArgs{ + Name: name, + } + _, err := IAM_CLIENT.CreateUser(args) + ExpectEqual(t.Errorf, err, nil) + + groupArgs := &api.CreateGroupArgs{ + Name: name, + Description: "description", + } + group, err := IAM_CLIENT.CreateGroup(groupArgs) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, name, group.Name) + ExpectEqual(t.Errorf, groupArgs.Description, group.Description) + + updateGroupArgs := &api.UpdateGroupArgs{ + Description: "updated group", + } + updated, err := IAM_CLIENT.UpdateGroup(name, updateGroupArgs) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, name, updated.Name) + ExpectEqual(t.Errorf, updateGroupArgs.Description, updated.Description) + + getRes, err := IAM_CLIENT.GetGroup(name) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, name, getRes.Name) + ExpectEqual(t.Errorf, updateGroupArgs.Description, getRes.Description) + + listRes, err := IAM_CLIENT.ListGroup() + ExpectEqual(t.Errorf, err, nil) + if listRes == nil || len(listRes.Groups) == 0 { + t.Errorf("list group return no result") + } + + err = IAM_CLIENT.DeleteUser(name) + ExpectEqual(t.Errorf, err, nil) + err = IAM_CLIENT.DeleteGroup(name) + ExpectEqual(t.Errorf, err, nil) +} + +func TestAddDeleteUserFromGroup(t *testing.T) { + name := "test_sdk_go_group" + args := &api.CreateUserArgs{ + Name: name, + } + user, err := IAM_CLIENT.CreateUser(args) + ExpectEqual(t.Errorf, err, nil) + + groupArgs := &api.CreateGroupArgs{ + Name: name, + Description: "description", + } + group, err := IAM_CLIENT.CreateGroup(groupArgs) + ExpectEqual(t.Errorf, err, nil) + + err = IAM_CLIENT.AddUserToGroup(name, name) + ExpectEqual(t.Errorf, err, nil) + + usersRes, err := IAM_CLIENT.ListUsersInGroup(name) + ExpectEqual(t.Errorf, err, nil) + if usersRes == nil || len(usersRes.Users) != 1 { + t.Errorf("list group result not 1") + } + ExpectEqual(t.Errorf, 1, len(usersRes.Users)) + ExpectEqual(t.Errorf, user.Id, usersRes.Users[0].Id) + ExpectEqual(t.Errorf, user.Name, usersRes.Users[0].Name) + + groupsRes, err := IAM_CLIENT.ListGroupsForUser(name) + ExpectEqual(t.Errorf, err, nil) + if groupsRes == nil || len(groupsRes.Groups) != 1 { + t.Errorf("list user result not 1") + } + ExpectEqual(t.Errorf, 1, len(groupsRes.Groups)) + ExpectEqual(t.Errorf, group.Id, groupsRes.Groups[0].Id) + ExpectEqual(t.Errorf, group.Name, groupsRes.Groups[0].Name) + + err = IAM_CLIENT.DeleteUserFromGroup(name, name) + ExpectEqual(t.Errorf, err, nil) + + usersRes, err = IAM_CLIENT.ListUsersInGroup(name) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, 0, len(usersRes.Users)) + + groupsRes, err = IAM_CLIENT.ListGroupsForUser(name) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, 0, len(groupsRes.Groups)) + + err = IAM_CLIENT.DeleteUser(name) + ExpectEqual(t.Errorf, err, nil) + + err = IAM_CLIENT.DeleteGroup(name) + ExpectEqual(t.Errorf, err, nil) +} + +func getPolicyDocument() string { + aclEntry := api.AclEntry{ + Service: "bos", + Region: "bj", + Permission: []string{"ListBucket"}, + Resource: []string{"*"}, + Effect: "Allow", + } + acl := &api.Acl{ + AccessControlList: []api.AclEntry{aclEntry}, + } + document, _ := json.Marshal(acl) + return string(document) +} + +func TestCreateGetListDeletePolicy(t *testing.T) { + name := "test_sdk_go_policy" + args := &api.CreatePolicyArgs{ + Name: name, + Description: "description", + Document: getPolicyDocument(), + } + + res, err := IAM_CLIENT.CreatePolicy(args) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, name, res.Name) + ExpectEqual(t.Errorf, args.Description, res.Description) + + getRes, err := IAM_CLIENT.GetPolicy(name, "") + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, name, getRes.Name) + ExpectEqual(t.Errorf, args.Description, getRes.Description) + + listRes, err := IAM_CLIENT.ListPolicy(name, "") + ExpectEqual(t.Errorf, err, nil) + if listRes == nil || len(listRes.Policies) == 0 { + t.Errorf("list policy result is empty") + } + + err = IAM_CLIENT.DeletePolicy(name) + ExpectEqual(t.Errorf, err, nil) +} + +func TestUserAttachDetachPolicy(t *testing.T) { + userName := "test_sdk_go_policy" + args := &api.CreateUserArgs{ + Name: userName, + } + _, err := IAM_CLIENT.CreateUser(args) + ExpectEqual(t.Errorf, err, nil) + + policyName := "test_sdk_go_policy" + policyArgs := &api.CreatePolicyArgs{ + Name: policyName, + Description: "description", + Document: getPolicyDocument(), + } + + _, err = IAM_CLIENT.CreatePolicy(policyArgs) + ExpectEqual(t.Errorf, err, nil) + + attachArgs := &api.AttachPolicyToUserArgs{ + UserName: userName, + PolicyName: policyName, + } + err = IAM_CLIENT.AttachPolicyToUser(attachArgs) + ExpectEqual(t.Errorf, err, nil) + + policies, err := IAM_CLIENT.ListUserAttachedPolicies(userName) + ExpectEqual(t.Errorf, err, nil) + if policies == nil || len(policies.Policies) != 1 { + t.Errorf("list policy result is not 1") + } + policy := policies.Policies[0] + ExpectEqual(t.Errorf, policyName, policy.Name) + + detachArgs := &api.DetachPolicyFromUserArgs{ + UserName: userName, + PolicyName: policyName, + } + err = IAM_CLIENT.DetachPolicyFromUser(detachArgs) + ExpectEqual(t.Errorf, err, nil) + + err = IAM_CLIENT.DeletePolicy(policyName) + ExpectEqual(t.Errorf, err, nil) + err = IAM_CLIENT.DeleteUser(userName) + ExpectEqual(t.Errorf, err, nil) +} + +func TestGroupAttachDetachPolicy(t *testing.T) { + groupName := "test_sdk_go_policy" + args := &api.CreateGroupArgs{ + Name: groupName, + } + _, err := IAM_CLIENT.CreateGroup(args) + ExpectEqual(t.Errorf, err, nil) + + policyName := "test_sdk_go_policy" + policyArgs := &api.CreatePolicyArgs{ + Name: policyName, + Description: "description", + Document: getPolicyDocument(), + } + + _, err = IAM_CLIENT.CreatePolicy(policyArgs) + ExpectEqual(t.Errorf, err, nil) + + attachArgs := &api.AttachPolicyToGroupArgs{ + GroupName: groupName, + PolicyName: policyName, + } + err = IAM_CLIENT.AttachPolicyToGroup(attachArgs) + ExpectEqual(t.Errorf, err, nil) + + policies, err := IAM_CLIENT.ListGroupAttachedPolicies(groupName) + ExpectEqual(t.Errorf, err, nil) + if policies == nil || len(policies.Policies) != 1 { + t.Errorf("list policy result is not 1") + } + policy := policies.Policies[0] + ExpectEqual(t.Errorf, policyName, policy.Name) + + detachArgs := &api.DetachPolicyFromGroupArgs{ + GroupName: groupName, + PolicyName: policyName, + } + err = IAM_CLIENT.DetachPolicyFromGroup(detachArgs) + ExpectEqual(t.Errorf, err, nil) + + err = IAM_CLIENT.DeletePolicy(policyName) + ExpectEqual(t.Errorf, err, nil) + err = IAM_CLIENT.DeleteGroup(groupName) + ExpectEqual(t.Errorf, err, nil) +}