diff --git a/.travis.yml b/.travis.yml index df57e02df..6540567ce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,13 @@ language: go sudo: false +before_install: + - mkdir -p $HOME/gopath/src/github.com/huaweicloud/golangsdk + - rsync -az ${TRAVIS_BUILD_DIR}/ $HOME/gopath/src/github.com/huaweicloud/golangsdk/ + - export TRAVIS_BUILD_DIR=$HOME/gopath/src/github.com/huaweicloud/golangsdk + - cd $HOME/gopath/src/github.com/huaweicloud/golangsdk install: - go get golang.org/x/crypto/ssh -- go get -v -tags 'fixtures acceptance' ./... +- go get github.com/xioxu/golangsdk - go get github.com/wadey/gocovmerge - go get github.com/mattn/goveralls - go get golang.org/x/tools/cmd/goimports diff --git a/README.md b/README.md index 912c805ba..53415f455 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Golangsdk: a Huawei clouds SDK for Golang -[![Go Report Card](https://goreportcard.com/badge/github.com/huaweicloud/golangsdk?branch=master)](https://goreportcard.com/badge/github.com/huaweicloud/golangsdk) -[![Build Status](https://travis-ci.org/huaweicloud/golangsdk.svg?branch=master)](https://travis-ci.org/huaweicloud/golangsdk) -[![Coverage Status](https://coveralls.io/repos/github/huaweicloud/golangsdk/badge.svg?branch=master)](https://coveralls.io/github/huaweicloud/golangsdk?branch=master) -[![LICENSE](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://github.com/huaweicloud/golangsdk/blob/master/LICENSE) +[![Go Report Card](https://goreportcard.com/badge/github.com/TonyGitUser/golangsdk?branch=master)](https://goreportcard.com/badge/github.com/TonyGitUser/golangsdk) +[![Build Status](https://travis-ci.org/TonyGitUser/golangsdk.svg?branch=master)](https://travis-ci.org/TonyGitUser/golangsdk) +[![Coverage Status](https://coveralls.io/repos/github/TonyGitUser/golangsdk/badge.svg?branch=master)](https://coveralls.io/github/TonyGitUser/golangsdk?branch=master) +[![LICENSE](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://github.com/TonyGitUser/golangsdk/blob/master/LICENSE) Golangsdk is a Huawei clouds Go SDK. Golangsdk is based on [Gophercloud](https://github.com/gophercloud/gophercloud) diff --git a/openstack/client.go b/openstack/client.go index 90e917331..4ae18d244 100644 --- a/openstack/client.go +++ b/openstack/client.go @@ -436,7 +436,7 @@ func NewKmsKeyV1(client *golangsdk.ProviderClient, eo golangsdk.EndpointOpts) (* sc.Endpoint = strings.Replace(sc.Endpoint, "ecs", "kms", 1) sc.Endpoint = sc.Endpoint[:strings.LastIndex(sc.Endpoint, "v2")+3] sc.Endpoint = strings.Replace(sc.Endpoint, "v2", "v1.0", 1) - sc.ResourceBase = sc.Endpoint + sc.ResourceBase = sc.Endpoint + client.ProjectID + "/" sc.Type = "kms" return sc, err } diff --git a/openstack/endpoint_location.go b/openstack/endpoint_location.go index 254cc2d4a..d1edad681 100644 --- a/openstack/endpoint_location.go +++ b/openstack/endpoint_location.go @@ -1,11 +1,21 @@ package openstack import ( + "errors" + "net/url" + "strings" + "github.com/huaweicloud/golangsdk" tokens2 "github.com/huaweicloud/golangsdk/openstack/identity/v2/tokens" tokens3 "github.com/huaweicloud/golangsdk/openstack/identity/v3/tokens" ) +// service have same endpoint address in different location, refer to https://developer.huaweicloud.com/endpoint +var allRegionInOneEndpoint = map[string]struct{}{ + "cdn": struct{}{}, + "dns": struct{}{}, +} + /* V2EndpointURL discovers the endpoint URL for a specific service from a ServiceCatalog acquired during the v2 identity service. @@ -20,7 +30,7 @@ func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts golangsdk.EndpointOpts) // Extract Endpoints from the catalog entries that match the requested Type, Name if provided, and Region if provided. var endpoints = make([]tokens2.Endpoint, 0, 1) for _, entry := range catalog.Entries { - if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) { + if (opts.Type == "" || entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) { for _, endpoint := range entry.Endpoints { if opts.Region == "" || endpoint.Region == opts.Region { endpoints = append(endpoints, endpoint) @@ -30,10 +40,18 @@ func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts golangsdk.EndpointOpts) } // Report an error if the options were ambiguous. - if len(endpoints) > 1 { - err := &ErrMultipleMatchingEndpointsV2{} - err.Endpoints = endpoints - return "", err + if opts.Type != "" { + if len(endpoints) > 1 { + err := &ErrMultipleMatchingEndpointsV2{} + err.Endpoints = endpoints + return "", err + } else if len(endpoints) < 1 { + return buildUrlIfNotFoundV2(catalog, opts) + } + } else { + if len(endpoints) < 1 { + return "", &golangsdk.ErrEndpointNotFound{} + } } // Extract the appropriate URL from the matching Endpoint. @@ -73,7 +91,7 @@ func V3EndpointURL(catalog *tokens3.ServiceCatalog, opts golangsdk.EndpointOpts) // Name if provided, and Region if provided. var endpoints = make([]tokens3.Endpoint, 0, 1) for _, entry := range catalog.Entries { - if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) { + if (opts.Type == "" || entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) { for _, endpoint := range entry.Endpoints { if opts.Availability != golangsdk.AvailabilityAdmin && opts.Availability != golangsdk.AvailabilityPublic && @@ -92,8 +110,18 @@ func V3EndpointURL(catalog *tokens3.ServiceCatalog, opts golangsdk.EndpointOpts) } // Report an error if the options were ambiguous. - if len(endpoints) > 1 { - return "", ErrMultipleMatchingEndpointsV3{Endpoints: endpoints} + if opts.Type != "" { + if len(endpoints) > 1 { + return "", ErrMultipleMatchingEndpointsV3{Endpoints: endpoints} + } else if len(endpoints) < 1 { + return buildUrlIfNotFoundV3(catalog, opts) + } + } else { + if len(endpoints) > 1 { + return endpoints[0].URL, nil + } else if len(endpoints) < 1 { + return "", &golangsdk.ErrEndpointNotFound{} + } } // Extract the URL from the matching Endpoint. @@ -105,3 +133,59 @@ func V3EndpointURL(catalog *tokens3.ServiceCatalog, opts golangsdk.EndpointOpts) err := &golangsdk.ErrEndpointNotFound{} return "", err } + +/* + buildUrlIfNotFound builds an endpoint if it is not found in identity service response +*/ +func buildUrlIfNotFoundV2(catalog *tokens2.ServiceCatalog, opts golangsdk.EndpointOpts) (string, error) { + + tmpOpts := opts + tmpOpts.Type = "" + + existingUrl, err := V2EndpointURL(catalog, tmpOpts) + return generateEndpointUrlWithExisting(existingUrl, opts, err) +} + +/* + buildUrlIfNotFound builds an endpoint if it is not found in identity service response +*/ +func buildUrlIfNotFoundV3(catalog *tokens3.ServiceCatalog, opts golangsdk.EndpointOpts) (string, error) { + + tmpOpts := opts + tmpOpts.Type = "" + + existingUrl, err := V3EndpointURL(catalog, tmpOpts) + return generateEndpointUrlWithExisting(existingUrl, opts, err) +} + +// internal method for extract a valid endpoint address +func generateEndpointUrlWithExisting(existingUrl string, opts golangsdk.EndpointOpts, err error) (string, error) { + if err != nil || existingUrl == "" { + return "", errors.New("No suitable endpoint could be found in the service catalog.") + } + + existingUrl = golangsdk.NormalizeURL(existingUrl) + u, _ := url.Parse(existingUrl) + urlDomainParts := strings.Split(u.Host, ".") + + if len(urlDomainParts) < 2 { + return "", errors.New("No suitable endpoint could be found in the service catalog.") + } + + var urlParts []string + urlParts = append(urlParts, opts.Type) + + if _, ok := allRegionInOneEndpoint[opts.Type]; ok { + urlParts = append(urlParts, urlDomainParts[(len(urlDomainParts)-2):]...) + } else { + if len(urlDomainParts) > 3 { + // such as https://kms.cn-north-1.myhwclouds.com + urlParts = append(urlParts, urlDomainParts[(len(urlDomainParts)-3):]...) + } else { + // such as https://kms.myhwclouds.com + urlParts = append(urlParts, opts.Region) + urlParts = append(urlParts, urlDomainParts[len(urlDomainParts)-2:]...) + } + } + return u.Scheme + "://" + strings.Join(urlParts, ".") + "/", nil +} diff --git a/openstack/kms/v1/cmk/API-cn.md b/openstack/kms/v1/cmk/API-cn.md new file mode 100644 index 000000000..c7a0ca30d --- /dev/null +++ b/openstack/kms/v1/cmk/API-cn.md @@ -0,0 +1,210 @@ +# Package antiddos + import "github.com/huaweicloud/golangsdk/openstack/kms/v1.0/cmk" +**[概述](#概述)** + +**[目录](#目录)** + +**[API对应表](#API对应表)** + +**[开始](#开始)** + +## 概述 +密钥管理服务(Key Management Service)通过简单、便捷的密钥管理界面,提供易用、高安全的云上加密及密钥管理功能,并为您的其它云服务提供加密特性,让您安心使用云服务,专注业务核心的开发。 + +示例代码, 取消计划删除密钥。 + + + result := cmk.CancelDeletion(client, cmk.CancelDeletionOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }) + +示例代码, 创建用户主密钥,可用来加密数据密钥。 + + + result, err := cmk.Create(client, cmk.CreateOpts{ + KeyAlias: "TestCMK2", + KeyDescription: "It's test CMK2.", + Origin: "kms", + Realm: "", + KeyPolicy: "", + KeyUsage: "", + KeyType: "", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + + if err != nil { + panic(err) + } + +示例代码, 禁用密钥,密钥禁用后不可以使用。 + + + result, err := cmk.Disable(client, cmk.DisableOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + +示例代码, 启用密钥,密钥启用后才可以使用。 + + + result, err := cmk.Enable(client, cmk.EnableOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + +示例代码, 查询密钥详细信息。 + + + result, err := cmk.Get(client, cmk.GetOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + + if err != nil { + panic(err) + } + +示例代码, 查询实例数,获取用户已经创建的用户主密钥数量。 + + + result, err := cmk.Instances(client).Extract() + + if err != nil { + panic(err) + } + +示例代码, 查询用户所有密钥列表。 + + + result, err := cmk.List(client, cmk.ListOpts{ + Limit: "1", + Marker: "", + }).AllPages() + + if err != nil { + panic(err) + } + +示例代码, 计划多少天后删除密钥,可设置7天~1096天内删除密钥。 + + + result, err := cmk.ScheduleDeletion(client, cmk.ScheduleDeletionOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + PendingDays: "20", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + + if err != nil { + panic(err) + } + +示例代码, 修改用户主密钥别名。 + + + result, err := cmk.UpdateAlias(client, cmk.UpdateAliasOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + KeyAlias: "TestABC", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +示例代码, 修改用户主密钥描述信息。 + + + result, err := cmk.UpdateDescription(client, cmk.UpdateDescriptionOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + KeyDescription: "TestABC", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +## 目录 +**[func CancelDeletion(*golangsdk.ServiceClient, CancelDeletionOptsBuilder) (CancelDeletionResult)](#func-canceldeletion)** +**[func Create(*golangsdk.ServiceClient, CreateOptsBuilder) (CreateResult)](#func-create)** +**[func Disable(*golangsdk.ServiceClient, DisableOptsBuilder) (DisableResult)](#func-disable)** +**[func Enable(*golangsdk.ServiceClient, EnableOptsBuilder) (EnableResult)](#func-enable)** +**[func Get(*golangsdk.ServiceClient, GetOptsBuilder) (GetResult)](#func-get)** +**[func Grant(*golangsdk.ServiceClient, GrantOptsBuilder) (GrantResult)](#func-grant)** +**[func Instances(*golangsdk.ServiceClient) (InstancesResult)](#func-instances)** +**[func List(*golangsdk.ServiceClient, ListOptsBuilder) (ListResult)](#func-list)** +**[func ListGrants(*golangsdk.ServiceClient, ListGrantsOptsBuilder) (ListGrantsResult)](#func-listgrants)** +**[func ListRetirable(*golangsdk.ServiceClient, ListRetirableOptsBuilder) (ListRetirableResult)](#func-listretirable)** +**[func Quotas(*golangsdk.ServiceClient) (QuotasResult)](#func-quotas)** +**[func Retire(*golangsdk.ServiceClient, RetireOptsBuilder) (RetireResult)](#func-retire)** +**[func Revoke(*golangsdk.ServiceClient, RevokeOptsBuilder) (RevokeResult)](#func-revoke)** +**[func ScheduleDeletion(*golangsdk.ServiceClient, ScheduleDeletionOptsBuilder) (ScheduleDeletionResult)](#func-scheduledeletion)** +**[func UpdateAlias(*golangsdk.ServiceClient, UpdateAliasOptsBuilder) (UpdateAliasResult)](#func-updatealias)** +**[func UpdateDescription(*golangsdk.ServiceClient, UpdateDescriptionOptsBuilder) (UpdateDescriptionResult)](#func-updatedescription)** +## API对应表 +|类别|API|EndPoint| +|----|---|--------| +|kms|func CancelDeletion(*golangsdk.ServiceClient, CancelDeletionOptsBuilder) (CancelDeletionResult)|POST /v1.0/{project_id}/kms/cancel-key-deletion| +|kms|func Create(*golangsdk.ServiceClient, CreateOptsBuilder) (CreateResult)|POST /v1.0/{project_id}/kms/create-key| +|kms|func Disable(*golangsdk.ServiceClient, DisableOptsBuilder) (DisableResult)|POST /v1.0/{project_id}/kms/disable-key| +|kms|func Enable(*golangsdk.ServiceClient, EnableOptsBuilder) (EnableResult)|POST /v1.0/{project_id}/kms/enable-key| +|kms|func Get(*golangsdk.ServiceClient, GetOptsBuilder) (GetResult)|POST /v1.0/{project_id}/kms/describe-key| +|kms|func Grant(*golangsdk.ServiceClient, GrantOptsBuilder) (GrantResult)|POST /v1.0/{project_id}/kms/create-grant| +|kms|func Instances(*golangsdk.ServiceClient) (InstancesResult)|GET /v1.0/{project_id}/kms/user-instances| +|kms|func List(*golangsdk.ServiceClient, ListOptsBuilder) (ListResult)|POST /v1.0/{project_id}/kms/list-keys| +|kms|func ListGrants(*golangsdk.ServiceClient, ListGrantsOptsBuilder) (ListGrantsResult)|POST /v1.0/{project_id}/kms/list-grants| +|kms|func ListRetirable(*golangsdk.ServiceClient, ListRetirableOptsBuilder) (ListRetirableResult)|POST /v1.0/{project_id}/kms/list-retirable-grants| +|kms|func Quotas(*golangsdk.ServiceClient) (QuotasResult)|GET /v1.0/{project_id}/kms/user-quotas| +|kms|func Retire(*golangsdk.ServiceClient, RetireOptsBuilder) (RetireResult)|POST /v1.0/{project_id}/kms/retire-grant| +|kms|func Revoke(*golangsdk.ServiceClient, RevokeOptsBuilder) (RevokeResult)|POST /v1.0/{project_id}/kms/revoke-grant| +|kms|func ScheduleDeletion(*golangsdk.ServiceClient, ScheduleDeletionOptsBuilder) (ScheduleDeletionResult)|POST /v1.0/{project_id}/kms/schedule-key-deletion| +|kms|func UpdateAlias(*golangsdk.ServiceClient, UpdateAliasOptsBuilder) (UpdateAliasResult)|POST /v1.0/{project_id}/kms/update-key-alias| +|kms|func UpdateDescription(*golangsdk.ServiceClient, UpdateDescriptionOptsBuilder) (UpdateDescriptionResult)|POST /v1.0/{project_id}/kms/update-key-description| +## 开始 +## func CancelDeletion + func CancelDeletion(*golangsdk.ServiceClient, CancelDeletionOptsBuilder) (CancelDeletionResult) +取消计划删除密钥。 +## func Create + func Create(*golangsdk.ServiceClient, CreateOptsBuilder) (CreateResult) +创建用户主密钥,可用来加密数据密钥。 +## func Disable + func Disable(*golangsdk.ServiceClient, DisableOptsBuilder) (DisableResult) +禁用密钥,密钥禁用后不可以使用。 +## func Enable + func Enable(*golangsdk.ServiceClient, EnableOptsBuilder) (EnableResult) +启用密钥,密钥启用后才可以使用。 +## func Get + func Get(*golangsdk.ServiceClient, GetOptsBuilder) (GetResult) +查询密钥详细信息。 +## func Grant + func Grant(*golangsdk.ServiceClient, GrantOptsBuilder) (GrantResult) +创建授权,被授权用户可以对授权密钥进行操作。 +## func Instances + func Instances(*golangsdk.ServiceClient) (InstancesResult) +查询实例数,获取用户已经创建的用户主密钥数量。 +## func List + func List(*golangsdk.ServiceClient, ListOptsBuilder) (ListResult) +查询用户所有密钥列表。 +## func ListGrants + func ListGrants(*golangsdk.ServiceClient, ListGrantsOptsBuilder) (ListGrantsResult) +查询密钥的授权列表。 +## func ListRetirable + func ListRetirable(*golangsdk.ServiceClient, ListRetirableOptsBuilder) (ListRetirableResult) +查询用户可以退役的授权列表。 +## func Quotas + func Quotas(*golangsdk.ServiceClient) (QuotasResult) +查询配额,查询用户可以创建的用户主密钥配额总数及当前使用量信息。 +## func Retire + func Retire(*golangsdk.ServiceClient, RetireOptsBuilder) (RetireResult) +退役授权,表示被授权用户不再具有授权密钥的操作权。 +## func Revoke + func Revoke(*golangsdk.ServiceClient, RevokeOptsBuilder) (RevokeResult) +撤销授权,授权用户撤销被授权用户操作密钥的权限。 +## func ScheduleDeletion + func ScheduleDeletion(*golangsdk.ServiceClient, ScheduleDeletionOptsBuilder) (ScheduleDeletionResult) +计划多少天后删除密钥,可设置7天~1096天内删除密钥。 +## func UpdateAlias + func UpdateAlias(*golangsdk.ServiceClient, UpdateAliasOptsBuilder) (UpdateAliasResult) +修改用户主密钥别名。 +## func UpdateDescription + func UpdateDescription(*golangsdk.ServiceClient, UpdateDescriptionOptsBuilder) (UpdateDescriptionResult) +修改用户主密钥描述信息。 diff --git a/openstack/kms/v1/cmk/API-en.md b/openstack/kms/v1/cmk/API-en.md new file mode 100644 index 000000000..f2b0e7495 --- /dev/null +++ b/openstack/kms/v1/cmk/API-en.md @@ -0,0 +1,210 @@ +# Package antiddos + import "github.com/huaweicloud/golangsdk/openstack/kms/v1.0/cmk" +**[Overview](#overview)** + +**[Index](#index)** + +**[API Mapping](#api-mapping)** + +**[Content](#content)** + +## Overview +Key Management Service (KMS) is a secure, reliable, and easy-to-use service that helps users centrally manage and safeguard their Customer Master Keys (CMKs) and key pairs. + +Sample Code, This API enables you to cancel the scheduled deletion of a CMK. + + + result := cmk.CancelDeletion(client, cmk.CancelDeletionOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }) + +Sample Code, This API is used to create customer master keys (CMKs) used to encrypt data encryption keys (DEKs). + + + result, err := cmk.Create(client, cmk.CreateOpts{ + KeyAlias: "TestCMK2", + KeyDescription: "It's test CMK2.", + Origin: "kms", + Realm: "", + KeyPolicy: "", + KeyUsage: "", + KeyType: "", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + + if err != nil { + panic(err) + } + +Sample Code, This API allows you to disable a CMK. A disabled CMK cannot be used. + + + result, err := cmk.Disable(client, cmk.DisableOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + +Sample Code, This API allows you to enable a CMK. Only an enabled CMK can be used. + + + result, err := cmk.Enable(client, cmk.EnableOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + +Sample Code, This API allows you to query the details about a CMK. + + + result, err := cmk.Get(client, cmk.GetOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + + if err != nil { + panic(err) + } + +Sample Code, This API is used to query the number of instances, that is, the number of CMKs created. + + + result, err := cmk.Instances(client).Extract() + + if err != nil { + panic(err) + } + +Sample Code, This API allows you to query the list of all CMKs. + + + result, err := cmk.List(client, cmk.ListOpts{ + Limit: "1", + Marker: "", + }).AllPages() + + if err != nil { + panic(err) + } + +Sample Code, This API enables you to schedule the deletion of a CMK. A CMK can be scheduled to be deleted after 7 to 1096 days. + + + result, err := cmk.ScheduleDeletion(client, cmk.ScheduleDeletionOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + PendingDays: "20", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + + if err != nil { + panic(err) + } + +Sample Code, This API enables you to change the alias of a CMK. + + + result, err := cmk.UpdateAlias(client, cmk.UpdateAliasOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + KeyAlias: "TestABC", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +Sample Code, This API enables you to change the description of a CMK. + + + result, err := cmk.UpdateDescription(client, cmk.UpdateDescriptionOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + KeyDescription: "TestABC", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +## Index +**[func CancelDeletion(*golangsdk.ServiceClient, CancelDeletionOptsBuilder) (CancelDeletionResult)](#func-canceldeletion)** +**[func Create(*golangsdk.ServiceClient, CreateOptsBuilder) (CreateResult)](#func-create)** +**[func Disable(*golangsdk.ServiceClient, DisableOptsBuilder) (DisableResult)](#func-disable)** +**[func Enable(*golangsdk.ServiceClient, EnableOptsBuilder) (EnableResult)](#func-enable)** +**[func Get(*golangsdk.ServiceClient, GetOptsBuilder) (GetResult)](#func-get)** +**[func Grant(*golangsdk.ServiceClient, GrantOptsBuilder) (GrantResult)](#func-grant)** +**[func Instances(*golangsdk.ServiceClient) (InstancesResult)](#func-instances)** +**[func List(*golangsdk.ServiceClient, ListOptsBuilder) (ListResult)](#func-list)** +**[func ListGrants(*golangsdk.ServiceClient, ListGrantsOptsBuilder) (ListGrantsResult)](#func-listgrants)** +**[func ListRetirable(*golangsdk.ServiceClient, ListRetirableOptsBuilder) (ListRetirableResult)](#func-listretirable)** +**[func Quotas(*golangsdk.ServiceClient) (QuotasResult)](#func-quotas)** +**[func Retire(*golangsdk.ServiceClient, RetireOptsBuilder) (RetireResult)](#func-retire)** +**[func Revoke(*golangsdk.ServiceClient, RevokeOptsBuilder) (RevokeResult)](#func-revoke)** +**[func ScheduleDeletion(*golangsdk.ServiceClient, ScheduleDeletionOptsBuilder) (ScheduleDeletionResult)](#func-scheduledeletion)** +**[func UpdateAlias(*golangsdk.ServiceClient, UpdateAliasOptsBuilder) (UpdateAliasResult)](#func-updatealias)** +**[func UpdateDescription(*golangsdk.ServiceClient, UpdateDescriptionOptsBuilder) (UpdateDescriptionResult)](#func-updatedescription)** +## API Mapping +|Catalog|API|EndPoint| +|----|---|--------| +|kms|func CancelDeletion(*golangsdk.ServiceClient, CancelDeletionOptsBuilder) (CancelDeletionResult)|POST /v1.0/{project_id}/kms/cancel-key-deletion| +|kms|func Create(*golangsdk.ServiceClient, CreateOptsBuilder) (CreateResult)|POST /v1.0/{project_id}/kms/create-key| +|kms|func Disable(*golangsdk.ServiceClient, DisableOptsBuilder) (DisableResult)|POST /v1.0/{project_id}/kms/disable-key| +|kms|func Enable(*golangsdk.ServiceClient, EnableOptsBuilder) (EnableResult)|POST /v1.0/{project_id}/kms/enable-key| +|kms|func Get(*golangsdk.ServiceClient, GetOptsBuilder) (GetResult)|POST /v1.0/{project_id}/kms/describe-key| +|kms|func Grant(*golangsdk.ServiceClient, GrantOptsBuilder) (GrantResult)|POST /v1.0/{project_id}/kms/create-grant| +|kms|func Instances(*golangsdk.ServiceClient) (InstancesResult)|GET /v1.0/{project_id}/kms/user-instances| +|kms|func List(*golangsdk.ServiceClient, ListOptsBuilder) (ListResult)|POST /v1.0/{project_id}/kms/list-keys| +|kms|func ListGrants(*golangsdk.ServiceClient, ListGrantsOptsBuilder) (ListGrantsResult)|POST /v1.0/{project_id}/kms/list-grants| +|kms|func ListRetirable(*golangsdk.ServiceClient, ListRetirableOptsBuilder) (ListRetirableResult)|POST /v1.0/{project_id}/kms/list-retirable-grants| +|kms|func Quotas(*golangsdk.ServiceClient) (QuotasResult)|GET /v1.0/{project_id}/kms/user-quotas| +|kms|func Retire(*golangsdk.ServiceClient, RetireOptsBuilder) (RetireResult)|POST /v1.0/{project_id}/kms/retire-grant| +|kms|func Revoke(*golangsdk.ServiceClient, RevokeOptsBuilder) (RevokeResult)|POST /v1.0/{project_id}/kms/revoke-grant| +|kms|func ScheduleDeletion(*golangsdk.ServiceClient, ScheduleDeletionOptsBuilder) (ScheduleDeletionResult)|POST /v1.0/{project_id}/kms/schedule-key-deletion| +|kms|func UpdateAlias(*golangsdk.ServiceClient, UpdateAliasOptsBuilder) (UpdateAliasResult)|POST /v1.0/{project_id}/kms/update-key-alias| +|kms|func UpdateDescription(*golangsdk.ServiceClient, UpdateDescriptionOptsBuilder) (UpdateDescriptionResult)|POST /v1.0/{project_id}/kms/update-key-description| +## Content +## func CancelDeletion + func CancelDeletion(*golangsdk.ServiceClient, CancelDeletionOptsBuilder) (CancelDeletionResult) +This API enables you to cancel the scheduled deletion of a CMK. +## func Create + func Create(*golangsdk.ServiceClient, CreateOptsBuilder) (CreateResult) +This API is used to create customer master keys (CMKs) used to encrypt data encryption keys (DEKs). +## func Disable + func Disable(*golangsdk.ServiceClient, DisableOptsBuilder) (DisableResult) +This API allows you to disable a CMK. A disabled CMK cannot be used. +## func Enable + func Enable(*golangsdk.ServiceClient, EnableOptsBuilder) (EnableResult) +This API allows you to enable a CMK. Only an enabled CMK can be used. +## func Get + func Get(*golangsdk.ServiceClient, GetOptsBuilder) (GetResult) +This API allows you to query the details about a CMK. +## func Grant + func Grant(*golangsdk.ServiceClient, GrantOptsBuilder) (GrantResult) +This API enables you to create a grant to grant permissions on a CMK to a user so that the user can perform operations on the CMK. +## func Instances + func Instances(*golangsdk.ServiceClient) (InstancesResult) +This API is used to query the number of instances, that is, the number of CMKs created. +## func List + func List(*golangsdk.ServiceClient, ListOptsBuilder) (ListResult) +This API allows you to query the list of all CMKs. +## func ListGrants + func ListGrants(*golangsdk.ServiceClient, ListGrantsOptsBuilder) (ListGrantsResult) +This API enables you to query grants on a CMK. +## func ListRetirable + func ListRetirable(*golangsdk.ServiceClient, ListRetirableOptsBuilder) (ListRetirableResult) +This API enables you to query grants that can be retired. +## func Quotas + func Quotas(*golangsdk.ServiceClient) (QuotasResult) +This API is used to query the quota of a user, that is, the allocated total number of CMKs that can be created by a user and the number of CMKs that has been created by the user. +## func Retire + func Retire(*golangsdk.ServiceClient, RetireOptsBuilder) (RetireResult) +This API enables users to retire a grant. +## func Revoke + func Revoke(*golangsdk.ServiceClient, RevokeOptsBuilder) (RevokeResult) +This API allows you to revoke a grant. +## func ScheduleDeletion + func ScheduleDeletion(*golangsdk.ServiceClient, ScheduleDeletionOptsBuilder) (ScheduleDeletionResult) +This API enables you to schedule the deletion of a CMK. A CMK can be scheduled to be deleted after 7 to 1096 days. +## func UpdateAlias + func UpdateAlias(*golangsdk.ServiceClient, UpdateAliasOptsBuilder) (UpdateAliasResult) +This API enables you to change the alias of a CMK. +## func UpdateDescription + func UpdateDescription(*golangsdk.ServiceClient, UpdateDescriptionOptsBuilder) (UpdateDescriptionResult) +This API enables you to change the description of a CMK. diff --git a/openstack/kms/v1/cmk/doc.go b/openstack/kms/v1/cmk/doc.go new file mode 100644 index 000000000..8c45dc1d8 --- /dev/null +++ b/openstack/kms/v1/cmk/doc.go @@ -0,0 +1,117 @@ +/* +Key Management Service (KMS) is a secure, reliable, and easy-to-use service that helps users centrally manage and safeguard their Customer Master Keys (CMKs) and key pairs. + +Sample Code, This API enables you to cancel the scheduled deletion of a CMK. + + + result := cmk.CancelDeletion(client, cmk.CancelDeletionOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }) + +Sample Code, This API is used to create customer master keys (CMKs) used to encrypt data encryption keys (DEKs). + + + result, err := cmk.Create(client, cmk.CreateOpts{ + KeyAlias: "TestCMK2", + KeyDescription: "It's test CMK2.", + Origin: "kms", + Realm: "", + KeyPolicy: "", + KeyUsage: "", + KeyType: "", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + + if err != nil { + panic(err) + } + +Sample Code, This API allows you to disable a CMK. A disabled CMK cannot be used. + + + result, err := cmk.Disable(client, cmk.DisableOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + +Sample Code, This API allows you to enable a CMK. Only an enabled CMK can be used. + + + result, err := cmk.Enable(client, cmk.EnableOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + +Sample Code, This API allows you to query the details about a CMK. + + + result, err := cmk.Get(client, cmk.GetOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + + if err != nil { + panic(err) + } + +Sample Code, This API is used to query the number of instances, that is, the number of CMKs created. + + + result, err := cmk.Instances(client).Extract() + + if err != nil { + panic(err) + } + +Sample Code, This API allows you to query the list of all CMKs. + + + result, err := cmk.List(client, cmk.ListOpts{ + Limit: "1", + Marker: "", + }).AllPages() + + if err != nil { + panic(err) + } + +Sample Code, This API enables you to schedule the deletion of a CMK. A CMK can be scheduled to be deleted after 7 to 1096 days. + + + result, err := cmk.ScheduleDeletion(client, cmk.ScheduleDeletionOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + PendingDays: "20", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + + if err != nil { + panic(err) + } + +Sample Code, This API enables you to change the alias of a CMK. + + + result, err := cmk.UpdateAlias(client, cmk.UpdateAliasOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + KeyAlias: "TestABC", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +Sample Code, This API enables you to change the description of a CMK. + + + result, err := cmk.UpdateDescription(client, cmk.UpdateDescriptionOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + KeyDescription: "TestABC", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +*/ +package cmk diff --git a/openstack/kms/v1/cmk/requests.go b/openstack/kms/v1/cmk/requests.go new file mode 100644 index 000000000..2ddf87d7d --- /dev/null +++ b/openstack/kms/v1/cmk/requests.go @@ -0,0 +1,471 @@ +package cmk + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/postpagination" +) + +type CancelDeletionOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type CancelDeletionOptsBuilder interface { + ToCancelDeletionMap() (map[string]interface{}, error) +} + +func (opts CancelDeletionOpts) ToCancelDeletionMap() (map[string]interface{}, error) { + b, err := golangsdk.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + return b, nil +} + +func CancelDeletion(client *golangsdk.ServiceClient, opts CancelDeletionOptsBuilder) (r CancelDeletionResult) { + b, err := opts.ToCancelDeletionMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = client.Post(CancelDeletionURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type CreateOpts struct { + + // Alias of a CMK (The alias's length ranges from 1 to 255 characters and matches the regular expression ^[a-zA-Z0-9:/_-]{1,255}$. In addition, it must be different from the alias of a Default Master Key created by another service.) + KeyAlias string `json:"key_alias,"` + + // CMK description (The value ranges from 0 to 255 characters.) + KeyDescription string `json:"key_description,omitempty"` + + // Origin of a CMK. The default value is kms. The following values are enumerated: kms indicates that the CMK material is generated by KMS. external indicates that the CMK material is imported. + Origin string `json:"origin,omitempty"` + + // Region where a CMK resides. + Realm string `json:"realm,omitempty"` + + // Key policy (This parameter is an extension field.) + KeyPolicy string `json:"key_policy,omitempty"` + + // Purpose of a CMK (The default value is , that is, a key is used to encrypt and decrypt data.) + KeyUsage string `json:"key_usage,omitempty"` + + // Type of a CMK + KeyType string `json:"key_type,omitempty"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type CreateOptsBuilder interface { + ToCreateMap() (map[string]interface{}, error) +} + +func (opts CreateOpts) ToCreateMap() (map[string]interface{}, error) { + b, _ := golangsdk.BuildRequestBody(opts, "") + return b, nil +} + +func Create(client *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, _ := opts.ToCreateMap() + + _, r.Err = client.Post(CreateURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type DisableOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type DisableOptsBuilder interface { + ToDisableMap() (map[string]interface{}, error) +} + +func (opts DisableOpts) ToDisableMap() (map[string]interface{}, error) { + b, _ := golangsdk.BuildRequestBody(opts, "") + return b, nil +} + +func Disable(client *golangsdk.ServiceClient, opts DisableOptsBuilder) (r DisableResult) { + b, _ := opts.ToDisableMap() + + _, r.Err = client.Post(DisableURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type EnableOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type EnableOptsBuilder interface { + ToEnableMap() (map[string]interface{}, error) +} + +func (opts EnableOpts) ToEnableMap() (map[string]interface{}, error) { + b, _ := golangsdk.BuildRequestBody(opts, "") + return b, nil +} + +func Enable(client *golangsdk.ServiceClient, opts EnableOptsBuilder) (r EnableResult) { + b, _ := opts.ToEnableMap() + _, r.Err = client.Post(EnableURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type GetOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type GetOptsBuilder interface { + ToGetMap() (map[string]interface{}, error) +} + +func (opts GetOpts) ToGetMap() (map[string]interface{}, error) { + b, _ := golangsdk.BuildRequestBody(opts, "") + return b, nil +} + +func Get(client *golangsdk.ServiceClient, opts GetOptsBuilder) (r GetResult) { + b, _ := opts.ToGetMap() + _, r.Err = client.Post(GetURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type GrantOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f. + KeyId string `json:"key_id,"` + + // 32-byte ID of a user to which permissions are granted that matches the regular expression ^[a-zA-Z0-9_-]{32}$ Example: 0d0466b00d0466b00d0466b00d0466b0. + GranteePrincipal string `json:"grantee_principal,"` + + // Permissions that can be granted Values: create-datakey, create-datakey-without-plaintext, encrypt-datakey, decrypt-datakey, describe-key, create-grant, retire-grant, encrypt-data, decrypt-data create-grant cannot be the only value. + Operations []string `json:"operations,"` + + // Name of a grant which can be 1 to 255 characters in length and matches the regular expression ^[a-zA-Z0-9:/_-]{1,255}$ + Name string `json:"name,omitempty"` + + // 32-byte ID of a user who can retire a grant that matches the regular expression ^[a-zA-Z0-9_-]{32}$ Example: 0d0466b00d0466b00d0466b00d0466b0 + RetiringPrincipal string `json:"retiring_principal,omitempty"` + + // 32-byte ID of a user who can retire a grant that matches the regular expression ^[a-zA-Z0-9_-]{32}$ Example: 0d0466b00d0466b00d0466b00d0466b0 + Sequence string `json:"sequence,omitempty"` + + // 64-byte ID of a grant + GrantId string `json:"grant_id,"` +} + +type GrantOptsBuilder interface { + ToGrantMap() (map[string]interface{}, error) +} + +func (opts GrantOpts) ToGrantMap() (map[string]interface{}, error) { + b, _ := golangsdk.BuildRequestBody(opts, "") + return b, nil +} + +func Grant(client *golangsdk.ServiceClient, opts GrantOptsBuilder) (r GrantResult) { + b, _ := opts.ToGrantMap() + _, r.Err = client.Post(GrantURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +func Instances(client *golangsdk.ServiceClient) (r InstancesResult) { + url := InstancesURL(client) + _, r.Err = client.Get(url, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type ListOpts struct { + + // This parameter specifies the number of entries returned. If the specified number is smaller than the actual number of existing entries, will be returned for the response parameter , indicating that the query results will be displayed in separate pages. The value is within the range of the maximum number of CMKs, for example, . + Limit int `json:"limit,omitempty"` + + // This parameter marks the starting location in a pagination query. If the value is , you can send consecutive requests to obtain more record entries. The value must be set to the value in the response, for example, . + Marker string `json:"marker,omitempty"` + + // State of a CMK that matches the regular expression . The following values are enumerated: + KeyState string `json:"key_state,omitempty"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type ListOptsBuilder interface { + ToListMap() (map[string]interface{}, error) +} + +func (opts ListOpts) ToListMap() (map[string]interface{}, error) { + b, _ := golangsdk.BuildRequestBody(opts, "") + return b, nil +} + +// This API allows you to query the list of all CMKs. +func List(client *golangsdk.ServiceClient, opts ListOptsBuilder) postpagination.Pager { + initialRequest, err := opts.ToListMap() + if err != nil { + return postpagination.Pager{Err: err} + } + + return postpagination.NewPager(client, "POST", ListURL(client), initialRequest, + func(r postpagination.PageResult) postpagination.Page { + p := ListPage{ + postpagination.PostMarkerPageBase{PageResult: r, Request: initialRequest}, + } + return p + }) +} + +type ListGrantsOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // This parameter specifies the number of entries returned. If the specified number is smaller than the actual number of existing entries, will be returned for the response parameter , indicating that the query results will be displayed in separate pages. + Limit string `json:"limit,omitempty"` + + // This parameter marks the starting location in a pagination query. + Marker string `json:"marker,omitempty"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type ListGrantsOptsBuilder interface { + ToListGrantsMap() (map[string]interface{}, error) +} + +func (opts ListGrantsOpts) ToListGrantsMap() (map[string]interface{}, error) { + b, _ := golangsdk.BuildRequestBody(opts, "") + return b, nil +} + +func ListGrants(client *golangsdk.ServiceClient, opts ListGrantsOptsBuilder) (r ListGrantsResult) { + b, _ := opts.ToListGrantsMap() + + _, r.Err = client.Post(ListGrantsURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type ListRetirableOpts struct { + + // This parameter specifies the number of entries returned. If the specified number is smaller than the actual number of existing entries,  will be returned for the response parameter , indicating that the query results will be displayed in separate pages. + Limit string `json:"limit,omitempty"` + + // This parameter marks the starting location in a pagination query. + Marker string `json:"marker,omitempty"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type ListRetirableOptsBuilder interface { + ToListRetirableMap() (map[string]interface{}, error) +} + +func (opts ListRetirableOpts) ToListRetirableMap() (map[string]interface{}, error) { + b, _ := golangsdk.BuildRequestBody(opts, "") + return b, nil +} + +func ListRetirable(client *golangsdk.ServiceClient, opts ListRetirableOptsBuilder) (r ListRetirableResult) { + b, _ := opts.ToListRetirableMap() + + _, r.Err = client.Post(ListRetirableURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +func Quotas(client *golangsdk.ServiceClient) (r QuotasResult) { + url := QuotasURL(client) + _, r.Err = client.Get(url, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type RetireOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // 64-byte ID of a grant that meets the regular expression + GrantId string `json:"grant_id,"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type RetireOptsBuilder interface { + ToRetireMap() (map[string]interface{}, error) +} + +func (opts RetireOpts) ToRetireMap() (map[string]interface{}, error) { + b, _ := golangsdk.BuildRequestBody(opts, "") + return b, nil +} + +func Retire(client *golangsdk.ServiceClient, opts RetireOptsBuilder) (r RetireResult) { + b, _ := opts.ToRetireMap() + _, r.Err = client.Post(RetireURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type RevokeOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // 64-byte ID of a grant that meets the regular expression + GrantId string `json:"grant_id,"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type RevokeOptsBuilder interface { + ToRevokeMap() (map[string]interface{}, error) +} + +func (opts RevokeOpts) ToRevokeMap() (map[string]interface{}, error) { + b, _ := golangsdk.BuildRequestBody(opts, "") + return b, nil +} + +func Revoke(client *golangsdk.ServiceClient, opts RevokeOptsBuilder) (r RevokeResult) { + b, _ := opts.ToRevokeMap() + _, r.Err = client.Post(RevokeURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type ScheduleDeletionOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // Number of days after which a CMK is scheduled to be deleted (The value ranges from  to .) + PendingDays string `json:"pending_days,"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type ScheduleDeletionOptsBuilder interface { + ToScheduleDeletionMap() (map[string]interface{}, error) +} + +func (opts ScheduleDeletionOpts) ToScheduleDeletionMap() (map[string]interface{}, error) { + b, _ := golangsdk.BuildRequestBody(opts, "") + return b, nil +} + +func ScheduleDeletion(client *golangsdk.ServiceClient, opts ScheduleDeletionOptsBuilder) (r ScheduleDeletionResult) { + b, _ := opts.ToScheduleDeletionMap() + + _, r.Err = client.Post(ScheduleDeletionURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type UpdateAliasOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // Alias of a CMK whose length is 1 to 255 characters and which matches the regular expression . Suffix of the alias cannot be . + KeyAlias string `json:"key_alias,"` + + // 36-byte serial number of a request message, for example, 919c82d4-8046-4722-9094-35c3c6524cff + Sequence string `json:"sequence,omitempty"` +} + +type UpdateAliasOptsBuilder interface { + ToUpdateAliasMap() (map[string]interface{}, error) +} + +func (opts UpdateAliasOpts) ToUpdateAliasMap() (map[string]interface{}, error) { + b, _ := golangsdk.BuildRequestBody(opts, "") + return b, nil +} + +func UpdateAlias(client *golangsdk.ServiceClient, opts UpdateAliasOptsBuilder) (r UpdateAliasResult) { + b, _ := opts.ToUpdateAliasMap() + + _, r.Err = client.Post(UpdateAliasURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type UpdateDescriptionOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // CMK description (The value ranges from 0 to 255 characters.) + KeyDescription string `json:"key_description,"` + + // 36-byte serial number of a request message, for example, 919c82d4-8046-4722-9094-35c3c6524cff + Sequence string `json:"sequence,omitempty"` +} + +type UpdateDescriptionOptsBuilder interface { + ToUpdateDescriptionMap() (map[string]interface{}, error) +} + +func (opts UpdateDescriptionOpts) ToUpdateDescriptionMap() (map[string]interface{}, error) { + b, _ := golangsdk.BuildRequestBody(opts, "") + return b, nil +} + +func UpdateDescription(client *golangsdk.ServiceClient, opts UpdateDescriptionOptsBuilder) (r UpdateDescriptionResult) { + b, _ := opts.ToUpdateDescriptionMap() + _, r.Err = client.Post(UpdateDescriptionURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} diff --git a/openstack/kms/v1/cmk/results.go b/openstack/kms/v1/cmk/results.go new file mode 100644 index 000000000..970824d39 --- /dev/null +++ b/openstack/kms/v1/cmk/results.go @@ -0,0 +1,450 @@ +package cmk + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/postpagination" +) + +type commonResult struct { + golangsdk.Result +} + +type CancelDeletionResult struct { + commonResult +} + +func (r CancelDeletionResult) Extract() (*CancelDeletionResponse, error) { + var response CancelDeletionResponse + err := r.ExtractInto(&response) + return &response, err +} + +type CancelDeletionResponse struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // CMK status: 2 indicates that the CMK is enabled. 3 indicates that the CMK is disabled. 4 indicates that the CMK is scheduled for deletion. + KeyState string `json:"key_state,"` +} + +type CreateResult struct { + commonResult +} + +func (r CreateResult) Extract() (*CreateResponse, error) { + var response CreateResponse + err := r.ExtractInto(&response) + return &response, err +} + +type CreateResponse struct { + + // ID of a user domain + KeyInfo struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // ID of a user domain + DomainId string `json:"domain_id,"` + } `json:"key_info,"` +} + +type DisableResult struct { + commonResult +} + +func (r DisableResult) Extract() (*DisableResponse, error) { + var response DisableResponse + err := r.ExtractInto(&response) + return &response, err +} + +type DisableResponse struct { + + // ID of a user domain + KeyInfo struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // CMK status: 2 indicates that the CMK is enabled. 3 indicates that the CMK is disabled. 4 indicates that the CMK is scheduled for deletion. + KeyState string `json:"key_state,"` + } `json:"key_info,"` +} + +type EnableResult struct { + commonResult +} + +func (r EnableResult) Extract() (*EnableResponse, error) { + var response EnableResponse + err := r.ExtractInto(&response) + return &response, err +} + +type EnableResponse struct { + + // ID of a user domain + KeyInfo struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // CMK status: 2 indicates that the CMK is enabled. 3 indicates that the CMK is disabled. 4 indicates that the CMK is scheduled for deletion. + KeyState string `json:"key_state,"` + } `json:"key_info,"` +} + +type GetResult struct { + commonResult +} + +func (r GetResult) Extract() (*GetResponse, error) { + var response GetResponse + err := r.ExtractInto(&response) + return &response, err +} + +type GetResponse struct { + + // ID of a user domain + KeyInfo struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // ID of a user domain + DomainId string `json:"domain_id,"` + + // Alias of a CMK + KeyAlias string `json:"key_alias,"` + + // Region where a CMK resides + Realm string `json:"realm,"` + + // Description of a CMK + KeyDescription string `json:"key_description,"` + + // Creation time (time stamp) of a CMK + CreationDate string `json:"creation_date,"` + + // Scheduled deletion time (time stamp) of a CMK + ScheduledDeletionDate string `json:"scheduled_deletion_date,"` + + // State of a CMK: 1 indicates that the CMK is waiting to be activated. 2 indicates that the CMK is enabled. 3 indicates that the CMK is disabled. 4 indicates that the CMK is scheduled for deletion. 5 indicates that the CMK is waiting to be imported. + KeyState string `json:"key_state,"` + + // Identification of a Master Key. The value indicates a Default Master Key, and the value indicates a CMK. + DefaultKeyFlag string `json:"default_key_flag,"` + + // Type of a CMK + KeyType string `json:"key_type,"` + + // Expiration time + ExpirationTime string `json:"expiration_time,"` + + // Origin of a CMK. The default value is . The following values are enumerated: + Origin string `json:"origin,"` + + // Key rotation status. The default value is false, indicating that key rotation is disabled. + KeyRotationEnabled string `json:"key_rotation_enabled,"` + } `json:"key_info,"` +} + +type GrantResult struct { + commonResult +} + +func (r GrantResult) Extract() (*GrantResponse, error) { + var response GrantResponse + err := r.ExtractInto(&response) + return &response, err +} + +type GrantResponse struct { +} + +type InstancesResult struct { + commonResult +} + +func (r InstancesResult) Extract() (*InstancesResponse, error) { + var response InstancesResponse + err := r.ExtractInto(&response) + return &response, err +} + +type InstancesResponse struct { + + // Number of CMKs + InstanceNum int `json:"instance_num,"` +} + +type ListPage struct { + postpagination.PostMarkerPageBase +} + +func (r ListPage) IsEmpty() (bool, error) { + response, err := ExtractList(r) + return len(response.Keys) == 0 && len(response.KeyDetails) == 0, err +} + +func ExtractList(r ListPage) (*ListResponse, error) { + var list ListResponse + r.ExtractInto(&list) + return &list, r.Err +} + +type ListResponse struct { + + // List of CMK IDs () + Keys []string `json:"keys,"` + + // List of CMK details. For format details, see . + KeyDetails []struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // ID of a user domain + DomainId string `json:"domain_id,"` + + // Alias of a CMK + KeyAlias string `json:"key_alias,"` + + // Region where a CMK resides + Realm string `json:"realm,"` + + // Description of a CMK + KeyDescription string `json:"key_description,"` + + // Creation time (time stamp) of a CMK + CreationDate string `json:"creation_date,"` + + // Scheduled deletion time (time stamp) of a CMK + ScheduledDeletionDate string `json:"scheduled_deletion_date,"` + + // State of a CMK: 1 indicates that the CMK is waiting to be activated. 2 indicates that the CMK is enabled. 3 indicates that the CMK is disabled. 4 indicates that the CMK is scheduled for deletion. 5 indicates that the CMK is waiting to be imported. + KeyState string `json:"key_state,"` + + // Identification of a Master Key. The value indicates a Default Master Key, and the value indicates a CMK. + DefaultKeyFlag string `json:"default_key_flag,"` + + // Type of a CMK + KeyType string `json:"key_type,"` + + // Expiration time + ExpirationTime string `json:"expiration_time,"` + + // Origin of a CMK. The default value is . The following values are enumerated: + Origin string `json:"origin,"` + + // Key rotation status. The default value is false, indicating that key rotation is disabled. + KeyRotationEnabled string `json:"key_rotation_enabled,"` + } `json:"key_details,"` + + // This parameter indicates the value required for obtaining the next page of query results. If the value is , the parameter is left blank. + NextMarker string `json:"next_marker,"` + + // This parameter indicates whether there are more results displayed in another page. If the value is true, there are more results. If the value is false, the current page is the last page. + Truncated string `json:"truncated,"` +} + +type ListGrantsResult struct { + commonResult +} + +func (r ListGrantsResult) Extract() (*ListGrantsResponse, error) { + var response ListGrantsResponse + err := r.ExtractInto(&response) + return &response, err +} + +type ListGrantsResponse struct { + + // List of grants + Grants []struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // 64-byte ID of a grant that meets the regular expression + GrantId string `json:"grant_id,"` + + // 32-byte ID of a user to which permissions are granted that matches the regular expression + GranteePrincipal string `json:"grantee_principal,"` + + // Permissions that can be granted. Values: , , , , , , , , + Operations int `json:"operations,"` + + // 32-byte ID of a user who created a grant that matches the regular expression + IssuingPrincipal string `json:"issuing_principal,"` + + // Creation time (time stamp) of a grant + CreationDate string `json:"creation_date,"` + + // Name of a grant which can be 1 to 255 characters in length and matches the regular expression + Name string `json:"name,omitempty"` + + // 32-byte ID of a user who can retire a grant that matches the regular expression + RetiringPrincipal string `json:"retiring_principal,omitempty"` + } `json:"grants,"` + + // This parameter indicates the value required for obtaining the next page of query results. + NextMarker string `json:"next_marker,"` + + // + Truncated string `json:"truncated,"` + + // This parameter indicates the total number of grants. + Total int `json:"total,"` +} + +type ListRetirableResult struct { + commonResult +} + +func (r ListRetirableResult) Extract() (*ListRetirableResponse, error) { + var response ListRetirableResponse + err := r.ExtractInto(&response) + return &response, err +} + +type ListRetirableResponse struct { + + // List of grants. For format details, see the response returned from the grant querying interface. + Grants []struct { + } `json:"grants,"` + + // This parameter indicates the value required for obtaining the next page of query results. + NextMarker string `json:"next_marker,"` + + // + Truncated string `json:"truncated,"` + + // This parameter indicates the total number of grants. + Total int `json:"total,"` +} + +type QuotasResult struct { + commonResult +} + +func (r QuotasResult) Extract() (*QuotasResponse, error) { + var response QuotasResponse + err := r.ExtractInto(&response) + return &response, err +} + +type QuotasResponse struct { + + // Quota list + Quotas struct { + + // Resource quota list + Resources []struct { + + // Quota type + Type string `json:"type,"` + + // Used quotas + Used int `json:"used,"` + + // Total quotas + Quota int `json:"quota,"` + } `json:"resources,"` + } `json:"quotas,"` +} + +type RetireResult struct { + commonResult +} + +func (r RetireResult) Extract() (*RetireResponse, error) { + var response RetireResponse + err := r.ExtractInto(&response) + return &response, err +} + +type RetireResponse struct { +} + +type RevokeResult struct { + commonResult +} + +func (r RevokeResult) Extract() (*RevokeResponse, error) { + var response RevokeResponse + err := r.ExtractInto(&response) + return &response, err +} + +type RevokeResponse struct { +} + +type ScheduleDeletionResult struct { + commonResult +} + +func (r ScheduleDeletionResult) Extract() (*ScheduleDeletionResponse, error) { + var response ScheduleDeletionResponse + err := r.ExtractInto(&response) + return &response, err +} + +type ScheduleDeletionResponse struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // CMK status: 2 indicates that the CMK is enabled. 3 indicates that the CMK is disabled. 4 indicates that the CMK is scheduled for deletion. + KeyState string `json:"key_state,"` +} + +type UpdateAliasResult struct { + commonResult +} + +func (r UpdateAliasResult) Extract() (*UpdateAliasResponse, error) { + var response UpdateAliasResponse + err := r.ExtractInto(&response) + return &response, err +} + +type UpdateAliasResponse struct { + + // ID of a user domain + KeyInfo struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // Alias of a CMK + KeyAlias string `json:"key_alias,"` + } `json:"key_info,"` +} + +type UpdateDescriptionResult struct { + commonResult +} + +func (r UpdateDescriptionResult) Extract() (*UpdateDescriptionResponse, error) { + var response UpdateDescriptionResponse + err := r.ExtractInto(&response) + return &response, err +} + +type UpdateDescriptionResponse struct { + + // ID of a user domain + KeyInfo struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // Description of a CMK + KeyDescription string `json:"key_description,"` + } `json:"key_info,"` +} diff --git a/openstack/kms/v1/cmk/testing/doc.go b/openstack/kms/v1/cmk/testing/doc.go new file mode 100644 index 000000000..7603f836a --- /dev/null +++ b/openstack/kms/v1/cmk/testing/doc.go @@ -0,0 +1 @@ +package testing diff --git a/openstack/kms/v1/cmk/testing/fixtures.go b/openstack/kms/v1/cmk/testing/fixtures.go new file mode 100644 index 000000000..9b251a739 --- /dev/null +++ b/openstack/kms/v1/cmk/testing/fixtures.go @@ -0,0 +1,555 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + + "github.com/huaweicloud/golangsdk/openstack/kms/v1/cmk" + "github.com/huaweicloud/golangsdk/testhelper/client" + + "encoding/json" + "io" + + th "github.com/huaweicloud/golangsdk/testhelper" +) + +var CreateOutput = ` +{ + "key_info": { + "key_id": "30361023-62e0-4609-a5fc-6ff8eb63c186", + "domain_id": "0984aafba48049a6b9457b89968eeabf" + } +} +` + +var CreateResponse = cmk.CreateResponse{ + KeyInfo: struct { + // ID of a CMK + KeyId string `json:"key_id,"` + // ID of a user domain + DomainId string `json:"domain_id,"` + }{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + DomainId: "0984aafba48049a6b9457b89968eeabf", + }, +} + +func HandleCreateSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/create-key", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, CreateOutput) + }) +} + +var EnableOutput = ` +{ + "key_info": { + "key_id": "30361023-62e0-4609-a5fc-6ff8eb63c186", + "key_state": "2" + } +} +` + +var EnableResponse = cmk.EnableResponse{ + KeyInfo: struct { + // ID of a CMK + KeyId string `json:"key_id,"` + + // Status of a CMK + KeyState string `json:"key_state,"` + }{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + KeyState: "2", + }, +} + +func HandleEnableSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/enable-key", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, EnableOutput) + }) +} + +var DisableOutput = ` +{ + "key_info": { + "key_id": "30361023-62e0-4609-a5fc-6ff8eb63c186", + "key_state": "3" + } +} +` + +var DisableResponse = cmk.DisableResponse{ + KeyInfo: struct { + // ID of a CMK + KeyId string `json:"key_id,"` + + // Status of a CMK + KeyState string `json:"key_state,"` + }{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + KeyState: "3", + }, +} + +func HandleDisableSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/disable-key", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, DisableOutput) + }) +} + +var GetOutput = ` +{ + "key_info": { + "key_id": "30361023-62e0-4609-a5fc-6ff8eb63c186", + "domain_id": "0984aafba48049a6b9457b89968eeabf", + "key_alias": "TestCMK2", + "realm": "cn-north-1", + "key_description": "It's test CMK2.", + "creation_date": "1522573239000", + "scheduled_deletion_date": "", + "expiration_time": "", + "origin": "kms", + "key_state": "3", + "default_key_flag": "0", + "key_type": "1", + "key_rotation_enabled": "false" + } +} +` + +var GetResponse = cmk.GetResponse{ + KeyInfo: struct { + // ID of a CMK + KeyId string `json:"key_id,"` + + // ID of a user domain + DomainId string `json:"domain_id,"` + + // Alias of a CMK + KeyAlias string `json:"key_alias,"` + + // Region where a CMK resides + Realm string `json:"realm,"` + + // Description of a CMK + KeyDescription string `json:"key_description,"` + + // Creation time (time stamp) of a CMK + CreationDate string `json:"creation_date,"` + + // Scheduled deletion time (time stamp) of a CMK + ScheduledDeletionDate string `json:"scheduled_deletion_date,"` + + // + KeyState string `json:"key_state,"` + + // Identification of a Master Key. The value indicates a Default Master Key, and the value indicates a CMK. + DefaultKeyFlag string `json:"default_key_flag,"` + + // Type of a CMK + KeyType string `json:"key_type,"` + + // Expiration time + ExpirationTime string `json:"expiration_time,"` + + // Origin of a CMK. The default value is . The following values are enumerated: + Origin string `json:"origin,"` + + // Key rotation status. The default value is false, indicating that key rotation is disabled. + KeyRotationEnabled string `json:"key_rotation_enabled,"` + }{ + //30361023-62e0-4609-a5fc-6ff8eb63c186 0984aafba48049a6b9457b89968eeabf TestCMK2 cn-north-1 It's test CMK2. 1522573239000 3 0 1 kms false + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + DomainId: "0984aafba48049a6b9457b89968eeabf", + KeyAlias: "TestCMK2", + Realm: "cn-north-1", + KeyDescription: "It's test CMK2.", + CreationDate: "1522573239000", + ScheduledDeletionDate: "", + KeyState: "3", + DefaultKeyFlag: "0", + KeyType: "1", + ExpirationTime: "", + Origin: "kms", + KeyRotationEnabled: "false", + }, +} + +func HandleGetSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/describe-key", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, GetOutput) + }) +} + +var InstancesOutput = `{"instance_num":2}` + +var InstancesResponse = cmk.InstancesResponse{ + InstanceNum: 2, +} + +func HandleInstancesSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/user-instances", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, InstancesOutput) + }) +} + +var ListFirstResponse = cmk.ListResponse{ + Keys: []string{"30361023-62e0-4609-a5fc-6ff8eb63c186"}, + KeyDetails: []struct { + KeyId string `json:"key_id,"` + DomainId string `json:"domain_id,"` + KeyAlias string `json:"key_alias,"` + Realm string `json:"realm,"` + KeyDescription string `json:"key_description,"` + CreationDate string `json:"creation_date,"` + ScheduledDeletionDate string `json:"scheduled_deletion_date,"` + KeyState string `json:"key_state,"` + DefaultKeyFlag string `json:"default_key_flag,"` + KeyType string `json:"key_type,"` + ExpirationTime string `json:"expiration_time,"` + Origin string `json:"origin,"` + KeyRotationEnabled string `json:"key_rotation_enabled,"` + }{ + { + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + DomainId: "0984aafba48049a6b9457b89968eeabf", + KeyAlias: "TestCMK2", + Realm: "cn-north-1", + KeyDescription: "It's test CMK2.", + CreationDate: "1522573239000", + ScheduledDeletionDate: "", + KeyState: "3", + DefaultKeyFlag: "0", + KeyType: "1", + ExpirationTime: "", + Origin: "kms", + KeyRotationEnabled: "false", + }, + }, + NextMarker: "1", + Truncated: "true", +} + +var ListSecondResponse = cmk.ListResponse{ + Keys: []string{"e966a300-0c34-4a31-86e1-e67d13e6426a"}, + KeyDetails: []struct { + KeyId string `json:"key_id,"` + DomainId string `json:"domain_id,"` + KeyAlias string `json:"key_alias,"` + Realm string `json:"realm,"` + KeyDescription string `json:"key_description,"` + CreationDate string `json:"creation_date,"` + ScheduledDeletionDate string `json:"scheduled_deletion_date,"` + KeyState string `json:"key_state,"` + DefaultKeyFlag string `json:"default_key_flag,"` + KeyType string `json:"key_type,"` + ExpirationTime string `json:"expiration_time,"` + Origin string `json:"origin,"` + KeyRotationEnabled string `json:"key_rotation_enabled,"` + }{ + { + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + DomainId: "0984aafba48049a6b9457b89968eeabf", + KeyAlias: "TestCMK", + Realm: "cn-north-1", + KeyDescription: "It's test CMK.", + CreationDate: "1522571717000", + ScheduledDeletionDate: "", + KeyState: "2", + DefaultKeyFlag: "0", + KeyType: "1", + ExpirationTime: "", + Origin: "kms", + KeyRotationEnabled: "false", + }, + }, + NextMarker: "1", + Truncated: "true", +} + +var ListAllPagesResponse = cmk.ListResponse{ + Keys: []string{"30361023-62e0-4609-a5fc-6ff8eb63c186", "e966a300-0c34-4a31-86e1-e67d13e6426a"}, + KeyDetails: []struct { + KeyId string `json:"key_id,"` + DomainId string `json:"domain_id,"` + KeyAlias string `json:"key_alias,"` + Realm string `json:"realm,"` + KeyDescription string `json:"key_description,"` + CreationDate string `json:"creation_date,"` + ScheduledDeletionDate string `json:"scheduled_deletion_date,"` + KeyState string `json:"key_state,"` + DefaultKeyFlag string `json:"default_key_flag,"` + KeyType string `json:"key_type,"` + ExpirationTime string `json:"expiration_time,"` + Origin string `json:"origin,"` + KeyRotationEnabled string `json:"key_rotation_enabled,"` + }{ + { + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + DomainId: "0984aafba48049a6b9457b89968eeabf", + KeyAlias: "TestCMK2", + Realm: "cn-north-1", + KeyDescription: "It's test CMK2.", + CreationDate: "1522573239000", + ScheduledDeletionDate: "", + KeyState: "3", + DefaultKeyFlag: "0", + KeyType: "1", + ExpirationTime: "", + Origin: "kms", + KeyRotationEnabled: "false", + }, + { + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + DomainId: "0984aafba48049a6b9457b89968eeabf", + KeyAlias: "TestCMK", + Realm: "cn-north-1", + KeyDescription: "It's test CMK.", + CreationDate: "1522571717000", + ScheduledDeletionDate: "", + KeyState: "2", + DefaultKeyFlag: "0", + KeyType: "1", + ExpirationTime: "", + Origin: "kms", + KeyRotationEnabled: "false", + }, + }, + NextMarker: "", + Truncated: "", +} + +var ListFirstOutput = ` +{ + "keys": ["30361023-62e0-4609-a5fc-6ff8eb63c186"], + "key_details": [{ + "key_id": "30361023-62e0-4609-a5fc-6ff8eb63c186", + "domain_id": "0984aafba48049a6b9457b89968eeabf", + "key_alias": "TestCMK2", + "realm": "cn-north-1", + "key_description": "It's test CMK2.", + "creation_date": "1522573239000", + "scheduled_deletion_date": "", + "expiration_time": "", + "origin": "kms", + "key_state": "3", + "default_key_flag": "0", + "key_type": "1", + "key_rotation_enabled": "false" + }], + "next_marker": "1", + "truncated": "true" +} +` + +var ListSecondOutput = ` +{ + "keys": ["e966a300-0c34-4a31-86e1-e67d13e6426a"], + "key_details": [{ + "key_id": "e966a300-0c34-4a31-86e1-e67d13e6426a", + "domain_id": "0984aafba48049a6b9457b89968eeabf", + "key_alias": "TestCMK", + "realm": "cn-north-1", + "key_description": "It's test CMK.", + "creation_date": "1522571717000", + "scheduled_deletion_date": "", + "expiration_time": "", + "origin": "kms", + "key_state": "2", + "default_key_flag": "0", + "key_type": "1", + "key_rotation_enabled": "false" + }], + "next_marker": "", + "truncated": "false" +} +` + +func HandleListSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/list-keys", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + var listOpts cmk.ListOpts + if reader, ok := r.Body.(io.Reader); ok { + if readCloser, ok := reader.(io.Closer); ok { + defer readCloser.Close() + } + json.NewDecoder(reader).Decode(&listOpts) + } + marker := listOpts.Marker + switch marker { + case "1": + fmt.Fprintf(w, ListSecondOutput) + case "": + fmt.Fprintf(w, ListFirstOutput) + } + }) +} + +var ScheduleDeletionResponse = cmk.ScheduleDeletionResponse{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + KeyState: "4", +} + +var ScheduleDeletionOutput = ` +{"key_id":"30361023-62e0-4609-a5fc-6ff8eb63c186","key_state":"4"} +` + +func HandleScheduleDeletionSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/schedule-key-deletion", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, ScheduleDeletionOutput) + }) +} + +var CancelDeletionResponse = cmk.CancelDeletionResponse{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + KeyState: "3", +} + +var CancelDeletionOutput = ` +{"key_id":"30361023-62e0-4609-a5fc-6ff8eb63c186","key_state":"3"} +` + +func HandleCancelDeletionSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/cancel-key-deletion", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, CancelDeletionOutput) + }) +} + +func HandleException(t *testing.T, url string) { + th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "") + }) +} + +var UpdateAliasResponse = cmk.UpdateAliasResponse{ + KeyInfo: struct { + KeyId string `json:"key_id,"` + KeyAlias string `json:"key_alias,"` + }{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + KeyAlias: "TestABC", + }, +} + +var UpdateAliasOutput = ` +{"key_info":{"key_id":"e966a300-0c34-4a31-86e1-e67d13e6426a","key_alias":"TestABC"}} +` + +func HandleUpdateAliasSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/update-key-alias", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, UpdateAliasOutput) + }) +} + +var UpdateDescriptionResponse = cmk.UpdateDescriptionResponse{ + KeyInfo: struct { + KeyId string `json:"key_id,"` + KeyDescription string `json:"key_description,"` + }{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + KeyDescription: "TestABC", + }, +} + +var UpdateDescriptionOutput = ` +{"key_info":{"key_id":"e966a300-0c34-4a31-86e1-e67d13e6426a","key_description":"TestABC"}} +` + +func HandleUpdateDescriptionSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/update-key-description", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, UpdateDescriptionOutput) + }) +} + +var QuotasResponse = cmk.QuotasResponse{ + // Quota list + Quotas: struct { + // Resource quota list + Resources []struct { + // Quota type + Type string `json:"type,"` + + // Used quotas + Used int `json:"used,"` + + // Total quotas + Quota int `json:"quota,"` + } `json:"resources,"` + }{ + Resources: []struct { + // Quota type + Type string `json:"type,"` + + // Used quotas + Used int `json:"used,"` + + // Total quotas + Quota int `json:"quota,"` + }{ + { + Type: "CMK", + Used: 2, + Quota: 5, + }, + { + Type: "grant_per_CMK", + Used: 0, + Quota: 100, + }, + }, + }, +} + +var QuotasOutput = ` +{"quotas":{"resources":[{"type":"CMK","used":2,"quota":5},{"type":"grant_per_CMK","used":0,"quota":100}]}} +` + +func HandleQuotasSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/user-quotas", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, QuotasOutput) + }) +} diff --git a/openstack/kms/v1/cmk/testing/requests_test.go b/openstack/kms/v1/cmk/testing/requests_test.go new file mode 100644 index 000000000..bb3a49a66 --- /dev/null +++ b/openstack/kms/v1/cmk/testing/requests_test.go @@ -0,0 +1,233 @@ +package testing + +import ( + "testing" + + "github.com/huaweicloud/golangsdk/openstack/kms/v1/cmk" + "github.com/huaweicloud/golangsdk/postpagination" + th "github.com/huaweicloud/golangsdk/testhelper" + "github.com/huaweicloud/golangsdk/testhelper/client" +) + +func TestCreateException(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleException(t, "/kms/create-key") + _, err := cmk.Create(client.ServiceClient(), cmk.CreateOpts{}).Extract() + th.AssertEquals(t, true, err != nil) +} + +func TestCreate(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleCreateSuccessfully(t) + + var createOps = cmk.CreateOpts{ + KeyAlias: "TestCMK2", + KeyDescription: "It's test CMK2.", + Origin: "kms", + Realm: "", + KeyPolicy: "", + KeyUsage: "", + KeyType: "", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + } + + actual, err := cmk.Create(client.ServiceClient(), createOps).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &CreateResponse, actual) +} + +func TestEnableException(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleException(t, "/kms/enable-key") + _, err := cmk.Enable(client.ServiceClient(), cmk.EnableOpts{}).Extract() + th.AssertEquals(t, true, err != nil) +} + +func TestEnable(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleEnableSuccessfully(t) + + var enableOps = cmk.EnableOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + } + + actual, err := cmk.Enable(client.ServiceClient(), enableOps).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &EnableResponse, actual) +} + +func TestDisableException(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleException(t, "/kms/disable-key") + _, err := cmk.Disable(client.ServiceClient(), cmk.DisableOpts{}).Extract() + th.AssertEquals(t, true, err != nil) +} + +func TestDisable(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleDisableSuccessfully(t) + + var disableOps = cmk.DisableOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + } + + actual, err := cmk.Disable(client.ServiceClient(), disableOps).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &DisableResponse, actual) +} + +func TestGetException(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleException(t, "/kms/describe-key") + _, err := cmk.Get(client.ServiceClient(), cmk.GetOpts{}).Extract() + th.AssertEquals(t, true, err != nil) +} + +func TestGet(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleGetSuccessfully(t) + + var getOps = cmk.GetOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + } + + actual, err := cmk.Get(client.ServiceClient(), getOps).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &GetResponse, actual) +} + +func TestInstances(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleInstancesSuccessfully(t) + + actual, err := cmk.Instances(client.ServiceClient()).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &InstancesResponse, actual) +} + +func TestListAllPage(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleListSuccessfully(t) + + actual, err := cmk.List(client.ServiceClient(), cmk.ListOpts{ + Limit: 1, + }).AllPages() + th.AssertNoErr(t, err) + listResponse, err := cmk.ExtractList(actual.(cmk.ListPage)) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &ListAllPagesResponse, listResponse) +} + +func TestListEachPage(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleListSuccessfully(t) + + err := cmk.List(client.ServiceClient(), cmk.ListOpts{ + Limit: 1, + }).EachPage(func(page postpagination.Page) (bool, error) { + listResponse, err := cmk.ExtractList(page.(cmk.ListPage)) + th.AssertNoErr(t, err) + isEmpty, err := page.(cmk.ListPage).IsEmpty() + th.AssertNoErr(t, err) + th.AssertEquals(t, false, isEmpty) + if listResponse.NextMarker == "1" { + th.CheckDeepEquals(t, &ListFirstResponse, listResponse) + return false, nil + } else { + th.CheckDeepEquals(t, &ListSecondResponse, listResponse) + return true, nil + } + }) + th.AssertNoErr(t, err) +} + +func TestScheduleDeletion(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleScheduleDeletionSuccessfully(t) + + var scheduleDeletiontOps = cmk.ScheduleDeletionOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + PendingDays: "20", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + } + + actual, err := cmk.ScheduleDeletion(client.ServiceClient(), scheduleDeletiontOps).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &ScheduleDeletionResponse, actual) +} +func TestCancelDeletionException(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleException(t, "/kms/cancel-key-deletion") + + _, err := cmk.CancelDeletion(client.ServiceClient(), cmk.CancelDeletionOpts{}).Extract() + th.AssertEquals(t, true, err != nil) +} + +func TestCancelDeletion(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleCancelDeletionSuccessfully(t) + + var cancelDeletionOps = cmk.CancelDeletionOpts{ + KeyId: "30361023-62e0-4609-a5fc-6ff8eb63c186", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + } + + actual, err := cmk.CancelDeletion(client.ServiceClient(), cancelDeletionOps).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &CancelDeletionResponse, actual) +} + +func TestUpdateAlias(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleUpdateAliasSuccessfully(t) + + actual, err := cmk.UpdateAlias(client.ServiceClient(), cmk.UpdateAliasOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + KeyAlias: "TestABC", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &UpdateAliasResponse, actual) +} + +func TestUpdateDescription(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleUpdateDescriptionSuccessfully(t) + + actual, err := cmk.UpdateDescription(client.ServiceClient(), cmk.UpdateDescriptionOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + KeyDescription: "TestABC", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &UpdateDescriptionResponse, actual) +} + +func TestQuotas(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleQuotasSuccessfully(t) + + actual, err := cmk.Quotas(client.ServiceClient()).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &QuotasResponse, actual) +} diff --git a/openstack/kms/v1/cmk/url.go b/openstack/kms/v1/cmk/url.go new file mode 100644 index 000000000..2dd97445c --- /dev/null +++ b/openstack/kms/v1/cmk/url.go @@ -0,0 +1,69 @@ +package cmk + +import ( + "github.com/huaweicloud/golangsdk" +) + +func CancelDeletionURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "cancel-key-deletion") +} + +func CreateURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "create-key") +} + +func DisableURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "disable-key") +} + +func EnableURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "enable-key") +} + +func GetURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "describe-key") +} + +func GrantURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "create-grant") +} + +func InstancesURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "user-instances") +} + +func ListURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "list-keys") +} + +func ListGrantsURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "list-grants") +} + +func ListRetirableURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "list-retirable-grants") +} + +func QuotasURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "user-quotas") +} + +func RetireURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "retire-grant") +} + +func RevokeURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "revoke-grant") +} + +func ScheduleDeletionURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "schedule-key-deletion") +} + +func UpdateAliasURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "update-key-alias") +} + +func UpdateDescriptionURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "update-key-description") +} diff --git a/openstack/kms/v1/crypto/API-cn.md b/openstack/kms/v1/crypto/API-cn.md new file mode 100644 index 000000000..a30d538de --- /dev/null +++ b/openstack/kms/v1/crypto/API-cn.md @@ -0,0 +1,126 @@ +# Package antiddos + import "github.com/huaweicloud/golangsdk/openstack/kms/v1.0/crypto" +**[概述](#概述)** + +**[目录](#目录)** + +**[API对应表](#API对应表)** + +**[开始](#开始)** + +## 概述 +密钥管理服务(Key Management Service)通过简单、便捷的密钥管理界面,提供易用、高安全的云上加密及密钥管理功能,并为您的其它云服务提供加密特性,让您安心使用云服务,专注业务核心的开发。 + +示例代码, 创建数据密钥,返回结果包含明文和密文。 + + + result, err := crypto.CreateDEK(client, crypto.CreateDEKOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + DatakeyLength: "64", + }).Extract() + if err != nil { + panic(err) + } + +示例代码, 创建数据密钥,返回结果只包含密文。 + + + result, err := crypto.CreateDEKWithoutPlainText(client, crypto.CreateDEKWithoutPlainTextOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + DatakeyLength: "512", + }).Extract() + if err != nil { + panic(err) + } + +示例代码, 解密数据密钥,用指定的主密钥解密数据密钥。 + + + result, err := crypto.DecryptDEK(client, crypto.DecryptDEKOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + CipherText: "0200980044f1f74e59884b4259ecfdd9149861c93219107895d3aca3afb5ba68991d13679db3736e820d75a17309535b14d6d12796eac84dc4e826ec15ee7db38df0fdb4e97e6c9991f4f043e878387db6d3d48946799f056a8bb9b1952cd73dd1548f2b3939e209df341dd028cb4306925ade0b65393636613330302d306333342d346133312d383665312d65363764313365363432366100000000b90c13a32b15375fbb0f14d6bec4b45d96a328afdb1258747c489e6dbb28a897", + DatakeyCipherLength: "64", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +示例代码, 解密数据。 + + + result, err := crypto.DecryptData(client, crypto.DecryptDataOpts{ + CipherText: "AgBoAAwOOx+Gi8JbPOvSA0tWgxC11ARcP0ZvqR/izGq+eSMqGlfN8QT3om5xbgoeJ4nfeGK0wcyyvRmpSLvhOyw6J3ZlOTY2YTMwMC0wYzM0LTRhMzEtODZlMS1lNjdkMTNlNjQyNmEAAAAA/XZGoJQFDcRsMwBxoSBuFGb6BwYULbGPN4352ZyZyGw=", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +示例代码, 加密数据密钥,用指定的主密钥加密数据密钥。 + + + result, err := crypto.EncryptDEK(client, crypto.EncryptDEKOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + PlainText: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F5A5FD42D16A20302798EF6ED309979B43003D2320D9F0E8EA9831A92759FB4B", + DatakeyPlainLength: "64", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +示例代码, 加密数据,用指定的用户主密钥加密数据。 + + + result, err := crypto.EncryptData(client, crypto.EncryptDataOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + PlainText: "ABC", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +## 目录 +**[func CreateDEK(*golangsdk.ServiceClient, CreateDEKOptsBuilder) (CreateDEKResult)](#func-createdek)** +**[func CreateDEKWithoutPlainText(*golangsdk.ServiceClient, CreateDEKWithoutPlainTextOptsBuilder) (CreateDEKWithoutPlainTextResult)](#func-createdekwithoutplaintext)** +**[func DecryptDEK(*golangsdk.ServiceClient, DecryptDEKOptsBuilder) (DecryptDEKResult)](#func-decryptdek)** +**[func DecryptData(*golangsdk.ServiceClient, DecryptDataOptsBuilder) (DecryptDataResult)](#func-decryptdata)** +**[func EncryptDEK(*golangsdk.ServiceClient, EncryptDEKOptsBuilder) (EncryptDEKResult)](#func-encryptdek)** +**[func EncryptData(*golangsdk.ServiceClient, EncryptDataOptsBuilder) (EncryptDataResult)](#func-encryptdata)** +**[func GenerateRandomString(*golangsdk.ServiceClient, GenerateRandomStringOptsBuilder) (GenerateRandomStringResult)](#func-generaterandomstring)** +## API对应表 +|类别|API|EndPoint| +|----|---|--------| +|kms|func CreateDEK(*golangsdk.ServiceClient, CreateDEKOptsBuilder) (CreateDEKResult)|POST /v1.0/{project_id}/kms/create-datakey| +|kms|func CreateDEKWithoutPlainText(*golangsdk.ServiceClient, CreateDEKWithoutPlainTextOptsBuilder) (CreateDEKWithoutPlainTextResult)|POST /v1.0/{project_id}/kms/create-datakey-without-plaintext| +|kms|func DecryptDEK(*golangsdk.ServiceClient, DecryptDEKOptsBuilder) (DecryptDEKResult)|POST /v1.0/{project_id}/kms/decrypt-datakey| +|kms|func DecryptData(*golangsdk.ServiceClient, DecryptDataOptsBuilder) (DecryptDataResult)|POST /v1.0/{project_id}/kms/decrypt-data| +|kms|func EncryptDEK(*golangsdk.ServiceClient, EncryptDEKOptsBuilder) (EncryptDEKResult)|POST /v1.0/{project_id}/kms/encrypt-datakey| +|kms|func EncryptData(*golangsdk.ServiceClient, EncryptDataOptsBuilder) (EncryptDataResult)|POST /v1.0/{project_id}/kms/encrypt-data| +|kms|func GenerateRandomString(*golangsdk.ServiceClient, GenerateRandomStringOptsBuilder) (GenerateRandomStringResult)|POST /v1.0/{project_id}/kms/gen-random| +## 开始 +## func CreateDEK + func CreateDEK(*golangsdk.ServiceClient, CreateDEKOptsBuilder) (CreateDEKResult) +创建数据密钥,返回结果包含明文和密文。 +## func CreateDEKWithoutPlainText + func CreateDEKWithoutPlainText(*golangsdk.ServiceClient, CreateDEKWithoutPlainTextOptsBuilder) (CreateDEKWithoutPlainTextResult) +创建数据密钥,返回结果只包含密文。 +## func DecryptDEK + func DecryptDEK(*golangsdk.ServiceClient, DecryptDEKOptsBuilder) (DecryptDEKResult) +解密数据密钥,用指定的主密钥解密数据密钥。 +## func DecryptData + func DecryptData(*golangsdk.ServiceClient, DecryptDataOptsBuilder) (DecryptDataResult) +解密数据。 +## func EncryptDEK + func EncryptDEK(*golangsdk.ServiceClient, EncryptDEKOptsBuilder) (EncryptDEKResult) +加密数据密钥,用指定的主密钥加密数据密钥。 +## func EncryptData + func EncryptData(*golangsdk.ServiceClient, EncryptDataOptsBuilder) (EncryptDataResult) +加密数据,用指定的用户主密钥加密数据。 +## func GenerateRandomString + func GenerateRandomString(*golangsdk.ServiceClient, GenerateRandomStringOptsBuilder) (GenerateRandomStringResult) +生成512bit的随机数。 diff --git a/openstack/kms/v1/crypto/API-en.md b/openstack/kms/v1/crypto/API-en.md new file mode 100644 index 000000000..3f4b6f45a --- /dev/null +++ b/openstack/kms/v1/crypto/API-en.md @@ -0,0 +1,126 @@ +# Package antiddos + import "github.com/huaweicloud/golangsdk/openstack/kms/v1.0/crypto" +**[Overview](#overview)** + +**[Index](#index)** + +**[API Mapping](#api-mapping)** + +**[Content](#content)** + +## Overview +Key Management Service (KMS) is a secure, reliable, and easy-to-use service that helps users centrally manage and safeguard their Customer Master Keys (CMKs) and key pairs. + +Sample Code, This API allows you to create a DEK. A returned result includes the plaintext and the ciphertext of a DEK. + + + result, err := crypto.CreateDEK(client, crypto.CreateDEKOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + DatakeyLength: "64", + }).Extract() + if err != nil { + panic(err) + } + +Sample Code, This API allows you to create a plaintext-free DEK, that is, the returned result of this API includes only the plaintext of the DEK. + + + result, err := crypto.CreateDEKWithoutPlainText(client, crypto.CreateDEKWithoutPlainTextOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + DatakeyLength: "512", + }).Extract() + if err != nil { + panic(err) + } + +Sample Code, This API enables you to decrypt a DEK using a specified CMK. + + + result, err := crypto.DecryptDEK(client, crypto.DecryptDEKOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + CipherText: "0200980044f1f74e59884b4259ecfdd9149861c93219107895d3aca3afb5ba68991d13679db3736e820d75a17309535b14d6d12796eac84dc4e826ec15ee7db38df0fdb4e97e6c9991f4f043e878387db6d3d48946799f056a8bb9b1952cd73dd1548f2b3939e209df341dd028cb4306925ade0b65393636613330302d306333342d346133312d383665312d65363764313365363432366100000000b90c13a32b15375fbb0f14d6bec4b45d96a328afdb1258747c489e6dbb28a897", + DatakeyCipherLength: "64", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +Sample Code, This API enables you to decrypt data. + + + result, err := crypto.DecryptData(client, crypto.DecryptDataOpts{ + CipherText: "AgBoAAwOOx+Gi8JbPOvSA0tWgxC11ARcP0ZvqR/izGq+eSMqGlfN8QT3om5xbgoeJ4nfeGK0wcyyvRmpSLvhOyw6J3ZlOTY2YTMwMC0wYzM0LTRhMzEtODZlMS1lNjdkMTNlNjQyNmEAAAAA/XZGoJQFDcRsMwBxoSBuFGb6BwYULbGPN4352ZyZyGw=", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +Sample Code, This API enables you to encrypt a DEK using a specified CMK. + + + result, err := crypto.EncryptDEK(client, crypto.EncryptDEKOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + PlainText: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F5A5FD42D16A20302798EF6ED309979B43003D2320D9F0E8EA9831A92759FB4B", + DatakeyPlainLength: "64", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +Sample Code, This API enables you to encrypt data using a specified CMK. + + + result, err := crypto.EncryptData(client, crypto.EncryptDataOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + PlainText: "ABC", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +## Index +**[func CreateDEK(*golangsdk.ServiceClient, CreateDEKOptsBuilder) (CreateDEKResult)](#func-createdek)** +**[func CreateDEKWithoutPlainText(*golangsdk.ServiceClient, CreateDEKWithoutPlainTextOptsBuilder) (CreateDEKWithoutPlainTextResult)](#func-createdekwithoutplaintext)** +**[func DecryptDEK(*golangsdk.ServiceClient, DecryptDEKOptsBuilder) (DecryptDEKResult)](#func-decryptdek)** +**[func DecryptData(*golangsdk.ServiceClient, DecryptDataOptsBuilder) (DecryptDataResult)](#func-decryptdata)** +**[func EncryptDEK(*golangsdk.ServiceClient, EncryptDEKOptsBuilder) (EncryptDEKResult)](#func-encryptdek)** +**[func EncryptData(*golangsdk.ServiceClient, EncryptDataOptsBuilder) (EncryptDataResult)](#func-encryptdata)** +**[func GenerateRandomString(*golangsdk.ServiceClient, GenerateRandomStringOptsBuilder) (GenerateRandomStringResult)](#func-generaterandomstring)** +## API Mapping +|Catalog|API|EndPoint| +|----|---|--------| +|kms|func CreateDEK(*golangsdk.ServiceClient, CreateDEKOptsBuilder) (CreateDEKResult)|POST /v1.0/{project_id}/kms/create-datakey| +|kms|func CreateDEKWithoutPlainText(*golangsdk.ServiceClient, CreateDEKWithoutPlainTextOptsBuilder) (CreateDEKWithoutPlainTextResult)|POST /v1.0/{project_id}/kms/create-datakey-without-plaintext| +|kms|func DecryptDEK(*golangsdk.ServiceClient, DecryptDEKOptsBuilder) (DecryptDEKResult)|POST /v1.0/{project_id}/kms/decrypt-datakey| +|kms|func DecryptData(*golangsdk.ServiceClient, DecryptDataOptsBuilder) (DecryptDataResult)|POST /v1.0/{project_id}/kms/decrypt-data| +|kms|func EncryptDEK(*golangsdk.ServiceClient, EncryptDEKOptsBuilder) (EncryptDEKResult)|POST /v1.0/{project_id}/kms/encrypt-datakey| +|kms|func EncryptData(*golangsdk.ServiceClient, EncryptDataOptsBuilder) (EncryptDataResult)|POST /v1.0/{project_id}/kms/encrypt-data| +|kms|func GenerateRandomString(*golangsdk.ServiceClient, GenerateRandomStringOptsBuilder) (GenerateRandomStringResult)|POST /v1.0/{project_id}/kms/gen-random| +## Content +## func CreateDEK + func CreateDEK(*golangsdk.ServiceClient, CreateDEKOptsBuilder) (CreateDEKResult) +This API allows you to create a DEK. A returned result includes the plaintext and the ciphertext of a DEK. +## func CreateDEKWithoutPlainText + func CreateDEKWithoutPlainText(*golangsdk.ServiceClient, CreateDEKWithoutPlainTextOptsBuilder) (CreateDEKWithoutPlainTextResult) +This API allows you to create a plaintext-free DEK, that is, the returned result of this API includes only the plaintext of the DEK. +## func DecryptDEK + func DecryptDEK(*golangsdk.ServiceClient, DecryptDEKOptsBuilder) (DecryptDEKResult) +This API enables you to decrypt a DEK using a specified CMK. +## func DecryptData + func DecryptData(*golangsdk.ServiceClient, DecryptDataOptsBuilder) (DecryptDataResult) +This API enables you to decrypt data. +## func EncryptDEK + func EncryptDEK(*golangsdk.ServiceClient, EncryptDEKOptsBuilder) (EncryptDEKResult) +This API enables you to encrypt a DEK using a specified CMK. +## func EncryptData + func EncryptData(*golangsdk.ServiceClient, EncryptDataOptsBuilder) (EncryptDataResult) +This API enables you to encrypt data using a specified CMK. +## func GenerateRandomString + func GenerateRandomString(*golangsdk.ServiceClient, GenerateRandomStringOptsBuilder) (GenerateRandomStringResult) +This API allows you to obtain a random number whose length can be up to 512 bits. diff --git a/openstack/kms/v1/crypto/doc.go b/openstack/kms/v1/crypto/doc.go new file mode 100644 index 000000000..ce74959ec --- /dev/null +++ b/openstack/kms/v1/crypto/doc.go @@ -0,0 +1,78 @@ +/* +Key Management Service (KMS) is a secure, reliable, and easy-to-use service that helps users centrally manage and safeguard their Customer Master Keys (CMKs) and key pairs. + +Sample Code, This API allows you to create a DEK. A returned result includes the plaintext and the ciphertext of a DEK. + + + result, err := crypto.CreateDEK(client, crypto.CreateDEKOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + DatakeyLength: "64", + }).Extract() + if err != nil { + panic(err) + } + +Sample Code, This API allows you to create a plaintext-free DEK, that is, the returned result of this API includes only the plaintext of the DEK. + + + result, err := crypto.CreateDEKWithoutPlainText(client, crypto.CreateDEKWithoutPlainTextOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + DatakeyLength: "512", + }).Extract() + if err != nil { + panic(err) + } + +Sample Code, This API enables you to decrypt a DEK using a specified CMK. + + + result, err := crypto.DecryptDEK(client, crypto.DecryptDEKOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + CipherText: "0200980044f1f74e59884b4259ecfdd9149861c93219107895d3aca3afb5ba68991d13679db3736e820d75a17309535b14d6d12796eac84dc4e826ec15ee7db38df0fdb4e97e6c9991f4f043e878387db6d3d48946799f056a8bb9b1952cd73dd1548f2b3939e209df341dd028cb4306925ade0b65393636613330302d306333342d346133312d383665312d65363764313365363432366100000000b90c13a32b15375fbb0f14d6bec4b45d96a328afdb1258747c489e6dbb28a897", + DatakeyCipherLength: "64", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +Sample Code, This API enables you to decrypt data. + + + result, err := crypto.DecryptData(client, crypto.DecryptDataOpts{ + CipherText: "AgBoAAwOOx+Gi8JbPOvSA0tWgxC11ARcP0ZvqR/izGq+eSMqGlfN8QT3om5xbgoeJ4nfeGK0wcyyvRmpSLvhOyw6J3ZlOTY2YTMwMC0wYzM0LTRhMzEtODZlMS1lNjdkMTNlNjQyNmEAAAAA/XZGoJQFDcRsMwBxoSBuFGb6BwYULbGPN4352ZyZyGw=", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +Sample Code, This API enables you to encrypt a DEK using a specified CMK. + + + result, err := crypto.EncryptDEK(client, crypto.EncryptDEKOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + PlainText: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F5A5FD42D16A20302798EF6ED309979B43003D2320D9F0E8EA9831A92759FB4B", + DatakeyPlainLength: "64", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +Sample Code, This API enables you to encrypt data using a specified CMK. + + + result, err := crypto.EncryptData(client, crypto.EncryptDataOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + PlainText: "ABC", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + if err != nil { + panic(err) + } + +*/ +package crypto diff --git a/openstack/kms/v1/crypto/requests.go b/openstack/kms/v1/crypto/requests.go new file mode 100644 index 000000000..505b1f1ce --- /dev/null +++ b/openstack/kms/v1/crypto/requests.go @@ -0,0 +1,282 @@ +package crypto + +import ( + "github.com/huaweicloud/golangsdk" +) + +type CreateDEKOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // The value of this parameter must be a series of "key:value" pairs used to record resource context information. The value of this parameter must not contain sensitive information and must be within 8192 characters in length. Example: {"Key1":"Value1","Key2":"Value2"} + EncryptionContext string `json:"encryption_context,omitempty"` + + // Number of bits in the length of a DEK (The maximum number is 512.) + DatakeyLength string `json:"datakey_length,"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type CreateDEKOptsBuilder interface { + ToCreateDEKMap() (map[string]interface{}, error) +} + +func (opts CreateDEKOpts) ToCreateDEKMap() (map[string]interface{}, error) { + b, err := golangsdk.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + return b, nil +} + +func CreateDEK(client *golangsdk.ServiceClient, opts CreateDEKOptsBuilder) (r CreateDEKResult) { + b, err := opts.ToCreateDEKMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = client.Post(CreateDEKURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type CreateDEKWithoutPlainTextOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // The value of this parameter must be a series of "key:value" pairs used to record resource context information. The value of this parameter must not contain sensitive information and must be within 8192 characters in length. Example: {"Key1":"Value1","Key2":"Value2"} + EncryptionContext string `json:"encryption_context,omitempty"` + + // Number of bits in the length of a DEK (The maximum number is 512.) + DatakeyLength string `json:"datakey_length,"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type CreateDEKWithoutPlainTextOptsBuilder interface { + ToCreateDEKWithoutPlainTextMap() (map[string]interface{}, error) +} + +func (opts CreateDEKWithoutPlainTextOpts) ToCreateDEKWithoutPlainTextMap() (map[string]interface{}, error) { + b, err := golangsdk.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + return b, nil +} + +func CreateDEKWithoutPlainText(client *golangsdk.ServiceClient, opts CreateDEKWithoutPlainTextOptsBuilder) (r CreateDEKWithoutPlainTextResult) { + b, err := opts.ToCreateDEKWithoutPlainTextMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = client.Post(CreateDEKWithoutPlainTextURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type DecryptDEKOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // The value of this parameter must be a series of "key:value" pairs used to record resource context information. The value of this parameter must not contain sensitive information and must be within 8192 characters in length. Example: {"Key1":"Value1","Key2":"Value2"} + EncryptionContext string `json:"encryption_context,omitempty"` + + // This parameter indicates the hexadecimal character string of the DEK ciphertext and the metadata. The value is the value in the encryption result of a DEK. + CipherText string `json:"cipher_text,"` + + // Number of bytes in the length of a DEK (The maximum number is 64.) + DatakeyCipherLength string `json:"datakey_cipher_length,"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type DecryptDEKOptsBuilder interface { + ToDecryptDEKMap() (map[string]interface{}, error) +} + +func (opts DecryptDEKOpts) ToDecryptDEKMap() (map[string]interface{}, error) { + b, err := golangsdk.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + return b, nil +} + +func DecryptDEK(client *golangsdk.ServiceClient, opts DecryptDEKOptsBuilder) (r DecryptDEKResult) { + b, err := opts.ToDecryptDEKMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = client.Post(DecryptDEKURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type DecryptDataOpts struct { + + // Ciphertext of encrypted data. The value is the value in the data encryption result that matches the regular expression . + CipherText string `json:"cipher_text,"` + + // The value of this parameter must be a series of "key:value" pairs used to record resource context information. The value of this parameter must not contain sensitive information and must be within 8192 characters in length. + EncryptionContext string `json:"encryption_context,omitempty"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type DecryptDataOptsBuilder interface { + ToDecryptDataMap() (map[string]interface{}, error) +} + +func (opts DecryptDataOpts) ToDecryptDataMap() (map[string]interface{}, error) { + b, err := golangsdk.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + return b, nil +} + +func DecryptData(client *golangsdk.ServiceClient, opts DecryptDataOptsBuilder) (r DecryptDataResult) { + b, err := opts.ToDecryptDataMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = client.Post(DecryptDataURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type EncryptDEKOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // The value of this parameter must be a series of "key:value" pairs used to record resource context information. The value of this parameter must not contain sensitive information and must be within 8192 characters in length. Example: {"Key1":"Value1","Key2":"Value2"} + EncryptionContext string `json:"encryption_context,omitempty"` + + // Both the plaintext (64 bytes) of a DEK and the SHA-256 hash value (32 bytes) of the plaintext are expressed as a hexadecimal character string. + PlainText string `json:"plain_text,"` + + // Number of bytes of the plaintext of a DEK (The maximum number is 64.) + DatakeyPlainLength string `json:"datakey_plain_length,"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type EncryptDEKOptsBuilder interface { + ToEncryptDEKMap() (map[string]interface{}, error) +} + +func (opts EncryptDEKOpts) ToEncryptDEKMap() (map[string]interface{}, error) { + b, err := golangsdk.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + return b, nil +} + +func EncryptDEK(client *golangsdk.ServiceClient, opts EncryptDEKOptsBuilder) (r EncryptDEKResult) { + b, err := opts.ToEncryptDEKMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = client.Post(EncryptDEKURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type EncryptDataOpts struct { + + // 36-byte ID of a CMK that matches the regular expression ^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$ Example: 0d0466b0-e727-4d9c-b35d-f84bb474a37f + KeyId string `json:"key_id,"` + + // The value of this parameter must be a series of "key:value" pairs used to record resource context information. The value of this parameter must not contain sensitive information and must be within 8192 characters in length. Example: {"Key1":"Value1","Key2":"Value2"} + EncryptionContext string `json:"encryption_context,omitempty"` + + // Plaintext data which is 1 to 4096 bytes in length and matches the regular expression . After being converted into a byte array, it is still 1 to 4096 bytes in length. + PlainText string `json:"plain_text,"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type EncryptDataOptsBuilder interface { + ToEncryptDataMap() (map[string]interface{}, error) +} + +func (opts EncryptDataOpts) ToEncryptDataMap() (map[string]interface{}, error) { + b, err := golangsdk.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + return b, nil +} + +func EncryptData(client *golangsdk.ServiceClient, opts EncryptDataOptsBuilder) (r EncryptDataResult) { + b, err := opts.ToEncryptDataMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = client.Post(EncryptDataURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +type GenerateRandomStringOpts struct { + + // Number of bits of a random number (The maximum length of a random number is 512 bits.) + RandomDataLength string `json:"random_data_length,"` + + // 36-byte serial number of a request message. Example: 919c82d4-8046-4722-9094-35c3c6524cff. + Sequence string `json:"sequence,omitempty"` +} + +type GenerateRandomStringOptsBuilder interface { + ToGenerateRandomStringMap() (map[string]interface{}, error) +} + +func (opts GenerateRandomStringOpts) ToGenerateRandomStringMap() (map[string]interface{}, error) { + b, err := golangsdk.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + return b, nil +} + +func GenerateRandomString(client *golangsdk.ServiceClient, opts GenerateRandomStringOptsBuilder) (r GenerateRandomStringResult) { + b, err := opts.ToGenerateRandomStringMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = client.Post(GenerateRandomStringURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} diff --git a/openstack/kms/v1/crypto/results.go b/openstack/kms/v1/crypto/results.go new file mode 100644 index 000000000..6a099b04a --- /dev/null +++ b/openstack/kms/v1/crypto/results.go @@ -0,0 +1,148 @@ +package crypto + +import ( + "github.com/huaweicloud/golangsdk" +) + +type commonResult struct { + golangsdk.Result +} + +type CreateDEKResult struct { + commonResult +} + +func (r CreateDEKResult) Extract() (*CreateDEKResponse, error) { + var response CreateDEKResponse + err := r.ExtractInto(&response) + return &response, err +} + +type CreateDEKResponse struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // The plaintext of a DEK is expressed in hexadecimal format, and two characters indicate one byte. + PlainText string `json:"plain_text,"` + + // The ciphertext of a DEK is expressed in hexadecimal format, and two characters indicate one byte. + CipherText string `json:"cipher_text,"` +} + +type CreateDEKWithoutPlainTextResult struct { + commonResult +} + +func (r CreateDEKWithoutPlainTextResult) Extract() (*CreateDEKWithoutPlainTextResponse, error) { + var response CreateDEKWithoutPlainTextResponse + err := r.ExtractInto(&response) + return &response, err +} + +type CreateDEKWithoutPlainTextResponse struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // The ciphertext of a DEK is expressed in hexadecimal format, and two characters indicate one byte. + CipherText string `json:"cipher_text,"` +} + +type DecryptDEKResult struct { + commonResult +} + +func (r DecryptDEKResult) Extract() (*DecryptDEKResponse, error) { + var response DecryptDEKResponse + err := r.ExtractInto(&response) + return &response, err +} + +type DecryptDEKResponse struct { + + // Hexadecimal character string of the plaintext of a DEK + DataKey string `json:"data_key,"` + + // Number of bytes in the length of the plaintext of a DEK + DatakeyLength string `json:"datakey_length,"` + + // Hexadecimal character string corresponding to the SHA-256 hash value of the plaintext of a DEK + DatakeyDgst string `json:"datakey_dgst,"` +} + +type DecryptDataResult struct { + commonResult +} + +func (r DecryptDataResult) Extract() (*DecryptDataResponse, error) { + var response DecryptDataResponse + err := r.ExtractInto(&response) + return &response, err +} + +type DecryptDataResponse struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // Plaintext of data + PlainText string `json:"plain_text,"` +} + +type EncryptDEKResult struct { + commonResult +} + +func (r EncryptDEKResult) Extract() (*EncryptDEKResponse, error) { + var response EncryptDEKResponse + err := r.ExtractInto(&response) + return &response, err +} + +type EncryptDEKResponse struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // The ciphertext of a DEK is expressed in hexadecimal format, and two characters indicate one byte. + CipherText string `json:"cipher_text,"` + + // Number of bytes in the length of a DEK + DatakeyLength string `json:"datakey_length,"` +} + +type EncryptDataResult struct { + commonResult +} + +func (r EncryptDataResult) Extract() (*EncryptDataResponse, error) { + var response EncryptDataResponse + err := r.ExtractInto(&response) + return &response, err +} + +type EncryptDataResponse struct { + + // ID of a CMK + KeyId string `json:"key_id,"` + + // Ciphertext data in Base64 format + CipherText string `json:"cipher_text,"` +} + +type GenerateRandomStringResult struct { + commonResult +} + +func (r GenerateRandomStringResult) Extract() (*GenerateRandomStringResponse, error) { + var response GenerateRandomStringResponse + err := r.ExtractInto(&response) + return &response, err +} + +type GenerateRandomStringResponse struct { + + // Random numbers are expressed in hexadecimal format. Two characters indicate one byte. Length of a random number must be consistent with the value entered by a user. + RandomData string `json:"random_data,"` +} diff --git a/openstack/kms/v1/crypto/testing/doc.go b/openstack/kms/v1/crypto/testing/doc.go new file mode 100644 index 000000000..7603f836a --- /dev/null +++ b/openstack/kms/v1/crypto/testing/doc.go @@ -0,0 +1 @@ +package testing diff --git a/openstack/kms/v1/crypto/testing/fixtures.go b/openstack/kms/v1/crypto/testing/fixtures.go new file mode 100644 index 000000000..f3eb000e6 --- /dev/null +++ b/openstack/kms/v1/crypto/testing/fixtures.go @@ -0,0 +1,166 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + + "github.com/huaweicloud/golangsdk/openstack/kms/v1/crypto" + + th "github.com/huaweicloud/golangsdk/testhelper" + "github.com/huaweicloud/golangsdk/testhelper/client" +) + +var CreateDEKOutput = ` +{ + "key_id": "e966a300-0c34-4a31-86e1-e67d13e6426a", + "plain_text": "24570315c5c496f51882abc923430549eb0661fdb387953afc4d3f476d0fab21a90ccbdfabfd6b4f19aaf9c4bec3707cac96f55c4f573a75c8e95b53abf5023c", + "cipher_text": "02009800c959d21a80123c067ef4bedd126f1959cb86de1aa16ca547c68149e03a631f108e7282219bea130b627c2772726685d1368f4ae3657e4bd5bad8a485ee1f5bac18329b33896c37ea72952e1505765b61c4e4d18f577fb3339b52cfebe19dc387cc38a15fd529b77c19ffed7f02ff583f65393636613330302d306333342d346133312d383665312d65363764313365363432366100000000c622f77e48e630a955feb2686acfd7ea0b9de94dbd537a6a552032bd579e1895" +} +` + +var CreateDEKResponse = crypto.CreateDEKResponse{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + PlainText: "24570315c5c496f51882abc923430549eb0661fdb387953afc4d3f476d0fab21a90ccbdfabfd6b4f19aaf9c4bec3707cac96f55c4f573a75c8e95b53abf5023c", + CipherText: "02009800c959d21a80123c067ef4bedd126f1959cb86de1aa16ca547c68149e03a631f108e7282219bea130b627c2772726685d1368f4ae3657e4bd5bad8a485ee1f5bac18329b33896c37ea72952e1505765b61c4e4d18f577fb3339b52cfebe19dc387cc38a15fd529b77c19ffed7f02ff583f65393636613330302d306333342d346133312d383665312d65363764313365363432366100000000c622f77e48e630a955feb2686acfd7ea0b9de94dbd537a6a552032bd579e1895", +} + +func HandleCreateDEKSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/create-datakey", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, CreateDEKOutput) + }) +} + +var CreateDEKWithoutPlainTextOutput = ` +{ + "key_id": "e966a300-0c34-4a31-86e1-e67d13e6426a", + "cipher_text": "02009800c959d21a80123c067ef4bedd126f1959cb86de1aa16ca547c68149e03a631f108e7282219bea130b627c2772726685d1368f4ae3657e4bd5bad8a485ee1f5bac18329b33896c37ea72952e1505765b61c4e4d18f577fb3339b52cfebe19dc387cc38a15fd529b77c19ffed7f02ff583f65393636613330302d306333342d346133312d383665312d65363764313365363432366100000000c622f77e48e630a955feb2686acfd7ea0b9de94dbd537a6a552032bd579e1895" +} +` + +var CreateDEKWithoutPlainTextResponse = crypto.CreateDEKWithoutPlainTextResponse{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + CipherText: "02009800c959d21a80123c067ef4bedd126f1959cb86de1aa16ca547c68149e03a631f108e7282219bea130b627c2772726685d1368f4ae3657e4bd5bad8a485ee1f5bac18329b33896c37ea72952e1505765b61c4e4d18f577fb3339b52cfebe19dc387cc38a15fd529b77c19ffed7f02ff583f65393636613330302d306333342d346133312d383665312d65363764313365363432366100000000c622f77e48e630a955feb2686acfd7ea0b9de94dbd537a6a552032bd579e1895", +} + +func HandleCreateWithoutPlainTextSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/create-datakey-without-plaintext", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, CreateDEKWithoutPlainTextOutput) + }) +} + +var EncryptDataOutput = ` +{ + "key_id": "e966a300-0c34-4a31-86e1-e67d13e6426a", + "cipher_text": "AgBoADOno72EHR/JjaUrSX7IKbS11ARcP0ZvqR/izGq+eSMqGlfN8QT3om5xbgoeJ4nfeC5n8bxo2XGoAIpcJaiYzj9lOTY2YTMwMC0wYzM0LTRhMzEtODZlMS1lNjdkMTNlNjQyNmEAAAAAoufe9kr8XlgVUSamOMOtsOIpw0Shy1pF1GnL2Wreobo=" +} +` + +var EncryptDataResponse = crypto.EncryptDataResponse{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + CipherText: "AgBoADOno72EHR/JjaUrSX7IKbS11ARcP0ZvqR/izGq+eSMqGlfN8QT3om5xbgoeJ4nfeC5n8bxo2XGoAIpcJaiYzj9lOTY2YTMwMC0wYzM0LTRhMzEtODZlMS1lNjdkMTNlNjQyNmEAAAAAoufe9kr8XlgVUSamOMOtsOIpw0Shy1pF1GnL2Wreobo=", +} + +func HandleEncryptDataSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/encrypt-data", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, EncryptDataOutput) + }) +} + +var DecryptDataOutput = ` +{ + "key_id":"e966a300-0c34-4a31-86e1-e67d13e6426a", + "plain_text":"ABC" +} +` + +var DecryptDataResponse = crypto.DecryptDataResponse{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + PlainText: "ABC", +} + +func HandleDecryptDataSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/decrypt-data", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, DecryptDataOutput) + }) +} + +var EncryptDEKOutput = ` +{ + "key_id": "e966a300-0c34-4a31-86e1-e67d13e6426a", + "cipher_text": "AgBoADOno72EHR/JjaUrSX7IKbS11ARcP0ZvqR/izGq+eSMqGlfN8QT3om5xbgoeJ4nfeC5n8bxo2XGoAIpcJaiYzj9lOTY2YTMwMC0wYzM0LTRhMzEtODZlMS1lNjdkMTNlNjQyNmEAAAAAoufe9kr8XlgVUSamOMOtsOIpw0Shy1pF1GnL2Wreobo=" +} +` + +var EncryptDEKResponse = crypto.EncryptDEKResponse{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + CipherText: "AgBoADOno72EHR/JjaUrSX7IKbS11ARcP0ZvqR/izGq+eSMqGlfN8QT3om5xbgoeJ4nfeC5n8bxo2XGoAIpcJaiYzj9lOTY2YTMwMC0wYzM0LTRhMzEtODZlMS1lNjdkMTNlNjQyNmEAAAAAoufe9kr8XlgVUSamOMOtsOIpw0Shy1pF1GnL2Wreobo=", +} + +func HandleEncryptDEKSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/encrypt-datakey", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, EncryptDEKOutput) + }) +} + +var DecryptDEKOutput = ` +{ + "data_key":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "datakey_length":"64", + "datakey_dgst":"f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b" +} +` + +var DecryptDEKResponse = crypto.DecryptDEKResponse{ + DataKey: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + DatakeyLength: "64", + DatakeyDgst: "f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", +} + +func HandleDecryptDEKSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/decrypt-datakey", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, DecryptDEKOutput) + }) +} + +var GenerateRandomStringOutput = ` +{"random_data":"e9b6bc9e7223390eb16f220e4f4be8741b1e936bd52b4347a52f689e485d939e91b78e31be39c04a57c2ac7d24678c1805619704768af45dcfca028fe83e650c"} +` + +var GenerateRandomStringResponse = crypto.GenerateRandomStringResponse{ + RandomData: "e9b6bc9e7223390eb16f220e4f4be8741b1e936bd52b4347a52f689e485d939e91b78e31be39c04a57c2ac7d24678c1805619704768af45dcfca028fe83e650c", +} + +func HandleGenerateRandomStringSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/kms/gen-random", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, GenerateRandomStringOutput) + }) +} diff --git a/openstack/kms/v1/crypto/testing/requests_test.go b/openstack/kms/v1/crypto/testing/requests_test.go new file mode 100644 index 000000000..c138c6e89 --- /dev/null +++ b/openstack/kms/v1/crypto/testing/requests_test.go @@ -0,0 +1,107 @@ +package testing + +import ( + "testing" + + "github.com/huaweicloud/golangsdk/openstack/kms/v1/crypto" + th "github.com/huaweicloud/golangsdk/testhelper" + "github.com/huaweicloud/golangsdk/testhelper/client" +) + +func TestCreateDEK(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleCreateDEKSuccessfully(t) + + actual, err := crypto.CreateDEK(client.ServiceClient(), crypto.CreateDEKOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + DatakeyLength: "512", + }).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &CreateDEKResponse, actual) +} + +func TestCreateDEKWithoutPlainText(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleCreateWithoutPlainTextSuccessfully(t) + + actual, err := crypto.CreateDEKWithoutPlainText(client.ServiceClient(), crypto.CreateDEKWithoutPlainTextOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + DatakeyLength: "512", + }).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &CreateDEKWithoutPlainTextResponse, actual) +} + +func TestEncryptData(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleEncryptDataSuccessfully(t) + + actual, err := crypto.EncryptData(client.ServiceClient(), crypto.EncryptDataOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + PlainText: "ABC", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &EncryptDataResponse, actual) +} + +func TestDecryptData(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleDecryptDataSuccessfully(t) + + actual, err := crypto.DecryptData(client.ServiceClient(), crypto.DecryptDataOpts{ + CipherText: "AgBoAAwOOx+Gi8JbPOvSA0tWgxC11ARcP0ZvqR/izGq+eSMqGlfN8QT3om5xbgoeJ4nfeGK0wcyyvRmpSLvhOyw6J3ZlOTY2YTMwMC0wYzM0LTRhMzEtODZlMS1lNjdkMTNlNjQyNmEAAAAA/XZGoJQFDcRsMwBxoSBuFGb6BwYULbGPN4352ZyZyGw=", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &DecryptDataResponse, actual) +} + +func TestEncryptDEK(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleEncryptDEKSuccessfully(t) + + actual, err := crypto.EncryptDEK(client.ServiceClient(), crypto.EncryptDEKOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + PlainText: "ABC", + DatakeyPlainLength: "64", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &EncryptDEKResponse, actual) +} + +func TestDecryptDEK(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleDecryptDEKSuccessfully(t) + + actual, err := crypto.DecryptDEK(client.ServiceClient(), crypto.DecryptDEKOpts{ + KeyId: "e966a300-0c34-4a31-86e1-e67d13e6426a", + CipherText: "0200980044f1f74e59884b4259ecfdd9149861c93219107895d3aca3afb5ba68991d13679db3736e820d75a17309535b14d6d12796eac84dc4e826ec15ee7db38df0fdb4e97e6c9991f4f043e878387db6d3d48946799f056a8bb9b1952cd73dd1548f2b3939e209df341dd028cb4306925ade0b65393636613330302d306333342d346133312d383665312d65363764313365363432366100000000b90c13a32b15375fbb0f14d6bec4b45d96a328afdb1258747c489e6dbb28a897", + DatakeyCipherLength: "64", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &DecryptDEKResponse, actual) +} + +func TestGenerateRandomString(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleGenerateRandomStringSuccessfully(t) + + actual, err := crypto.GenerateRandomString(client.ServiceClient(), crypto.GenerateRandomStringOpts{ + RandomDataLength: "512", + Sequence: "919c82d4-8046-4722-9094-35c3c6524cff", + }).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &GenerateRandomStringResponse, actual) +} diff --git a/openstack/kms/v1/crypto/url.go b/openstack/kms/v1/crypto/url.go new file mode 100644 index 000000000..88cdeaf69 --- /dev/null +++ b/openstack/kms/v1/crypto/url.go @@ -0,0 +1,33 @@ +package crypto + +import ( + "github.com/huaweicloud/golangsdk" +) + +func CreateDEKURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "create-datakey") +} + +func CreateDEKWithoutPlainTextURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "create-datakey-without-plaintext") +} + +func DecryptDEKURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "decrypt-datakey") +} + +func DecryptDataURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "decrypt-data") +} + +func EncryptDEKURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "encrypt-datakey") +} + +func EncryptDataURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "encrypt-data") +} + +func GenerateRandomStringURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("kms", "gen-random") +} diff --git a/openstack/kms/v1/keys/doc.go b/openstack/kms/v1/keys/doc.go deleted file mode 100644 index 9832dcd72..000000000 --- a/openstack/kms/v1/keys/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Package keys provides information and interaction with keys in the -// Key Management Service service. The customer master keys (CMKs) used -// to encrypt data encryption keys (DEKs) -package keys diff --git a/openstack/kms/v1/keys/requests.go b/openstack/kms/v1/keys/requests.go deleted file mode 100644 index e7ebb8a55..000000000 --- a/openstack/kms/v1/keys/requests.go +++ /dev/null @@ -1,296 +0,0 @@ -package keys - -import ( - "github.com/huaweicloud/golangsdk" - //"github.com/huaweicloud/golangsdk/pagination" -) - -type CreateOpts struct { - // Alias of a CMK - KeyAlias string `json:"key_alias" required:"true"` - // CMK description - KeyDescription string `json:"key_description,omitempty"` - // Region where a CMK resides - Realm string `json:"realm,omitempty"` - // Purpose of a CMK (The default value is Encrypt_Decrypt) - KeyUsage string `json:"key_usage,omitempty"` -} - -type DeleteOpts struct { - // ID of a CMK - KeyID string `json:"key_id" required:"true"` - // Number of days after which a CMK is scheduled to be deleted - // (The value ranges from 7 to 1096.) - PendingDays string `json:"pending_days" required:"true"` -} - -type UpdateAliasOpts struct { - // ID of a CMK - KeyID string `json:"key_id" required:"true"` - // CMK description - KeyAlias string `json:"key_alias" required:"true"` -} - -type UpdateDesOpts struct { - // ID of a CMK - KeyID string `json:"key_id" required:"true"` - // CMK description - KeyDescription string `json:"key_description" required:"true"` -} - -type DataEncryptOpts struct { - // ID of a CMK - KeyID string `json:"key_id" required:"true"` - // CMK description - EncryptionContext string `json:"encryption_context,omitempty"` - // 36-byte serial number of a request message - DatakeyLength string `json:"datakey_length,omitempty"` -} - -type EncryptDEKOpts struct { - // ID of a CMK - KeyID string `json:"key_id" required:"true"` - // CMK description - EncryptionContext string `json:"encryption_context,omitempty"` - // 36-byte serial number of a request message - DataKeyPlainLength string `json:"datakey_plain_length,omitempty"` - // Both the plaintext (64 bytes) of a DEK and the SHA-256 hash value (32 bytes) - // of the plaintext are expressed as a hexadecimal character string. - PlainText string `json:"plain_text" required:"true"` -} - -// ListOpts holds options for listing Volumes. It is passed to the volumes.List -// function. -type ListOpts struct { - // State of a CMK - KeyState string `json:"key_state,omitempty"` - Limit string `json:"limit,omitempty"` - Marker string `json:"marker,omitempty"` -} - -// ToKeyCreateMap assembles a request body based on the contents of a -// CreateOpts. -func (opts CreateOpts) ToKeyCreateMap() (map[string]interface{}, error) { - return golangsdk.BuildRequestBody(opts, "") -} - -// ToKeyDeleteMap assembles a request body based on the contents of a -// DeleteOpts. -func (opts DeleteOpts) ToKeyDeleteMap() (map[string]interface{}, error) { - return golangsdk.BuildRequestBody(opts, "") -} - -// ToKeyUpdateAliasMap assembles a request body based on the contents of a -// UpdateAliasOpts. -func (opts UpdateAliasOpts) ToKeyUpdateAliasMap() (map[string]interface{}, error) { - return golangsdk.BuildRequestBody(opts, "") -} - -// ToKeyUpdateDesMap assembles a request body based on the contents of a -// UpdateDesOpts. -func (opts UpdateDesOpts) ToKeyUpdateDesMap() (map[string]interface{}, error) { - return golangsdk.BuildRequestBody(opts, "") -} - -func (opts DataEncryptOpts) ToDataEncryptMap() (map[string]interface{}, error) { - return golangsdk.BuildRequestBody(opts, "") -} - -func (opts EncryptDEKOpts) ToEncryptDEKMap() (map[string]interface{}, error) { - return golangsdk.BuildRequestBody(opts, "") -} - -func (opts ListOpts) ToKeyListMap() (map[string]interface{}, error) { - return golangsdk.BuildRequestBody(opts, "") -} - -type CreateOptsBuilder interface { - ToKeyCreateMap() (map[string]interface{}, error) -} - -type DeleteOptsBuilder interface { - ToKeyDeleteMap() (map[string]interface{}, error) -} - -type UpdateAliasOptsBuilder interface { - ToKeyUpdateAliasMap() (map[string]interface{}, error) -} - -type UpdateDesOptsBuilder interface { - ToKeyUpdateDesMap() (map[string]interface{}, error) -} - -type DataEncryptOptsBuilder interface { - ToDataEncryptMap() (map[string]interface{}, error) -} - -type EncryptDEKOptsBuilder interface { - ToEncryptDEKMap() (map[string]interface{}, error) -} - -type ListOptsBuilder interface { - ToKeyListMap() (map[string]interface{}, error) -} - -// Create will create a new key based on the values in CreateOpts. To ExtractKeyInfo -// the key object from the response, call the ExtractKeyInfo method on the -// CreateResult. -func Create(client *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToKeyCreateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(createURL(client), b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// Get retrieves the key with the provided ID. To extract the key object -// from the response, call the Extract method on the GetResult. -func Get(client *golangsdk.ServiceClient, id string) (r GetResult) { - b := map[string]interface{}{"key_id": id} - _, r.Err = client.Post(getURL(client), &b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// Delete will delete the existing key with the provided ID. -func Delete(client *golangsdk.ServiceClient, opts DeleteOptsBuilder) (r DeleteResult) { - b, err := opts.ToKeyDeleteMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(deleteURL(client), b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - JSONResponse: &r.Body, - }) - return -} - -func UpdateAlias(client *golangsdk.ServiceClient, opts UpdateAliasOptsBuilder) (r UpdateAliasResult) { - b, err := opts.ToKeyUpdateAliasMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(updateAliasURL(client), b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -func UpdateDes(client *golangsdk.ServiceClient, opts UpdateDesOptsBuilder) (r UpdateDesResult) { - b, err := opts.ToKeyUpdateDesMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(updateDesURL(client), b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -func DataEncryptGet(client *golangsdk.ServiceClient, opts DataEncryptOptsBuilder) (r DataEncryptResult) { - b, err := opts.ToDataEncryptMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(dataEncryptURL(client), b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -func DataEncryptGetWithoutPlaintext(client *golangsdk.ServiceClient, opts DataEncryptOptsBuilder) (r DataEncryptResult) { - b, err := opts.ToDataEncryptMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(dataEncryptURL(client), b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -func EncryptDEKGet(client *golangsdk.ServiceClient, opts EncryptDEKOptsBuilder) (r EncryptDEKResult) { - b, err := opts.ToEncryptDEKMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(encryptDEKURL(client), b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -func EnableKey(client *golangsdk.ServiceClient, id string) (r ExtractUpdateKeyStateResult) { - b := map[string]interface{}{"key_id": id} - _, r.Err = client.Post(enableKeyURL(client), b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -func DisableKey(client *golangsdk.ServiceClient, id string) (r ExtractUpdateKeyStateResult) { - b := map[string]interface{}{"key_id": id} - _, r.Err = client.Post(disableKeyURL(client), b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -func List(client *golangsdk.ServiceClient, opts ListOptsBuilder) (r ListResult) { - b, err := opts.ToKeyListMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(listURL(client), b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -func ListAllKeys(client *golangsdk.ServiceClient, opts ListOptsBuilder) (r ListResult) { - b, err := opts.ToKeyListMap() - if err != nil { - r.Err = err - return - } - _, r.Err = client.Post(listURL(client), b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -//func List(client *golangsdk.ServiceClient, opts ListOptsBuilder) (r GetResult) { -// //url := listURL(client) -// //if opts != nil { -// // query, err := opts.ToKeyListQuery() -// // if err != nil { -// // return pagination.Pager{Err: err} -// // } -// // url += query -// //} -// b, err := opts.ToKeyListQuery() -// if err != nil { -// r.Err = err -// return -// } -// _, r.Err = client.Post(listURL(client), b, &r.Body, &golangsdk.RequestOpts{ -// OkCodes: []int{200}, -// }) -// return -// -// //return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { -// // return KeyPage{pagination.LinkedPageBase{PageResult: r}} -// //}) -//} diff --git a/openstack/kms/v1/keys/results.go b/openstack/kms/v1/keys/results.go deleted file mode 100644 index 23f161882..000000000 --- a/openstack/kms/v1/keys/results.go +++ /dev/null @@ -1,157 +0,0 @@ -package keys - -import ( - "github.com/huaweicloud/golangsdk" - "github.com/huaweicloud/golangsdk/pagination" -) - -type commonResult struct { - golangsdk.Result -} - -// Key contains all the information associated with a CMK. -type Key struct { - // Current ID of a CMK - KeyID string `json:"key_id"` - // ID of a user domain for the key. - DomainID string `json:"domain_id"` - // Alias of a CMK - KeyAlias string `json:"key_alias"` - // Region where a CMK resides - Realm string `json:"realm"` - // Description of a CMK - KeyDescription string `json:"key_description"` - // Creation time (time stamp) of a CMK - CreationDate string `json:"creation_date"` - // Scheduled deletion time (time stamp) of a CMK - ScheduledDeletionDate string `json:"scheduled_deletion_date"` - // State of a CMK - KeyState string `json:"key_state"` - // Identification of a Master Key. The value 1 indicates a Default - // Master Key, and the value 0 indicates a CMK - DefaultKeyFlag string `json:"default_key_flag"` - // Expiration time - ExpirationTime string `json:"expiration_time"` - // Origin of a CMK. The default value is kms. The following values - // are enumerated: kms indicates that the CMK material is generated by KMS. - Origin string `json:"origin"` -} - -type ListKey struct { - Keys []string `json:"keys"` - KeyDetails []Key `json:"key_details"` - NextMarker string `json:"next_marker"` - Truncated string `json:"truncated"` -} - -type DataKey struct { - // Current ID of a CMK - KeyID string `json:"key_id"` - PlainText string `json:"plain_text"` - CipherText string `json:"cipher_text"` -} - -type EncryptDEK struct { - // Current ID of a CMK - KeyID string `json:"key_id"` - DataKeyLength string `json:"datakey_length"` - CipherText string `json:"cipher_text"` -} - -type UpdateKeyState struct { - // Current ID of a CMK - KeyID string `json:"key_id"` - KeyState string `json:"key_state"` -} - -// CreateResult contains the response body and error from a Create request. -type CreateResult struct { - commonResult -} - -// GetResult contains the response body and error from a Get request. -type GetResult struct { - commonResult -} - -// DeleteResult contains the response body and error from a Delete request. -type DeleteResult struct { - commonResult -} - -// UpdateAliasResult contains the response body and error from a UpdateAlias request. -type UpdateAliasResult struct { - commonResult -} - -// UpdateDesResult contains the response body and error from a UpdateDes request. -type UpdateDesResult struct { - commonResult -} - -type DataEncryptResult struct { - commonResult -} - -type EncryptDEKResult struct { - commonResult -} - -type ExtractUpdateKeyStateResult struct { - commonResult -} - -type ListResult struct { - commonResult -} - -func (r commonResult) ExtractListKey() (*ListKey, error) { - var s *ListKey - err := r.ExtractInto(&s) - return s, err -} - -func (r commonResult) Extract() (*Key, error) { - var s *Key - err := r.ExtractInto(&s) - return s, err -} - -func (r commonResult) ExtractKeyInfo() (*Key, error) { - var s Key - err := r.ExtractKeyInfoInto(&s) - return &s, err -} - -func (r commonResult) ExtractKeyInfoInto(v interface{}) error { - return r.Result.ExtractIntoStructPtr(v, "key_info") -} - -func (r commonResult) ExtractDataKey() (*DataKey, error) { - var s *DataKey - err := r.ExtractInto(&s) - return s, err -} - -func (r commonResult) ExtractEncryptDEK() (*EncryptDEK, error) { - var s *EncryptDEK - err := r.ExtractInto(&s) - return s, err -} - -type KeyPage struct { - pagination.LinkedPageBase -} - -func (r KeyPage) IsEmpty() (bool, error) { - s, err := ExtractKeys(r) - return len(s) == 0, err -} - -func ExtractKeys(r pagination.Page) ([]Key, error) { - var s struct { - Keys []Key `json:"keys"` - } - err := (r.(KeyPage)).ExtractInto(&s) - return s.Keys, err -} diff --git a/openstack/kms/v1/keys/urls.go b/openstack/kms/v1/keys/urls.go deleted file mode 100644 index 8ef2dde92..000000000 --- a/openstack/kms/v1/keys/urls.go +++ /dev/null @@ -1,47 +0,0 @@ -package keys - -import "github.com/huaweicloud/golangsdk" - -const ( - resourcePath = "kms" -) - -func getURL(c *golangsdk.ServiceClient) string { - return c.ServiceURL(c.ProjectID, resourcePath, "describe-key") -} - -func createURL(c *golangsdk.ServiceClient) string { - return c.ServiceURL(c.ProjectID, resourcePath, "create-key") -} - -func deleteURL(c *golangsdk.ServiceClient) string { - return c.ServiceURL(c.ProjectID, resourcePath, "schedule-key-deletion") -} - -func updateAliasURL(c *golangsdk.ServiceClient) string { - return c.ServiceURL(c.ProjectID, resourcePath, "update-key-alias") -} - -func updateDesURL(c *golangsdk.ServiceClient) string { - return c.ServiceURL(c.ProjectID, resourcePath, "update-key-description") -} - -func dataEncryptURL(c *golangsdk.ServiceClient) string { - return c.ServiceURL(c.ProjectID, resourcePath, "create-datakey") -} - -func encryptDEKURL(c *golangsdk.ServiceClient) string { - return c.ServiceURL(c.ProjectID, resourcePath, "encrypt-datakey") -} - -func enableKeyURL(c *golangsdk.ServiceClient) string { - return c.ServiceURL(c.ProjectID, resourcePath, "enable-key") -} - -func disableKeyURL(c *golangsdk.ServiceClient) string { - return c.ServiceURL(c.ProjectID, resourcePath, "disable-key") -} - -func listURL(c *golangsdk.ServiceClient) string { - return c.ServiceURL(c.ProjectID, resourcePath, "list-keys") -} diff --git a/openstack/testing/endpoint_location_test.go b/openstack/testing/endpoint_location_test.go index 7d743b5b9..729f81145 100644 --- a/openstack/testing/endpoint_location_test.go +++ b/openstack/testing/endpoint_location_test.go @@ -80,8 +80,28 @@ func TestV2EndpointExact(t *testing.T) { } } +func TestV2EndpointExactNonExist(t *testing.T) { + expectedURLs := map[golangsdk.Availability]string{ + golangsdk.AvailabilityPublic: "https://none.same.correct.com/", + golangsdk.AvailabilityAdmin: "https://none.same.correct.com/", + golangsdk.AvailabilityInternal: "https://none.same.correct.com/", + } + + for availability, expected := range expectedURLs { + actual, err := openstack.V2EndpointURL(&catalog2, golangsdk.EndpointOpts{ + Type: "none", + Name: "same", + Region: "same", + Availability: availability, + }) + th.AssertNoErr(t, err) + th.CheckEquals(t, expected, actual) + } +} + func TestV2EndpointNone(t *testing.T) { - _, actual := openstack.V2EndpointURL(&catalog2, golangsdk.EndpointOpts{ + _, actual := openstack.V2EndpointURL(&tokens2.ServiceCatalog{ + Entries: []tokens2.CatalogEntry{}}, golangsdk.EndpointOpts{ Type: "nope", Availability: golangsdk.AvailabilityPublic, }) @@ -200,8 +220,28 @@ func TestV3EndpointExact(t *testing.T) { } } +func TestV3EndpointExactNonExist(t *testing.T) { + expectedURLs := map[golangsdk.Availability]string{ + golangsdk.AvailabilityPublic: "https://none.same.correct.com/", + golangsdk.AvailabilityAdmin: "https://none.same.correct.com/", + golangsdk.AvailabilityInternal: "https://none.same.correct.com/", + } + + for availability, expected := range expectedURLs { + actual, err := openstack.V3EndpointURL(&catalog3, golangsdk.EndpointOpts{ + Type: "none", + Name: "same", + Region: "same", + Availability: availability, + }) + th.AssertNoErr(t, err) + th.CheckEquals(t, expected, actual) + } +} + func TestV3EndpointNone(t *testing.T) { - _, actual := openstack.V3EndpointURL(&catalog3, golangsdk.EndpointOpts{ + _, actual := openstack.V3EndpointURL(&tokens3.ServiceCatalog{ + Entries: []tokens3.CatalogEntry{}}, golangsdk.EndpointOpts{ Type: "nope", Availability: golangsdk.AvailabilityPublic, }) diff --git a/postpagination/http.go b/postpagination/http.go new file mode 100644 index 000000000..f612b4a5e --- /dev/null +++ b/postpagination/http.go @@ -0,0 +1,67 @@ +package postpagination + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "github.com/huaweicloud/golangsdk" +) + +// PageResult stores the HTTP response that returned the current page of results. +type PageResult struct { + golangsdk.Result + url.URL +} + +// PageResultFrom parses an HTTP response as JSON and returns a PageResult containing the +// results, interpreting it as JSON if the content type indicates. +func PageResultFrom(resp *http.Response) (PageResult, error) { + var parsedBody interface{} + + defer resp.Body.Close() + rawBody, err := ioutil.ReadAll(resp.Body) + if err != nil { + return PageResult{}, err + } + + if strings.HasPrefix(resp.Header.Get("Content-Type"), "application/json") { + err = json.Unmarshal(rawBody, &parsedBody) + if err != nil { + return PageResult{}, err + } + } else { + parsedBody = rawBody + } + + return PageResultFromParsed(resp, parsedBody), err +} + +// PageResultFromParsed constructs a PageResult from an HTTP response that has already had its +// body parsed as JSON (and closed). +func PageResultFromParsed(resp *http.Response, body interface{}) PageResult { + return PageResult{ + Result: golangsdk.Result{ + Body: body, + Header: resp.Header, + }, + URL: *resp.Request.URL, + } +} + +// Request performs an HTTP request and extracts the http.Response from the result. +func Request(client *golangsdk.ServiceClient, method string, request interface{}, headers map[string]string, url string) (*http.Response, error) { + if method == "POST" { + return client.Post(url, request, nil, &golangsdk.RequestOpts{ + MoreHeaders: headers, + OkCodes: []int{200, 204, 300}, + }) + } else { + return client.Get(url, nil, &golangsdk.RequestOpts{ + MoreHeaders: headers, + OkCodes: []int{200, 204, 300}, + }) + } +} diff --git a/postpagination/linked.go b/postpagination/linked.go new file mode 100644 index 000000000..a4941a439 --- /dev/null +++ b/postpagination/linked.go @@ -0,0 +1,97 @@ +package postpagination + +import ( + "fmt" + "reflect" + + "github.com/huaweicloud/golangsdk" +) + +// LinkedPageBase may be embedded to implement a page that provides navigational "Next" and "Previous" links within its result. +type LinkedPageBase struct { + PageResult + + // LinkPath lists the keys that should be traversed within a response to arrive at the "next" pointer. + // If any link along the path is missing, an empty URL will be returned. + // If any link results in an unexpected value type, an error will be returned. + // When left as "nil", []string{"links", "next"} will be used as a default. + LinkPath []string +} + +// NextPageURL extracts the pagination structure from a JSON response and returns the "next" link, if one is present. +// It assumes that the links are available in a "links" element of the top-level response object. +// If this is not the case, override NextPageURL on your result type. +func (current LinkedPageBase) NextPageURL() (string, error) { + var path []string + var key string + + if current.LinkPath == nil { + path = []string{"links", "next"} + } else { + path = current.LinkPath + } + + submap, ok := current.Body.(map[string]interface{}) + if !ok { + err := golangsdk.ErrUnexpectedType{} + err.Expected = "map[string]interface{}" + err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) + return "", err + } + + for { + key, path = path[0], path[1:len(path)] + + value, ok := submap[key] + if !ok { + return "", nil + } + + if len(path) > 0 { + submap, ok = value.(map[string]interface{}) + if !ok { + err := golangsdk.ErrUnexpectedType{} + err.Expected = "map[string]interface{}" + err.Actual = fmt.Sprintf("%v", reflect.TypeOf(value)) + return "", err + } + } else { + if value == nil { + // Actual null element. + return "", nil + } + + url, ok := value.(string) + if !ok { + err := golangsdk.ErrUnexpectedType{} + err.Expected = "string" + err.Actual = fmt.Sprintf("%v", reflect.TypeOf(value)) + return "", err + } + + return url, nil + } + } +} + +// NextPageRequest generates the body for the page of results after this one. +func (current LinkedPageBase) NextPageRequest() (interface{}, error) { + return "", nil +} + +// IsEmpty satisifies the IsEmpty method of the Page interface +func (current LinkedPageBase) IsEmpty() (bool, error) { + if b, ok := current.Body.([]interface{}); ok { + return len(b) == 0, nil + } + err := golangsdk.ErrUnexpectedType{} + err.Expected = "[]interface{}" + err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) + return true, err +} + +// GetBody returns the linked page's body. This method is needed to satisfy the +// Page interface. +func (current LinkedPageBase) GetBody() interface{} { + return current.Body +} diff --git a/postpagination/marker.go b/postpagination/marker.go new file mode 100644 index 000000000..759942c7e --- /dev/null +++ b/postpagination/marker.go @@ -0,0 +1,58 @@ +package postpagination + +import ( + "fmt" + "reflect" + + "github.com/huaweicloud/golangsdk" +) + +// MarkerPage is a stricter Page interface that describes additional functionality required for use with NewMarkerPager. +// For convenience, embed the MarkedPageBase struct. +type MarkerPage interface { + Page + + // LastMarker returns the last "marker" value on this page. + LastMarker() (string, error) +} + +// MarkerPageBase is a page in a collection that's paginated by "limit" and "marker" query parameters. +type MarkerPageBase struct { + PageResult + + // Owner is a reference to the embedding struct. + Owner MarkerPage +} + +// NextPageURL generates the URL for the page of results after this one. +func (current MarkerPageBase) NextPageURL() (string, error) { + currentURL := current.URL + + mark, err := current.Owner.LastMarker() + if err != nil { + return "", err + } + + q := currentURL.Query() + q.Set("marker", mark) + currentURL.RawQuery = q.Encode() + + return currentURL.String(), nil +} + +// IsEmpty satisifies the IsEmpty method of the Page interface +func (current MarkerPageBase) IsEmpty() (bool, error) { + if b, ok := current.Body.([]interface{}); ok { + return len(b) == 0, nil + } + err := golangsdk.ErrUnexpectedType{} + err.Expected = "[]interface{}" + err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) + return true, err +} + +// GetBody returns the linked page's body. This method is needed to satisfy the +// Page interface. +func (current MarkerPageBase) GetBody() interface{} { + return current.Body +} diff --git a/postpagination/pager.go b/postpagination/pager.go new file mode 100644 index 000000000..ff54d2b68 --- /dev/null +++ b/postpagination/pager.go @@ -0,0 +1,266 @@ +package postpagination + +import ( + "errors" + "fmt" + "net/http" + "reflect" + "strings" + + "github.com/huaweicloud/golangsdk" +) + +var ( + // ErrPageNotAvailable is returned from a Pager when a next or previous page is requested, but does not exist. + ErrPageNotAvailable = errors.New("The requested page does not exist.") +) + +// Page must be satisfied by the result type of any resource collection. +// It allows clients to interact with the resource uniformly, regardless of whether or not or how it's paginated. +// Generally, rather than implementing this interface directly, implementors should embed one of the concrete PageBase structs, +// instead. +// Depending on the pagination strategy of a particular resource, there may be an additional subinterface that the result type +// will need to implement. +type Page interface { + // NextPageURL generates the URL for the page of data that follows this collection. + // Return "" if no such page exists. + NextPageURL() (string, error) + + // NextPageRequest generate the body for the page for data that follows this collection. + // Return nil if no such page exists. + NextPageRequest() (interface{}, error) + + // IsEmpty returns true if this Page has no items in it. + IsEmpty() (bool, error) + + // GetBody returns the Page Body. This is used in the `AllPages` method. + GetBody() interface{} +} + +// Pager knows how to advance through a specific resource collection, one page at a time. +type Pager struct { + client *golangsdk.ServiceClient + + method string + + initialURL string + + initialRequest interface{} + + createPage func(r PageResult) Page + + Err error + + // Headers supplies additional HTTP headers to populate on each paged request. + Headers map[string]string +} + +// NewPager constructs a manually-configured pager. +// Supply the URL for the first page, a function that requests a specific page given a URL, and a function that counts a page. +func NewPager(client *golangsdk.ServiceClient, method string, initialURL string, initialRequest interface{}, createPage func(r PageResult) Page) Pager { + return Pager{ + client: client, + method: method, + initialURL: initialURL, + initialRequest: initialRequest, + createPage: createPage, + } +} + +// WithPageCreator returns a new Pager that substitutes a different page creation function. This is +// useful for overriding List functions in delegation. +func (p Pager) WithPageCreator(createPage func(r PageResult) Page) Pager { + return Pager{ + client: p.client, + method: p.method, + initialURL: p.initialURL, + initialRequest: p.initialRequest, + createPage: createPage, + } +} + +func (p Pager) fetchNextPage(method string, url string, request interface{}) (Page, error) { + resp, err := Request(p.client, method, request, p.Headers, url) + if err != nil { + return nil, err + } + + remembered, err := PageResultFrom(resp) + if err != nil { + return nil, err + } + + return p.createPage(remembered), nil +} + +// EachPage iterates over each page returned by a Pager, yielding one at a time to a handler function. +// Return "false" from the handler to prematurely stop iterating. +func (p Pager) EachPage(handler func(Page) (bool, error)) error { + if p.Err != nil { + return p.Err + } + currentURL := p.initialURL + currentRequest := p.initialRequest + for { + currentPage, err := p.fetchNextPage(p.method, currentURL, currentRequest) + if err != nil { + return err + } + + empty, err := currentPage.IsEmpty() + if err != nil { + return err + } + if empty { + return nil + } + + ok, err := handler(currentPage) + if err != nil { + return err + } + if !ok { + return nil + } + + currentURL, err = currentPage.NextPageURL() + if err != nil { + return err + } + if currentURL == "" { + return nil + } + + currentRequest, err = currentPage.NextPageRequest() + if err != nil { + return err + } + if currentRequest == nil { + return nil + } + } +} + +// AllPages returns all the pages from a `List` operation in a single page, +// allowing the user to retrieve all the pages at once. +func (p Pager) AllPages() (Page, error) { + // pagesSlice holds all the pages until they get converted into as Page Body. + var pagesSlice []interface{} + // body will contain the final concatenated Page body. + var body reflect.Value + + // Grab a test page to ascertain the page body type. + testPage, err := p.fetchNextPage(p.method, p.initialURL, p.initialRequest) + if err != nil { + return nil, err + } + // Store the page type so we can use reflection to create a new mega-page of + // that type. + pageType := reflect.TypeOf(testPage) + + // if it's a single page, just return the testPage (first page) + if _, found := pageType.FieldByName("SinglePageBase"); found { + return testPage, nil + } + + // Switch on the page body type. Recognized types are `map[string]interface{}`, + // `[]byte`, and `[]interface{}`. + switch pb := testPage.GetBody().(type) { + case map[string]interface{}: + // key is the map key for the page body if the body type is `map[string]interface{}`. + var mapPagesSlice = make(map[string]interface{}) + // Iterate over the pages to concatenate the bodies. + err = p.EachPage(func(page Page) (bool, error) { + b := page.GetBody().(map[string]interface{}) + for k, v := range b { + // If it's a linked page, we don't want the `links`, we want the other one. + if !strings.HasSuffix(k, "links") && !strings.HasSuffix(k, "next_marker") && !strings.HasSuffix(k, "truncated") { + // check the field's type. we only want []interface{} (which is really []map[string]interface{}) + switch vt := v.(type) { + case []interface{}: + slice := mapPagesSlice[k] + if slice == nil { + var temp []interface{} + slice = temp + } + slice = append(slice.([]interface{}), vt...) + mapPagesSlice[k] = slice + } + } + } + return true, nil + }) + if err != nil { + return nil, err + } + var dummyKey = "" + var dummyValue []interface{} + body = reflect.MakeMap(reflect.MapOf(reflect.TypeOf(dummyKey), reflect.TypeOf(dummyValue))) + for mapKey, mapValue := range mapPagesSlice { + body.SetMapIndex(reflect.ValueOf(mapKey), reflect.ValueOf(mapValue)) + } + case []byte: + // Iterate over the pages to concatenate the bodies. + err = p.EachPage(func(page Page) (bool, error) { + b := page.GetBody().([]byte) + pagesSlice = append(pagesSlice, b) + // seperate pages with a comma + pagesSlice = append(pagesSlice, []byte{10}) + return true, nil + }) + if err != nil { + return nil, err + } + if len(pagesSlice) > 0 { + // Remove the trailing comma. + pagesSlice = pagesSlice[:len(pagesSlice)-1] + } + var b []byte + // Combine the slice of slices in to a single slice. + for _, slice := range pagesSlice { + b = append(b, slice.([]byte)...) + } + // Set body to value of type `bytes`. + body = reflect.New(reflect.TypeOf(b)).Elem() + body.SetBytes(b) + case []interface{}: + // Iterate over the pages to concatenate the bodies. + err = p.EachPage(func(page Page) (bool, error) { + b := page.GetBody().([]interface{}) + pagesSlice = append(pagesSlice, b...) + return true, nil + }) + if err != nil { + return nil, err + } + // Set body to value of type `[]interface{}` + body = reflect.MakeSlice(reflect.TypeOf(pagesSlice), len(pagesSlice), len(pagesSlice)) + for i, s := range pagesSlice { + body.Index(i).Set(reflect.ValueOf(s)) + } + default: + err := golangsdk.ErrUnexpectedType{} + err.Expected = "map[string]interface{}/[]byte/[]interface{}" + err.Actual = fmt.Sprintf("%T", pb) + return nil, err + } + + // Each `Extract*` function is expecting a specific type of page coming back, + // otherwise the type assertion in those functions will fail. pageType is needed + // to create a type in this method that has the same type that the `Extract*` + // function is expecting and set the Body of that object to the concatenated + // pages. + page := reflect.New(pageType) + // Set the page body to be the concatenated pages. + page.Elem().FieldByName("Body").Set(body) + // Set any additional headers that were pass along. The `objectstorage` pacakge, + // for example, passes a Content-Type header. + h := make(http.Header) + for k, v := range p.Headers { + h.Add(k, v) + } + page.Elem().FieldByName("Header").Set(reflect.ValueOf(h)) + // Type assert the page to a Page interface so that the type assertion in the + // `Extract*` methods will work. + return page.Elem().Interface().(Page), err +} diff --git a/postpagination/pkg.go b/postpagination/pkg.go new file mode 100644 index 000000000..e47537f41 --- /dev/null +++ b/postpagination/pkg.go @@ -0,0 +1,4 @@ +/* +Package pagination contains utilities and convenience structs that implement common pagination idioms within OpenStack APIs. +*/ +package postpagination diff --git a/postpagination/postmarker.go b/postpagination/postmarker.go new file mode 100644 index 000000000..4be68250b --- /dev/null +++ b/postpagination/postmarker.go @@ -0,0 +1,91 @@ +package postpagination + +import ( + "encoding/json" + "fmt" + "reflect" + + "github.com/huaweicloud/golangsdk" +) + +type PageBuilder interface { + ToServerPageMap() (map[string]interface{}, error) +} + +// MarkerPage is a stricter Page interface that describes additional functionality required for use with NewMarkerPager. +// For convenience, embed the MarkedPageBase struct. +type PostMarkerPage interface { + Page +} + +// MarkerPageBase is a page in a collection that's paginated by "limit" and "marker" query parameters. +type PostMarkerPageBase struct { + PageResult + + ListFieldName string + + Request map[string]interface{} + + // Owner is a reference to the embedding struct. + Owner PostMarkerPage +} + +// NextPageURL generates the URL for the page of results after this one. +func (current PostMarkerPageBase) NextPageURL() (string, error) { + return current.URL.String(), nil +} + +// NextPageRequest generates the body for the page of results after this one. +func (current PostMarkerPageBase) NextPageRequest() (interface{}, error) { + var nextMarker string + var truncated string + var nextRequest map[string]interface{} = nil + + submap, ok := current.Body.(map[string]interface{}) + if !ok { + err := golangsdk.ErrUnexpectedType{} + err.Expected = "map[string]interface{}" + err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) + return nil, err + } + + truncated, ok = submap["truncated"].(string) + if !ok || truncated == "false" { + return nil, nil + } + + nextMarker, ok = submap["next_marker"].(string) + if !ok { + return nil, nil + } + + rawBody, err := json.Marshal(current.Request) + if err != nil { + return nil, err + } + + err = json.Unmarshal(rawBody, &nextRequest) + if err != nil { + return nil, err + } + + nextRequest["marker"] = nextMarker + return nextRequest, nil +} + +// IsEmpty satisifies the IsEmpty method of the Page interface +func (current PostMarkerPageBase) IsEmpty() (bool, error) { + if b, ok := current.Body.([]interface{}); ok { + return len(b) == 0, nil + } + err := golangsdk.ErrUnexpectedType{} + err.Expected = "[]interface{}" + err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) + return true, err +} + +// GetBody returns the linked page's body. This method is needed to satisfy the +// Page interface. +func (current PostMarkerPageBase) GetBody() interface{} { + return current.Body +} diff --git a/postpagination/single.go b/postpagination/single.go new file mode 100644 index 000000000..68eb3c40a --- /dev/null +++ b/postpagination/single.go @@ -0,0 +1,33 @@ +package postpagination + +import ( + "fmt" + "reflect" + + "github.com/huaweicloud/golangsdk" +) + +// SinglePageBase may be embedded in a Page that contains all of the results from an operation at once. +type SinglePageBase PageResult + +// NextPageURL always returns "" to indicate that there are no more pages to return. +func (current SinglePageBase) NextPageURL() (string, error) { + return "", nil +} + +// IsEmpty satisifies the IsEmpty method of the Page interface +func (current SinglePageBase) IsEmpty() (bool, error) { + if b, ok := current.Body.([]interface{}); ok { + return len(b) == 0, nil + } + err := golangsdk.ErrUnexpectedType{} + err.Expected = "[]interface{}" + err.Actual = fmt.Sprintf("%v", reflect.TypeOf(current.Body)) + return true, err +} + +// GetBody returns the single page's body. This method is needed to satisfy the +// Page interface. +func (current SinglePageBase) GetBody() interface{} { + return current.Body +}