use trash to add aliyun sdk

This commit is contained in:
loganhz
2017-07-20 09:49:01 +08:00
parent c2e9dee2eb
commit e24ce5a36a
38 changed files with 3851 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
.idea
+12
View File
@@ -0,0 +1,12 @@
language: go
go:
- 1.7.4
# let us have speedy Docker-based Travis workers
sudo: false
script:
- go get ./...
- go vet ./...
- go build ./...
+191
View File
@@ -0,0 +1,191 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2015-2015 Li Yi (denverdino@gmail.com).
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+178
View File
@@ -0,0 +1,178 @@
# AliyunGo: Go SDK for Aliyun Services
[![Build Status](https://travis-ci.org/denverdino/aliyungo.svg?branch=master)](https://travis-ci.org/denverdino/aliyungo) [![CircleCI](https://circleci.com/gh/denverdino/aliyungo.svg?style=svg)](https://circleci.com/gh/denverdino/aliyungo) [![Go Report Card](https://goreportcard.com/badge/github.com/denverdino/aliyungo)](https://goreportcard.com/report/github.com/denverdino/aliyungo)
This is an unofficial Go SDK for Aliyun Services. You are welcome for contribution.
## Package Structure
* ecs: [Elastic Compute Service](https://help.aliyun.com/document_detail/ecs/open-api/summary.html)
* oss: [Open Storage Service](https://help.aliyun.com/document_detail/oss/api-reference/abstract.html)
* slb: [Server Load Balancer](https://help.aliyun.com/document_detail/slb/api-reference/brief-introduction.html)
* dns: [DNS](https://help.aliyun.com/document_detail/dns/api-reference/summary.html)
* sls: [Logging Service](https://help.aliyun.com/document_detail/sls/api/overview.html)
* ram: [Resource Access Management](https://help.aliyun.com/document_detail/ram/ram-api-reference/intro/intro.html)
* rds: [Relational Database Service](https://help.aliyun.com/document_detail/26226.html)
* cms: [Cloud Monitor Service](https://help.aliyun.com/document_detail/28615.html)
* cs: [Container Service](https://help.aliyun.com/product/25972.html)
* sts: [Security Token Service](https://help.aliyun.com/document_detail/28756.html)
* dm: [Direct Mail](https://help.aliyun.com/document_detail/29414.html)
* sms: [Short Message Service](https://help.aliyun.com/product/44282.html)
* push: [Cloud Mobile Push](https://help.aliyun.com/document_detail/30049.html)
* opensearch: [OpenSearch](https://help.aliyun.com/document_detail/29118.html)
* mq: [Message Queue](https://help.aliyun.com/document_detail/29532.html)
* nas: [Network Attached Storage](https://help.aliyun.com/document_detail/27518.html)
* common: Common libary of Aliyun Go SDK
* util: Utility helpers
## Quick Start
```go
package main
import (
"fmt"
"github.com/denverdino/aliyungo/ecs"
)
const ACCESS_KEY_ID = "<YOUR_ID>"
const ACCESS_KEY_SECRET = "<****>"
func main() {
client := ecs.NewClient(ACCESS_KEY_ID, ACCESS_KEY_SECRET)
fmt.Print(client.DescribeRegions())
}
```
## Documentation
* ECS: [https://godoc.org/github.com/denverdino/aliyungo/ecs](https://godoc.org/github.com/denverdino/aliyungo/ecs) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/ecs?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/ecs)
* OSS: [https://godoc.org/github.com/denverdino/aliyungo/oss](https://godoc.org/github.com/denverdino/aliyungo/oss) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/oss?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/oss)
* SLB: [https://godoc.org/github.com/denverdino/aliyungo/slb](https://godoc.org/github.com/denverdino/aliyungo/slb) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/slb?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/slb)
* DNS: [https://godoc.org/github.com/denverdino/aliyungo/dns](https://godoc.org/github.com/denverdino/aliyungo/dns) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/dns?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/dns)
* SLS: [https://godoc.org/github.com/denverdino/aliyungo/sls](https://godoc.org/github.com/denverdino/aliyungo/sls) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/sls?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/sls)
* RAM: [https://godoc.org/github.com/denverdino/aliyungo/ram](https://godoc.org/github.com/denverdino/aliyungo/ram) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/ram?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/ram)
* RDS: [https://godoc.org/github.com/denverdino/aliyungo/rds](https://godoc.org/github.com/denverdino/aliyungo/rds) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/rds?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/rds)
* CMS: [https://godoc.org/github.com/denverdino/aliyungo/cms](https://godoc.org/github.com/denverdino/aliyungo/cms) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/cms?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/cms)
* CS: [https://godoc.org/github.com/denverdino/aliyungo/cs](https://godoc.org/github.com/denverdino/aliyungo/cs) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/cs?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/cs)
* STS: [https://godoc.org/github.com/denverdino/aliyungo/sts](https://godoc.org/github.com/denverdino/aliyungo/sts) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/sts?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/sts)
* DM: [https://godoc.org/github.com/denverdino/aliyungo/dm](https://godoc.org/github.com/denverdino/aliyungo/dm) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/dm?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/dm)
* SMS: [https://godoc.org/github.com/denverdino/aliyungo/sms](https://godoc.org/github.com/denverdino/aliyungo/sms) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/sms?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/sms)
* MQ: [https://godoc.org/github.com/denverdino/aliyungo/mq](https://godoc.org/github.com/denverdino/aliyungo/mq) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/mq?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/mq)
* NAS: [https://godoc.org/github.com/denverdino/aliyungo/nas](https://godoc.org/github.com/denverdino/aliyungo/nas) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/nas?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/nas)
* OPENSEARCH: [https://godoc.org/github.com/denverdino/aliyungo/opensearch](https://godoc.org/github.com/denverdino/aliyungo/opensearch) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/opensearch?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/opensearch)
* PUSH: [https://godoc.org/github.com/denverdino/aliyungo/push](https://godoc.org/github.com/denverdino/aliyungo/push) [![GoDoc](https://godoc.org/github.com/denverdino/aliyungo/push?status.svg)](https://godoc.org/github.com/denverdino/aliyungo/push)
## Build and Install
go get:
```sh
go get github.com/denverdino/aliyungo
```
## Test ECS
Modify "ecs/config_test.go"
```sh
TestAccessKeyId = "MY_ACCESS_KEY_ID"
TestAccessKeySecret = "MY_ACCESS_KEY_ID"
TestInstanceId = "MY_INSTANCE_ID"
TestIAmRich = false
```
* TestAccessKeyId: the Access Key Id
* TestAccessKeySecret: the Access Key Secret.
* TestInstanceId: the existing instance id for testing. It will be stopped and restarted during testing.
* TestIAmRich(Optional): If it is set to true, it will perform tests to create virtual machines and disks under your account. And you will pay the bill. :-)
Under "ecs" and run
```sh
go test
```
## Test OSS
Modify "oss/config_test.go"
```sh
TestAccessKeyId = "MY_ACCESS_KEY_ID"
TestAccessKeySecret = "MY_ACCESS_KEY_ID"
TestRegion = oss.Beijing
TestBucket = "denverdino"
```
* TestAccessKeyId: the Access Key Id
* TestAccessKeySecret: the Access Key Secret.
* TestRegion: the region of OSS for testing
* TestBucket: the bucket name for testing
Under "oss" and run
```sh
go test
```
## Contributors
* Li Yi (denverdino@gmail.com)
* Boshi Lian (farmer1992@gmail.com)
* Yu Zhou (oscarrr110@gmail.com)
* Yufei Zhang
* linuxlikerqq
* Changhai Yan
* Jizhong Jiang (jiangjizhong@gmail.com)
* Kent Wang (pragkent@gmail.com)
* ringtail
* aiden0z (aiden0xz@gmail.com)
* jimmycmh
* menglingwei
* mingang.he (dustgle@gmail.com)
* Young Chen (chainone@gmail.com)
* johnzeng
* spacexnice (445436286@qq.com)
* xiaoheihero
* hmgle (dustgle@gmail.com)
* jzwlqx (jiangjizhong@gmail.com)
* Linhua Tan (toolchainX@gmail.com)
* Plutonist (p@vecsight.com)
* Bin Liu
* wangyue
* demonwy
* yarous224
* yufeizyf (xazyf9111@sina.cn)
* keontang (ikeontang@gmail.com)
* Cholerae Hu (me@cholerae.com)
* Zach Bergh (berghzach@gmail.com)
* Bingshen Wang
* xiaozhu36
* Russell (yufeiwu@gmail.com)
* zhuzhih2017
* cheyang
* Hobo Chen
* Shuwei Yin
## License
This project is licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/denverdino/aliyungo/blob/master/LICENSE.txt) for the full license text.
## Related projects
* Aliyun ECS driver for Docker Machine: [Pull request](https://github.com/docker/machine/pull/1182)
* Aliyun OSS driver for Docker Registry V2: [Pull request](https://github.com/docker/distribution/pull/514)
## References
The GO API design of OSS refer the implementation from [https://github.com/AdRoll/goamz](https://github.com/AdRoll)
+13
View File
@@ -0,0 +1,13 @@
machine:
environment:
GODIST: "go1.7.5.linux-amd64.tar.gz"
services:
- docker
dependencies:
override:
- go get -t -d -v ./...
test:
override:
- go vet ./...
+357
View File
@@ -0,0 +1,357 @@
package common
import (
"bytes"
"encoding/json"
"io/ioutil"
"log"
"net/http"
"net/url"
"strings"
"time"
"github.com/denverdino/aliyungo/util"
)
// RemovalPolicy.N add index to array item
// RemovalPolicy=["a", "b"] => RemovalPolicy.1="a" RemovalPolicy.2="b"
type FlattenArray []string
// string contains underline which will be replaced with dot
// SystemDisk_Category => SystemDisk.Category
type UnderlineString string
// A Client represents a client of ECS services
type Client struct {
AccessKeyId string //Access Key Id
AccessKeySecret string //Access Key Secret
debug bool
httpClient *http.Client
endpoint string
version string
serviceCode string
regionID Region
businessInfo string
userAgent string
}
// NewClient creates a new instance of ECS client
func (client *Client) Init(endpoint, version, accessKeyId, accessKeySecret string) {
client.AccessKeyId = accessKeyId
client.AccessKeySecret = accessKeySecret + "&"
client.debug = false
client.httpClient = &http.Client{}
client.endpoint = endpoint
client.version = version
}
func (client *Client) NewInit(endpoint, version, accessKeyId, accessKeySecret, serviceCode string, regionID Region) {
client.Init(endpoint, version, accessKeyId, accessKeySecret)
client.serviceCode = serviceCode
client.regionID = regionID
client.setEndpointByLocation(regionID, serviceCode, accessKeyId, accessKeySecret)
}
//NewClient using location service
func (client *Client) setEndpointByLocation(region Region, serviceCode, accessKeyId, accessKeySecret string) {
locationClient := NewLocationClient(accessKeyId, accessKeySecret)
ep := locationClient.DescribeOpenAPIEndpoint(region, serviceCode)
if ep == "" {
ep = loadEndpointFromFile(region, serviceCode)
}
if ep != "" {
client.endpoint = ep
}
}
// SetEndpoint sets custom endpoint
func (client *Client) SetEndpoint(endpoint string) {
client.endpoint = endpoint
}
// SetEndpoint sets custom version
func (client *Client) SetVersion(version string) {
client.version = version
}
func (client *Client) SetRegionID(regionID Region) {
client.regionID = regionID
}
//SetServiceCode sets serviceCode
func (client *Client) SetServiceCode(serviceCode string) {
client.serviceCode = serviceCode
}
// SetAccessKeyId sets new AccessKeyId
func (client *Client) SetAccessKeyId(id string) {
client.AccessKeyId = id
}
// SetAccessKeySecret sets new AccessKeySecret
func (client *Client) SetAccessKeySecret(secret string) {
client.AccessKeySecret = secret + "&"
}
// SetDebug sets debug mode to log the request/response message
func (client *Client) SetDebug(debug bool) {
client.debug = debug
}
// SetBusinessInfo sets business info to log the request/response message
func (client *Client) SetBusinessInfo(businessInfo string) {
if strings.HasPrefix(businessInfo, "/") {
client.businessInfo = businessInfo
} else if businessInfo != "" {
client.businessInfo = "/" + businessInfo
}
}
// SetUserAgent sets user agent to the request/response message
func (client *Client) SetUserAgent(userAgent string) {
client.userAgent = userAgent
}
// Invoke sends the raw HTTP request for ECS services
func (client *Client) Invoke(action string, args interface{}, response interface{}) error {
request := Request{}
request.init(client.version, action, client.AccessKeyId)
query := util.ConvertToQueryValues(request)
util.SetQueryValues(args, &query)
// Sign request
signature := util.CreateSignatureForRequest(ECSRequestMethod, &query, client.AccessKeySecret)
// Generate the request URL
requestURL := client.endpoint + "?" + query.Encode() + "&Signature=" + url.QueryEscape(signature)
httpReq, err := http.NewRequest(ECSRequestMethod, requestURL, nil)
if err != nil {
return GetClientError(err)
}
// TODO move to util and add build val flag
httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
httpReq.Header.Set("User-Agent", httpReq.UserAgent()+ " " +client.userAgent)
t0 := time.Now()
httpResp, err := client.httpClient.Do(httpReq)
t1 := time.Now()
if err != nil {
return GetClientError(err)
}
statusCode := httpResp.StatusCode
if client.debug {
log.Printf("Invoke %s %s %d (%v)", ECSRequestMethod, requestURL, statusCode, t1.Sub(t0))
}
defer httpResp.Body.Close()
body, err := ioutil.ReadAll(httpResp.Body)
if err != nil {
return GetClientError(err)
}
if client.debug {
var prettyJSON bytes.Buffer
err = json.Indent(&prettyJSON, body, "", " ")
log.Println(string(prettyJSON.Bytes()))
}
if statusCode >= 400 && statusCode <= 599 {
errorResponse := ErrorResponse{}
err = json.Unmarshal(body, &errorResponse)
ecsError := &Error{
ErrorResponse: errorResponse,
StatusCode: statusCode,
}
return ecsError
}
err = json.Unmarshal(body, response)
//log.Printf("%++v", response)
if err != nil {
return GetClientError(err)
}
return nil
}
// Invoke sends the raw HTTP request for ECS services
func (client *Client) InvokeByFlattenMethod(action string, args interface{}, response interface{}) error {
request := Request{}
request.init(client.version, action, client.AccessKeyId)
query := util.ConvertToQueryValues(request)
util.SetQueryValueByFlattenMethod(args, &query)
// Sign request
signature := util.CreateSignatureForRequest(ECSRequestMethod, &query, client.AccessKeySecret)
// Generate the request URL
requestURL := client.endpoint + "?" + query.Encode() + "&Signature=" + url.QueryEscape(signature)
httpReq, err := http.NewRequest(ECSRequestMethod, requestURL, nil)
if err != nil {
return GetClientError(err)
}
// TODO move to util and add build val flag
httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
httpReq.Header.Set("User-Agent", httpReq.UserAgent()+ " " +client.userAgent)
t0 := time.Now()
httpResp, err := client.httpClient.Do(httpReq)
t1 := time.Now()
if err != nil {
return GetClientError(err)
}
statusCode := httpResp.StatusCode
if client.debug {
log.Printf("Invoke %s %s %d (%v)", ECSRequestMethod, requestURL, statusCode, t1.Sub(t0))
}
defer httpResp.Body.Close()
body, err := ioutil.ReadAll(httpResp.Body)
if err != nil {
return GetClientError(err)
}
if client.debug {
var prettyJSON bytes.Buffer
err = json.Indent(&prettyJSON, body, "", " ")
log.Println(string(prettyJSON.Bytes()))
}
if statusCode >= 400 && statusCode <= 599 {
errorResponse := ErrorResponse{}
err = json.Unmarshal(body, &errorResponse)
ecsError := &Error{
ErrorResponse: errorResponse,
StatusCode: statusCode,
}
return ecsError
}
err = json.Unmarshal(body, response)
//log.Printf("%++v", response)
if err != nil {
return GetClientError(err)
}
return nil
}
// Invoke sends the raw HTTP request for ECS services
//改进了一下上面那个方法,可以使用各种Http方法
//2017.1.30 增加了一个path参数,用来拓展访问的地址
func (client *Client) InvokeByAnyMethod(method, action, path string, args interface{}, response interface{}) error {
request := Request{}
request.init(client.version, action, client.AccessKeyId)
data := util.ConvertToQueryValues(request)
util.SetQueryValues(args, &data)
// Sign request
signature := util.CreateSignatureForRequest(method, &data, client.AccessKeySecret)
data.Add("Signature", signature)
// Generate the request URL
var (
httpReq *http.Request
err error
)
if method == http.MethodGet {
requestURL := client.endpoint + path + "?" + data.Encode()
//fmt.Println(requestURL)
httpReq, err = http.NewRequest(method, requestURL, nil)
} else {
//fmt.Println(client.endpoint + path)
httpReq, err = http.NewRequest(method, client.endpoint+path, strings.NewReader(data.Encode()))
httpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
if err != nil {
return GetClientError(err)
}
// TODO move to util and add build val flag
httpReq.Header.Set("X-SDK-Client", `AliyunGO/`+Version+client.businessInfo)
httpReq.Header.Set("User-Agent", httpReq.Header.Get("User-Agent")+ " " +client.userAgent)
t0 := time.Now()
httpResp, err := client.httpClient.Do(httpReq)
t1 := time.Now()
if err != nil {
return GetClientError(err)
}
statusCode := httpResp.StatusCode
if client.debug {
log.Printf("Invoke %s %s %d (%v) %v", ECSRequestMethod, client.endpoint, statusCode, t1.Sub(t0), data.Encode())
}
defer httpResp.Body.Close()
body, err := ioutil.ReadAll(httpResp.Body)
if err != nil {
return GetClientError(err)
}
if client.debug {
var prettyJSON bytes.Buffer
err = json.Indent(&prettyJSON, body, "", " ")
log.Println(string(prettyJSON.Bytes()))
}
if statusCode >= 400 && statusCode <= 599 {
errorResponse := ErrorResponse{}
err = json.Unmarshal(body, &errorResponse)
ecsError := &Error{
ErrorResponse: errorResponse,
StatusCode: statusCode,
}
return ecsError
}
err = json.Unmarshal(body, response)
//log.Printf("%++v", response)
if err != nil {
return GetClientError(err)
}
return nil
}
// GenerateClientToken generates the Client Token with random string
func (client *Client) GenerateClientToken() string {
return util.CreateRandomString()
}
func GetClientErrorFromString(str string) error {
return &Error{
ErrorResponse: ErrorResponse{
Code: "AliyunGoClientFailure",
Message: str,
},
StatusCode: -1,
}
}
func GetClientError(err error) error {
return GetClientErrorFromString(err.Error())
}
+118
View File
@@ -0,0 +1,118 @@
package common
import (
"encoding/xml"
"fmt"
"io/ioutil"
"os"
"strings"
)
const (
// LocationDefaultEndpoint is the default API endpoint of Location services
locationDefaultEndpoint = "https://location.aliyuncs.com"
locationAPIVersion = "2015-06-12"
HTTP_PROTOCOL = "http"
HTTPS_PROTOCOL = "https"
)
var (
endpoints = make(map[Region]map[string]string)
)
//init endpoints from file
func init() {
}
func NewLocationClient(accessKeyId, accessKeySecret string) *Client {
endpoint := os.Getenv("LOCATION_ENDPOINT")
if endpoint == "" {
endpoint = locationDefaultEndpoint
}
client := &Client{}
client.Init(endpoint, locationAPIVersion, accessKeyId, accessKeySecret)
return client
}
func (client *Client) DescribeEndpoint(args *DescribeEndpointArgs) (*DescribeEndpointResponse, error) {
response := &DescribeEndpointResponse{}
err := client.Invoke("DescribeEndpoint", args, response)
if err != nil {
return nil, err
}
return response, err
}
func getProductRegionEndpoint(region Region, serviceCode string) string {
if sp, ok := endpoints[region]; ok {
if endpoint, ok := sp[serviceCode]; ok {
return endpoint
}
}
return ""
}
func setProductRegionEndpoint(region Region, serviceCode string, endpoint string) {
endpoints[region] = map[string]string{
serviceCode: endpoint,
}
}
func (client *Client) DescribeOpenAPIEndpoint(region Region, serviceCode string) string {
if endpoint := getProductRegionEndpoint(region, serviceCode); endpoint != "" {
return endpoint
}
defaultProtocols := HTTP_PROTOCOL
args := &DescribeEndpointArgs{
Id: region,
ServiceCode: serviceCode,
Type: "openAPI",
}
endpoint, err := client.DescribeEndpoint(args)
if err != nil || endpoint.Endpoint == "" {
return ""
}
for _, protocol := range endpoint.Protocols.Protocols {
if strings.ToLower(protocol) == HTTPS_PROTOCOL {
defaultProtocols = HTTPS_PROTOCOL
break
}
}
ep := fmt.Sprintf("%s://%s", defaultProtocols, endpoint.Endpoint)
setProductRegionEndpoint(region, serviceCode, ep)
return ep
}
func loadEndpointFromFile(region Region, serviceCode string) string {
data, err := ioutil.ReadFile("./endpoints.xml")
if err != nil {
return ""
}
var endpoints Endpoints
err = xml.Unmarshal(data, &endpoints)
if err != nil {
return ""
}
for _, endpoint := range endpoints.Endpoint {
if endpoint.RegionIds.RegionId == string(region) {
for _, product := range endpoint.Products.Product {
if strings.ToLower(product.ProductName) == serviceCode {
return fmt.Sprintf("%s://%s", HTTPS_PROTOCOL, product.DomainName)
}
}
}
}
return ""
}
File diff suppressed because it is too large Load Diff
+34
View File
@@ -0,0 +1,34 @@
package common
// Region represents ECS region
type Region string
// Constants of region definition
const (
Hangzhou = Region("cn-hangzhou")
Qingdao = Region("cn-qingdao")
Beijing = Region("cn-beijing")
Hongkong = Region("cn-hongkong")
Shenzhen = Region("cn-shenzhen")
Shanghai = Region("cn-shanghai")
Zhangjiakou = Region("cn-zhangjiakou")
APSouthEast1 = Region("ap-southeast-1")
APNorthEast1 = Region("ap-northeast-1")
APSouthEast2 = Region("ap-southeast-2")
USWest1 = Region("us-west-1")
USEast1 = Region("us-east-1")
MEEast1 = Region("me-east-1")
EUCentral1 = Region("eu-central-1")
)
var ValidRegions = []Region{
Hangzhou, Qingdao, Beijing, Shenzhen, Hongkong, Shanghai, Zhangjiakou,
USWest1, USEast1,
APNorthEast1, APSouthEast1, APSouthEast2,
MEEast1,
EUCentral1,
}
+101
View File
@@ -0,0 +1,101 @@
package common
import (
"fmt"
"log"
"time"
"github.com/denverdino/aliyungo/util"
)
// Constants for Aliyun API requests
const (
SignatureVersion = "1.0"
SignatureMethod = "HMAC-SHA1"
JSONResponseFormat = "JSON"
XMLResponseFormat = "XML"
ECSRequestMethod = "GET"
)
type Request struct {
Format string
Version string
AccessKeyId string
Signature string
SignatureMethod string
Timestamp util.ISO6801Time
SignatureVersion string
SignatureNonce string
ResourceOwnerAccount string
Action string
}
func (request *Request) init(version string, action string, AccessKeyId string) {
request.Format = JSONResponseFormat
request.Timestamp = util.NewISO6801Time(time.Now().UTC())
request.Version = version
request.SignatureVersion = SignatureVersion
request.SignatureMethod = SignatureMethod
request.SignatureNonce = util.CreateRandomString()
request.Action = action
request.AccessKeyId = AccessKeyId
}
type Response struct {
RequestId string
}
type ErrorResponse struct {
Response
HostId string
Code string
Message string
}
// An Error represents a custom error for Aliyun API failure response
type Error struct {
ErrorResponse
StatusCode int //Status Code of HTTP Response
}
func (e *Error) Error() string {
return fmt.Sprintf("Aliyun API Error: RequestId: %s Status Code: %d Code: %s Message: %s", e.RequestId, e.StatusCode, e.Code, e.Message)
}
type Pagination struct {
PageNumber int
PageSize int
}
func (p *Pagination) SetPageSize(size int) {
p.PageSize = size
}
func (p *Pagination) Validate() {
if p.PageNumber < 0 {
log.Printf("Invalid PageNumber: %d", p.PageNumber)
p.PageNumber = 1
}
if p.PageSize < 0 {
log.Printf("Invalid PageSize: %d", p.PageSize)
p.PageSize = 10
} else if p.PageSize > 50 {
log.Printf("Invalid PageSize: %d", p.PageSize)
p.PageSize = 50
}
}
// A PaginationResponse represents a response with pagination information
type PaginationResult struct {
TotalCount int
PageNumber int
PageSize int
}
// NextPage gets the next page of the result set
func (r *PaginationResult) NextPage() *Pagination {
if r.PageNumber*r.PageSize >= r.TotalCount {
return nil
}
return &Pagination{PageNumber: r.PageNumber + 1, PageSize: r.PageSize}
}
+89
View File
@@ -0,0 +1,89 @@
package common
type InternetChargeType string
const (
PayByBandwidth = InternetChargeType("PayByBandwidth")
PayByTraffic = InternetChargeType("PayByTraffic")
)
type InstanceChargeType string
const (
PrePaid = InstanceChargeType("PrePaid")
PostPaid = InstanceChargeType("PostPaid")
)
type DescribeEndpointArgs struct {
Id Region
ServiceCode string
Type string
}
type EndpointItem struct {
Protocols struct {
Protocols []string
}
Type string
Namespace string
Id Region
SerivceCode string
Endpoint string
}
type DescribeEndpointResponse struct {
Response
EndpointItem
}
type NetType string
const (
Internet = NetType("Internet")
Intranet = NetType("Intranet")
)
type TimeType string
const (
Hour = TimeType("Hour")
Day = TimeType("Day")
Month = TimeType("Month")
Year = TimeType("Year")
)
type NetworkType string
const (
Classic = NetworkType("Classic")
VPC = NetworkType("VPC")
)
type BusinessInfo struct {
Pack string `json:"pack,omitempty"`
ActivityId string `json:"activityId,omitempty"`
}
//xml
type Endpoints struct {
Endpoint []Endpoint `xml:"Endpoint"`
}
type Endpoint struct {
Name string `xml:"name,attr"`
RegionIds RegionIds `xml:"RegionIds"`
Products Products `xml:"Products"`
}
type RegionIds struct {
RegionId string `xml:"RegionId"`
}
type Products struct {
Product []Product `xml:"Product"`
}
type Product struct {
ProductName string `xml:"ProductName"`
DomainName string `xml:"DomainName"`
}
+3
View File
@@ -0,0 +1,3 @@
package common
const Version = "0.1"
+41
View File
@@ -0,0 +1,41 @@
package dns
import (
"log"
"github.com/denverdino/aliyungo/common"
)
type AddDomainArgs struct {
DomainName string
//optional
GroupId string
}
type AddDomainResponse struct {
common.Response
DomainId string
DomainName string
GroupId string
GroupName string
PunyCode string
DnsServers struct {
DnsServer []string
}
}
// AddDomain
//
// You can read doc at https://help.aliyun.com/document_detail/29749.html?spm=5176.doc29805.6.592.6LMqlG
func (client *Client) AddDomain(args *AddDomainArgs) (response *AddDomainResponse, err error) {
action := "AddDomain"
response = &AddDomainResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
log.Printf("%s error, %v", action, err)
return response, err
}
}
+32
View File
@@ -0,0 +1,32 @@
package dns
import (
"log"
"github.com/denverdino/aliyungo/common"
)
type AddDomainGroupArgs struct {
GroupName string
}
type AddDomainGroupResponse struct {
common.Response
GroupId string
GroupName string
}
// AddDomainGroup
//
// You can read doc at https://help.aliyun.com/document_detail/29762.html?spm=5176.doc29749.6.604.PJtwG1
func (client *Client) AddDomainGroup(args *AddDomainGroupArgs) (response *AddDomainGroupResponse, err error) {
action := "AddDomainGroup"
response = &AddDomainGroupResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
log.Printf("%s error, %v", action, err)
return response, err
}
}
+40
View File
@@ -0,0 +1,40 @@
package dns
import (
"log"
"github.com/denverdino/aliyungo/common"
)
type AddDomainRecordArgs struct {
DomainName string
RR string
Type string
Value string
//optional
TTL int32
Priority int
Line string
}
type AddDomainRecordResponse struct {
common.Response
InstanceId string
RecordId string
}
// AddDomainRecord
//
// You can read doc at https://docs.aliyun.com/#/pub/dns/api-reference/record-related&AddDomainRecord
func (client *Client) AddDomainRecord(args *AddDomainRecordArgs) (response *AddDomainRecordResponse, err error) {
action := "AddDomainRecord"
response = &AddDomainRecordResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
log.Printf("%s error, %v", action, err)
return response, err
}
}
+33
View File
@@ -0,0 +1,33 @@
package dns
import (
"log"
"github.com/denverdino/aliyungo/common"
)
type ChangeDomainGroupArgs struct {
DomainName string
GroupId string
}
type ChangeDomainGroupResponse struct {
common.Response
GroupId string
GroupName string
}
// ChangeDomainGroup
//
// You can read doc at https://help.aliyun.com/document_detail/29765.html?spm=5176.doc29764.6.607.WUJQgE
func (client *Client) ChangeDomainGroup(args *ChangeDomainGroupArgs) (response *ChangeDomainGroupResponse, err error) {
action := "ChangeDomainGroup"
response = &ChangeDomainGroupResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
log.Printf("%s error, %v", action, err)
return response, err
}
}
+31
View File
@@ -0,0 +1,31 @@
package dns
import (
"log"
"github.com/denverdino/aliyungo/common"
)
type DeleteDomainArgs struct {
DomainName string
}
type DeleteDomainResponse struct {
common.Response
DomainName string
}
// DeleteDomain
//
// You can read doc at https://help.aliyun.com/document_detail/29750.html?spm=5176.doc29766.6.593.eELaZ7
func (client *Client) DeleteDomain(args *DeleteDomainArgs) (response *DeleteDomainResponse, err error) {
action := "DeleteDomain"
response = &DeleteDomainResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
log.Printf("%s error, %v", action, err)
return response, err
}
}
+31
View File
@@ -0,0 +1,31 @@
package dns
import (
"log"
"github.com/denverdino/aliyungo/common"
)
type DeleteDomainGroupArgs struct {
GroupId string
}
type DeleteDomainGroupResponse struct {
common.Response
GroupName string
}
// DeleteDomainGroup
//
// You can read doc at https://help.aliyun.com/document_detail/29764.html?spm=5176.doc29763.6.606.Vm3FyC
func (client *Client) DeleteDomainGroup(args *DeleteDomainGroupArgs) (response *DeleteDomainGroupResponse, err error) {
action := "DeleteDomainGroup"
response = &DeleteDomainGroupResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
log.Printf("%s error, %v", action, err)
return response, err
}
}
+27
View File
@@ -0,0 +1,27 @@
package dns
import "github.com/denverdino/aliyungo/common"
type DeleteDomainRecordArgs struct {
RecordId string
}
type DeleteDomainRecordResponse struct {
common.Response
InstanceId string
RecordId string
}
// DeleteDomainRecord
//
// You can read doc at https://docs.aliyun.com/#/pub/dns/api-reference/record-related&DeleteDomainRecord
func (client *Client) DeleteDomainRecord(args *DeleteDomainRecordArgs) (response *DeleteDomainRecordResponse, err error) {
action := "DeleteDomainRecord"
response = &DeleteDomainRecordResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
return nil, err
}
}
+32
View File
@@ -0,0 +1,32 @@
package dns
import "github.com/denverdino/aliyungo/common"
type DeleteSubDomainRecordsArgs struct {
DomainName string
RR string
//optional
Type string
}
type DeleteSubDomainRecordsResponse struct {
common.Response
InstanceId string
RR string
// TotalCount int32
}
// DeleteSubDomainRecords
//
// You can read doc at https://docs.aliyun.com/#/pub/dns/api-reference/record-related&DeleteSubDomainRecords
func (client *Client) DeleteSubDomainRecords(args *DeleteSubDomainRecordsArgs) (response *DeleteSubDomainRecordsResponse, err error) {
action := "DeleteSubDomainRecords"
response = &DeleteSubDomainRecordsResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
return nil, err
}
}
+45
View File
@@ -0,0 +1,45 @@
package dns
import (
"log"
"github.com/denverdino/aliyungo/common"
)
type DomainGroupType struct {
GroupId string
GroupName string
}
type DescribeDomainGroupsArgs struct {
//optional
PageNumber int32
PageSize int32
KeyWord string
}
type DescribeDomainGroupsResponse struct {
response common.Response
TotalCount int32
PageNumber int32
PageSize int32
DomainGroups struct {
DomainGroup []DomainGroupType
}
}
// DescribeDomainGroups
//
// You can read doc at https://help.aliyun.com/document_detail/29766.html?spm=5176.doc29765.6.608.qcQr2R
func (client *Client) DescribeDomainGroups(args *DescribeDomainGroupsArgs) (groups []DomainGroupType, err error) {
action := "DescribeDomainGroups"
response := &DescribeDomainGroupsResponse{}
err = client.Invoke(action, args, response)
if err != nil {
log.Printf("%s error, %v", action, err)
return nil, err
}
return response.DomainGroups.DomainGroup, nil
}
+46
View File
@@ -0,0 +1,46 @@
package dns
import (
"log"
"github.com/denverdino/aliyungo/common"
)
type DomainType struct {
DomainId string
DomainName string
AliDomain bool
GroupId string
GroupName string
InstanceId string
VersionCode string
PunyCode string
DnsServers struct {
DnsServer []string
}
}
type DescribeDomainInfoArgs struct {
DomainName string
}
type DescribeDomainInfoResponse struct {
response common.Response
DomainType
}
// DescribeDomainInfo
//
// You can read doc at https://help.aliyun.com/document_detail/29752.html?spm=5176.doc29751.6.595.VJM3Gy
func (client *Client) DescribeDomainInfo(args *DescribeDomainInfoArgs) (domain DomainType, err error) {
action := "DescribeDomainInfo"
response := &DescribeDomainInfoResponse{}
err = client.Invoke(action, args, response)
if err != nil {
log.Printf("%s error, %v", action, err)
return DomainType{}, err
}
return response.DomainType, nil
}
+26
View File
@@ -0,0 +1,26 @@
package dns
import "github.com/denverdino/aliyungo/common"
type DescribeDomainRecordInfoArgs struct {
RecordId string
}
type DescribeDomainRecordInfoResponse struct {
common.Response
RecordType
}
// DescribeDomainRecordInfo
//
// You can read doc at https://docs.aliyun.com/#/pub/dns/api-reference/record-related&DescribeDomainRecordInfo
func (client *Client) DescribeDomainRecordInfo(args *DescribeDomainRecordInfoArgs) (response *DescribeDomainRecordInfoResponse, err error) {
action := "DescribeDomainRecordInfo"
response = &DescribeDomainRecordInfoResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
return nil, err
}
}
@@ -0,0 +1,40 @@
package dns
import "github.com/denverdino/aliyungo/common"
// endpoint change to 'http://alidns.aliyuncs.com' then record ttl and priority change to string
type RecordTypeNew struct {
DomainName string
RecordId string
RR string
Type string
Value string
TTL string
Priority string
Line string
Status string
Locked bool
}
type DescribeDomainRecordInfoNewArgs struct {
RecordId string
}
type DescribeDomainRecordInfoNewResponse struct {
common.Response
RecordTypeNew
}
// DescribeDomainRecordInformation
//
// You can read doc at https://docs.aliyun.com/#/pub/dns/api-reference/record-related&DescribeDomainRecordInfo
func (client *Client) DescribeDomainRecordInfoNew(args *DescribeDomainRecordInfoNewArgs) (response *DescribeDomainRecordInfoNewResponse, err error) {
action := "DescribeDomainRecordInfo"
response = &DescribeDomainRecordInfoNewResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
return nil, err
}
}
+36
View File
@@ -0,0 +1,36 @@
package dns
import "github.com/denverdino/aliyungo/common"
type DescribeDomainRecordsArgs struct {
DomainName string
//optional
common.Pagination
RRKeyWord string
TypeKeyWord string
ValueKeyWord string
}
type DescribeDomainRecordsResponse struct {
common.Response
common.PaginationResult
InstanceId string
DomainRecords struct {
Record []RecordType
}
}
// DescribeDomainRecords
//
// You can read doc at https://docs.aliyun.com/#/pub/dns/api-reference/record-related&DescribeDomainRecords
func (client *Client) DescribeDomainRecords(args *DescribeDomainRecordsArgs) (response *DescribeDomainRecordsResponse, err error) {
action := "DescribeDomainRecords"
response = &DescribeDomainRecordsResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
return nil, err
}
}
+36
View File
@@ -0,0 +1,36 @@
package dns
import "github.com/denverdino/aliyungo/common"
type DescribeDomainRecordsNewArgs struct {
DomainName string
//optional
common.Pagination
RRKeyWord string
TypeKeyWord string
ValueKeyWord string
}
type DescribeDomainRecordsNewResponse struct {
common.Response
common.PaginationResult
InstanceId string
DomainRecords struct {
Record []RecordTypeNew
}
}
// DescribeDomainRecordsNew
//
// You can read doc at https://docs.aliyun.com/#/pub/dns/api-reference/record-related&DescribeDomainRecords
func (client *Client) DescribeDomainRecordsNew(args *DescribeDomainRecordsNewArgs) (response *DescribeDomainRecordsNewResponse, err error) {
action := "DescribeDomainRecords"
response = &DescribeDomainRecordsNewResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
return nil, err
}
}
+41
View File
@@ -0,0 +1,41 @@
package dns
import (
"log"
"github.com/denverdino/aliyungo/common"
)
type DescribeDomainsArgs struct {
// optional
PageNumber int32
PageSize int32
KeyWord string
GroupId string
}
type DescribeDomainsResponse struct {
response common.Response
TotalCount int32
PageNumber int32
PageSize int32
Domains struct {
Domain []DomainType
}
}
// DescribeDomains
//
// You can read doc at https://help.aliyun.com/document_detail/29751.html?spm=5176.doc29750.6.594.dvyRJV
func (client *Client) DescribeDomains(args *DescribeDomainsArgs) (domains []DomainType, err error) {
action := "DescribeDomains"
response := &DescribeDomainsResponse{}
err = client.Invoke(action, args, response)
if err != nil {
log.Printf("%s error, %v", action, err)
return nil, err
}
return response.Domains.Domain, err
}
+37
View File
@@ -0,0 +1,37 @@
package dns
import "github.com/denverdino/aliyungo/common"
type DescribeSubDomainRecordsArgs struct {
SubDomain string
//optional
PageNumber int32
PageSize int32
Type string
}
type DescribeSubDomainRecordsResponse struct {
common.Response
InstanceId string
TotalCount int32
PageNumber int32
PageSize int32
DomainRecords struct {
Record []RecordType
}
}
// DescribeSubDomainRecords
//
// You can read doc at https://docs.aliyun.com/#/pub/dns/api-reference/record-related&DescribeSubDomainRecords
func (client *Client) DescribeSubDomainRecords(args *DescribeSubDomainRecordsArgs) (response *DescribeSubDomainRecordsResponse, err error) {
action := "DescribeSubDomainRecords"
response = &DescribeSubDomainRecordsResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
return nil, err
}
}
+29
View File
@@ -0,0 +1,29 @@
package dns
import "github.com/denverdino/aliyungo/common"
type GetMainDomainNameArgs struct {
InputString string
}
type GetMainDomainNameResponse struct {
common.Response
InstanceId string
DomainName string
RR string
DomainLevel int32
}
// GetMainDomainName
//
// You can read doc at https://docs.aliyun.com/#/pub/dns/api-reference/domain-related&GetMainDomainName
func (client *Client) GetMainDomainName(args *GetMainDomainNameArgs) (response *GetMainDomainNameResponse, err error) {
action := "GetMainDomainName"
response = &GetMainDomainNameResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
return nil, err
}
}
+33
View File
@@ -0,0 +1,33 @@
package dns
import (
"log"
"github.com/denverdino/aliyungo/common"
)
type UpdateDomainGroupArgs struct {
GroupId string
GroupName string
}
type UpdateDomainGroupResponse struct {
common.Response
GroupId string
GroupName string
}
// UpdateDomainGroup
//
// You can read doc at https://help.aliyun.com/document_detail/29763.html?spm=5176.doc29762.6.605.iFRKjn
func (client *Client) UpdateDomainGroup(args *UpdateDomainGroupArgs) (response *UpdateDomainGroupResponse, err error) {
action := "UpdateDomainGroup"
response = &UpdateDomainGroupResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
log.Printf("%s error, %v", action, err)
return response, err
}
}
+35
View File
@@ -0,0 +1,35 @@
package dns
import "github.com/denverdino/aliyungo/common"
type UpdateDomainRecordArgs struct {
RecordId string
RR string
Type string
Value string
//optional
TTL int32
Priority int32
Line string
}
type UpdateDomainRecordResponse struct {
common.Response
InstanceId string
RecordId string
}
// UpdateDomainRecord
//
// You can read doc at https://docs.aliyun.com/#/pub/dns/api-reference/record-related&UpdateDomainRecord
func (client *Client) UpdateDomainRecord(args *UpdateDomainRecordArgs) (response *UpdateDomainRecordResponse, err error) {
action := "UpdateDomainRecord"
response = &UpdateDomainRecordResponse{}
err = client.Invoke(action, args, response)
if err == nil {
return response, nil
} else {
return nil, err
}
}
+49
View File
@@ -0,0 +1,49 @@
package dns
import (
"github.com/denverdino/aliyungo/common"
"os"
)
type Client struct {
common.Client
}
const (
// DNSDefaultEndpoint is the default API endpoint of DNS services
DNSDefaultEndpoint = "http://dns.aliyuncs.com"
DNSAPIVersion = "2015-01-09"
DNSDefaultEndpointNew = "http://alidns.aliyuncs.com"
)
// NewClient creates a new instance of DNS client
func NewClient(accessKeyId, accessKeySecret string) *Client {
endpoint := os.Getenv("DNS_ENDPOINT")
if endpoint == "" {
endpoint = DNSDefaultEndpoint
}
return NewClientWithEndpoint(endpoint, accessKeyId, accessKeySecret)
}
// NewClientNew creates a new instance of DNS client, with http://alidns.aliyuncs.com as default endpoint
func NewClientNew(accessKeyId, accessKeySecret string) *Client {
endpoint := os.Getenv("DNS_ENDPOINT")
if endpoint == "" {
endpoint = DNSDefaultEndpointNew
}
return NewClientWithEndpoint(endpoint, accessKeyId, accessKeySecret)
}
// NewCustomClient creates a new instance of ECS client with customized API endpoint
func NewCustomClient(accessKeyId, accessKeySecret string, endpoint string) *Client {
client := &Client{}
client.Init(endpoint, DNSAPIVersion, accessKeyId, accessKeySecret)
return client
}
func NewClientWithEndpoint(endpoint string, accessKeyId, accessKeySecret string) *Client {
client := &Client{}
client.Init(endpoint, DNSAPIVersion, accessKeyId, accessKeySecret)
return client
}
+28
View File
@@ -0,0 +1,28 @@
package dns
//
//you can read doc at https://docs.aliyun.com/#/pub/dns/api-reference/enum-type&record-format
const (
ARecord = "A"
NSRecord = "NS"
MXRecord = "MX"
TXTRecord = "TXT"
CNAMERecord = "CNAME"
SRVRecord = "SRV"
AAAARecord = "AAAA"
RedirectURLRecord = "REDIRECT_URL"
ForwordURLRecord = "FORWORD_URL"
)
type RecordType struct {
DomainName string
RecordId string
RR string
Type string
Value string
TTL int32
Priority int32
Line string
Status string
Locked bool
}
+76
View File
@@ -0,0 +1,76 @@
package util
import (
"time"
)
// AttemptStrategy is reused from the goamz package
// AttemptStrategy represents a strategy for waiting for an action
// to complete successfully. This is an internal type used by the
// implementation of other packages.
type AttemptStrategy struct {
Total time.Duration // total duration of attempt.
Delay time.Duration // interval between each try in the burst.
Min int // minimum number of retries; overrides Total
}
type Attempt struct {
strategy AttemptStrategy
last time.Time
end time.Time
force bool
count int
}
// Start begins a new sequence of attempts for the given strategy.
func (s AttemptStrategy) Start() *Attempt {
now := time.Now()
return &Attempt{
strategy: s,
last: now,
end: now.Add(s.Total),
force: true,
}
}
// Next waits until it is time to perform the next attempt or returns
// false if it is time to stop trying.
func (a *Attempt) Next() bool {
now := time.Now()
sleep := a.nextSleep(now)
if !a.force && !now.Add(sleep).Before(a.end) && a.strategy.Min <= a.count {
return false
}
a.force = false
if sleep > 0 && a.count > 0 {
time.Sleep(sleep)
now = time.Now()
}
a.count++
a.last = now
return true
}
func (a *Attempt) nextSleep(now time.Time) time.Duration {
sleep := a.strategy.Delay - now.Sub(a.last)
if sleep < 0 {
return 0
}
return sleep
}
// HasNext returns whether another attempt will be made if the current
// one fails. If it returns true, the following call to Next is
// guaranteed to return true.
func (a *Attempt) HasNext() bool {
if a.force || a.strategy.Min > a.count {
return true
}
now := time.Now()
if now.Add(a.nextSleep(now)).Before(a.end) {
a.force = true
return true
}
return false
}
+314
View File
@@ -0,0 +1,314 @@
package util
import (
"encoding/json"
"fmt"
"log"
"net/url"
"reflect"
"strconv"
"strings"
"time"
)
// change instance=["a", "b"]
// to instance.1="a" instance.2="b"
func FlattenFn(fieldName string, field reflect.Value, values *url.Values) {
l := field.Len()
if l > 0 {
for i := 0; i < l; i++ {
str := field.Index(i).String()
values.Set(fieldName+"."+strconv.Itoa(i+1), str)
}
}
}
func Underline2Dot(name string) string {
return strings.Replace(name, "_", ".", -1)
}
//ConvertToQueryValues converts the struct to url.Values
func ConvertToQueryValues(ifc interface{}) url.Values {
values := url.Values{}
SetQueryValues(ifc, &values)
return values
}
//SetQueryValues sets the struct to existing url.Values following ECS encoding rules
func SetQueryValues(ifc interface{}, values *url.Values) {
setQueryValues(ifc, values, "")
}
func SetQueryValueByFlattenMethod(ifc interface{}, values *url.Values) {
setQueryValuesByFlattenMethod(ifc, values, "")
}
func setQueryValues(i interface{}, values *url.Values, prefix string) {
// add to support url.Values
mapValues, ok := i.(url.Values)
if ok {
for k, _ := range mapValues {
values.Set(k, mapValues.Get(k))
}
return
}
elem := reflect.ValueOf(i)
if elem.Kind() == reflect.Ptr {
elem = elem.Elem()
}
elemType := elem.Type()
for i := 0; i < elem.NumField(); i++ {
fieldName := elemType.Field(i).Name
anonymous := elemType.Field(i).Anonymous
field := elem.Field(i)
// TODO Use Tag for validation
// tag := typ.Field(i).Tag.Get("tagname")
kind := field.Kind()
if (kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map || kind == reflect.Chan) && field.IsNil() {
continue
}
if kind == reflect.Ptr {
field = field.Elem()
kind = field.Kind()
}
var value string
//switch field.Interface().(type) {
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i := field.Int()
if i != 0 {
value = strconv.FormatInt(i, 10)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
i := field.Uint()
if i != 0 {
value = strconv.FormatUint(i, 10)
}
case reflect.Float32:
value = strconv.FormatFloat(field.Float(), 'f', 4, 32)
case reflect.Float64:
value = strconv.FormatFloat(field.Float(), 'f', 4, 64)
case reflect.Bool:
value = strconv.FormatBool(field.Bool())
case reflect.String:
value = field.String()
case reflect.Map:
ifc := field.Interface()
m := ifc.(map[string]string)
if m != nil {
j := 0
for k, v := range m {
j++
keyName := fmt.Sprintf("%s.%d.Key", fieldName, j)
values.Set(keyName, k)
valueName := fmt.Sprintf("%s.%d.Value", fieldName, j)
values.Set(valueName, v)
}
}
case reflect.Slice:
switch field.Type().Elem().Kind() {
case reflect.Uint8:
value = string(field.Bytes())
case reflect.String:
l := field.Len()
if l > 0 {
strArray := make([]string, l)
for i := 0; i < l; i++ {
strArray[i] = field.Index(i).String()
}
bytes, err := json.Marshal(strArray)
if err == nil {
value = string(bytes)
} else {
log.Printf("Failed to convert JSON: %v", err)
}
}
default:
l := field.Len()
for j := 0; j < l; j++ {
prefixName := fmt.Sprintf("%s.%d.", fieldName, (j + 1))
ifc := field.Index(j).Interface()
//log.Printf("%s : %v", prefixName, ifc)
if ifc != nil {
setQueryValues(ifc, values, prefixName)
}
}
continue
}
default:
switch field.Interface().(type) {
case ISO6801Time:
t := field.Interface().(ISO6801Time)
value = t.String()
case time.Time:
t := field.Interface().(time.Time)
value = GetISO8601TimeStamp(t)
default:
ifc := field.Interface()
if ifc != nil {
if anonymous {
SetQueryValues(ifc, values)
} else {
prefixName := fieldName + "."
setQueryValues(ifc, values, prefixName)
}
continue
}
}
}
if value != "" {
name := elemType.Field(i).Tag.Get("ArgName")
if name == "" {
name = fieldName
}
if prefix != "" {
name = prefix + name
}
values.Set(name, value)
}
}
}
func setQueryValuesByFlattenMethod(i interface{}, values *url.Values, prefix string) {
// add to support url.Values
mapValues, ok := i.(url.Values)
if ok {
for k, _ := range mapValues {
values.Set(k, mapValues.Get(k))
}
return
}
elem := reflect.ValueOf(i)
if elem.Kind() == reflect.Ptr {
elem = elem.Elem()
}
elemType := elem.Type()
for i := 0; i < elem.NumField(); i++ {
fieldName := elemType.Field(i).Name
anonymous := elemType.Field(i).Anonymous
field := elem.Field(i)
// TODO Use Tag for validation
// tag := typ.Field(i).Tag.Get("tagname")
kind := field.Kind()
if (kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map || kind == reflect.Chan) && field.IsNil() {
continue
}
if kind == reflect.Ptr {
field = field.Elem()
kind = field.Kind()
}
var value string
//switch field.Interface().(type) {
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i := field.Int()
if i != 0 {
value = strconv.FormatInt(i, 10)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
i := field.Uint()
if i != 0 {
value = strconv.FormatUint(i, 10)
}
case reflect.Float32:
value = strconv.FormatFloat(field.Float(), 'f', 4, 32)
case reflect.Float64:
value = strconv.FormatFloat(field.Float(), 'f', 4, 64)
case reflect.Bool:
value = strconv.FormatBool(field.Bool())
case reflect.String:
value = field.String()
case reflect.Map:
ifc := field.Interface()
m := ifc.(map[string]string)
if m != nil {
j := 0
for k, v := range m {
j++
keyName := fmt.Sprintf("%s.%d.Key", fieldName, j)
values.Set(keyName, k)
valueName := fmt.Sprintf("%s.%d.Value", fieldName, j)
values.Set(valueName, v)
}
}
case reflect.Slice:
if field.Type().Name() == "FlattenArray" {
FlattenFn(fieldName, field, values)
} else {
switch field.Type().Elem().Kind() {
case reflect.Uint8:
value = string(field.Bytes())
case reflect.String:
l := field.Len()
if l > 0 {
strArray := make([]string, l)
for i := 0; i < l; i++ {
strArray[i] = field.Index(i).String()
}
bytes, err := json.Marshal(strArray)
if err == nil {
value = string(bytes)
} else {
log.Printf("Failed to convert JSON: %v", err)
}
}
default:
l := field.Len()
for j := 0; j < l; j++ {
prefixName := fmt.Sprintf("%s.%d.", fieldName, (j + 1))
ifc := field.Index(j).Interface()
//log.Printf("%s : %v", prefixName, ifc)
if ifc != nil {
setQueryValuesByFlattenMethod(ifc, values, prefixName)
}
}
continue
}
}
default:
switch field.Interface().(type) {
case ISO6801Time:
t := field.Interface().(ISO6801Time)
value = t.String()
case time.Time:
t := field.Interface().(time.Time)
value = GetISO8601TimeStamp(t)
default:
ifc := field.Interface()
if ifc != nil {
if anonymous {
SetQueryValues(ifc, values)
} else {
prefixName := fieldName + "."
setQueryValuesByFlattenMethod(ifc, values, prefixName)
}
continue
}
}
}
if value != "" {
name := elemType.Field(i).Tag.Get("ArgName")
if name == "" {
name = fieldName
}
if prefix != "" {
name = prefix + name
}
// NOTE: here we will change name to underline style when the type is UnderlineString
if field.Type().Name() == "UnderlineString" {
name = Underline2Dot(name)
}
values.Set(name, value)
}
}
}
+80
View File
@@ -0,0 +1,80 @@
package util
import (
"fmt"
"strconv"
"time"
)
// GetISO8601TimeStamp gets timestamp string in ISO8601 format
func GetISO8601TimeStamp(ts time.Time) string {
t := ts.UTC()
return fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
}
const formatISO8601 = "2006-01-02T15:04:05Z"
const jsonFormatISO8601 = `"` + formatISO8601 + `"`
const formatISO8601withoutSeconds = "2006-01-02T15:04Z"
const jsonFormatISO8601withoutSeconds = `"` + formatISO8601withoutSeconds + `"`
// A ISO6801Time represents a time in ISO8601 format
type ISO6801Time time.Time
// New constructs a new iso8601.Time instance from an existing
// time.Time instance. This causes the nanosecond field to be set to
// 0, and its time zone set to a fixed zone with no offset from UTC
// (but it is *not* UTC itself).
func NewISO6801Time(t time.Time) ISO6801Time {
return ISO6801Time(time.Date(
t.Year(),
t.Month(),
t.Day(),
t.Hour(),
t.Minute(),
t.Second(),
0,
time.UTC,
))
}
// IsDefault checks if the time is default
func (it *ISO6801Time) IsDefault() bool {
return *it == ISO6801Time{}
}
// MarshalJSON serializes the ISO6801Time into JSON string
func (it ISO6801Time) MarshalJSON() ([]byte, error) {
return []byte(time.Time(it).Format(jsonFormatISO8601)), nil
}
// UnmarshalJSON deserializes the ISO6801Time from JSON string
func (it *ISO6801Time) UnmarshalJSON(data []byte) error {
str := string(data)
if str == "\"\"" || len(data) == 0 {
return nil
}
var t time.Time
var err error
if str[0] == '"' {
t, err = time.ParseInLocation(jsonFormatISO8601, str, time.UTC)
if err != nil {
t, err = time.ParseInLocation(jsonFormatISO8601withoutSeconds, str, time.UTC)
}
} else {
var i int64
i, err = strconv.ParseInt(str, 10, 64)
if err == nil {
t = time.Unix(i/1000, i%1000)
}
}
if err == nil {
*it = ISO6801Time(t)
}
return err
}
// String returns the time in ISO6801Time format
func (it ISO6801Time) String() string {
return time.Time(it).Format(formatISO8601)
}
+40
View File
@@ -0,0 +1,40 @@
package util
import (
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"net/url"
"strings"
)
//CreateSignature creates signature for string following Aliyun rules
func CreateSignature(stringToSignature, accessKeySecret string) string {
// Crypto by HMAC-SHA1
hmacSha1 := hmac.New(sha1.New, []byte(accessKeySecret))
hmacSha1.Write([]byte(stringToSignature))
sign := hmacSha1.Sum(nil)
// Encode to Base64
base64Sign := base64.StdEncoding.EncodeToString(sign)
return base64Sign
}
func percentReplace(str string) string {
str = strings.Replace(str, "+", "%20", -1)
str = strings.Replace(str, "*", "%2A", -1)
str = strings.Replace(str, "%7E", "~", -1)
return str
}
// CreateSignatureForRequest creates signature for query string values
func CreateSignatureForRequest(method string, values *url.Values, accessKeySecret string) string {
canonicalizedQueryString := percentReplace(values.Encode())
stringToSign := method + "&%2F&" + url.QueryEscape(canonicalizedQueryString)
return CreateSignature(stringToSign, accessKeySecret)
}
+147
View File
@@ -0,0 +1,147 @@
package util
import (
"bytes"
srand "crypto/rand"
"encoding/binary"
"math/rand"
"net/http"
"net/url"
"sort"
"time"
)
const dictionary = "_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
//CreateRandomString create random string
func CreateRandomString() string {
b := make([]byte, 32)
l := len(dictionary)
_, err := srand.Read(b)
if err != nil {
// fail back to insecure rand
rand.Seed(time.Now().UnixNano())
for i := range b {
b[i] = dictionary[rand.Int()%l]
}
} else {
for i, v := range b {
b[i] = dictionary[v%byte(l)]
}
}
return string(b)
}
// Encode encodes the values into ``URL encoded'' form
// ("acl&bar=baz&foo=quux") sorted by key.
func Encode(v url.Values) string {
if v == nil {
return ""
}
var buf bytes.Buffer
keys := make([]string, 0, len(v))
for k := range v {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
vs := v[k]
prefix := url.QueryEscape(k)
for _, v := range vs {
if buf.Len() > 0 {
buf.WriteByte('&')
}
buf.WriteString(prefix)
if v != "" {
buf.WriteString("=")
buf.WriteString(url.QueryEscape(v))
}
}
}
return buf.String()
}
func GetGMTime() string {
return time.Now().UTC().Format(http.TimeFormat)
}
//
func randUint32() uint32 {
return randUint32Slice(1)[0]
}
func randUint32Slice(c int) []uint32 {
b := make([]byte, c*4)
_, err := srand.Read(b)
if err != nil {
// fail back to insecure rand
rand.Seed(time.Now().UnixNano())
for i := range b {
b[i] = byte(rand.Int())
}
}
n := make([]uint32, c)
for i := range n {
n[i] = binary.BigEndian.Uint32(b[i*4 : i*4+4])
}
return n
}
func toByte(n uint32, st, ed byte) byte {
return byte(n%uint32(ed-st+1) + uint32(st))
}
func toDigit(n uint32) byte {
return toByte(n, '0', '9')
}
func toLowerLetter(n uint32) byte {
return toByte(n, 'a', 'z')
}
func toUpperLetter(n uint32) byte {
return toByte(n, 'A', 'Z')
}
type convFunc func(uint32) byte
var convFuncs = []convFunc{toDigit, toLowerLetter, toUpperLetter}
// tools for generating a random ECS instance password
// from 8 to 30 char MUST contain digit upper, case letter and upper case letter
// http://docs.aliyun.com/#/pub/ecs/open-api/instance&createinstance
func GenerateRandomECSPassword() string {
// [8, 30]
l := int(randUint32()%23 + 8)
n := randUint32Slice(l)
b := make([]byte, l)
b[0] = toDigit(n[0])
b[1] = toLowerLetter(n[1])
b[2] = toUpperLetter(n[2])
for i := 3; i < l; i++ {
b[i] = convFuncs[n[i]%3](n[i])
}
s := make([]byte, l)
perm := rand.Perm(l)
for i, v := range perm {
s[v] = b[i]
}
return string(s)
}