├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── account.go ├── alias.go ├── async_config.go ├── cdn_events_trigger.go ├── client.go ├── client_test.go ├── config.go ├── connect.go ├── const.go ├── custom_domain.go ├── custom_domain_test.go ├── error.go ├── eventbridge_trigger.go ├── function.go ├── function_test.go ├── glide.lock ├── glide.yaml ├── go.mod ├── go.sum ├── http_trigger.go ├── instance_exec.go ├── layers.go ├── list_instances.go ├── log_trigger.go ├── mns_trigger.go ├── on_demand_config.go ├── on_demand_config_test.go ├── option.go ├── oss_temp_token.go ├── provision_config.go ├── provision_config_test.go ├── reserved_capacity.go ├── reserved_capacity_test.go ├── samples ├── glide.lock ├── hello_world.zip ├── instance_exec.go ├── layer.go ├── sample.go └── trigger.go ├── service.go ├── service_test.go ├── setup.sh ├── sign_url_request.go ├── sign_url_request_test.go ├── signature.go ├── signature_test.go ├── stateful_async_invocation.go ├── tablestore_trigger.go ├── tag.go ├── tag_test.go ├── testCode ├── hello_world.zip └── main.py ├── time_trigger.go ├── trigger.go ├── types.go ├── util.go ├── version.go ├── zip.go └── zip_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/ 3 | vendor/ 4 | bin/ 5 | .DS_Store 6 | TestZipDirWithSymbolLinks/ 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.8.x 5 | - 1.9.x 6 | - 1.10.x 7 | - 1.11.x 8 | 9 | script: 10 | - bash ./setup.sh 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Alibaba Cloud 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GOPATH=$(shell go env | grep GOPATH | sed 's/GOPATH=//' | sed 's/"//g') 2 | 3 | all: 4 | go build 5 | 6 | test: 7 | go test 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Aliyun FunctionCompute Go SDK 2 | 3 | API Reference : 4 | 5 | [FC API](https://help.aliyun.com/document_detail/52877.html) 6 | 7 | [![GitHub Version](https://badge.fury.io/gh/aliyun%2Ffc-go-sdk.svg)](https://badge.fury.io/gh/aliyun%2Ffc-go-sdk) 8 | [![Build Status](https://travis-ci.org/aliyun/fc-go-sdk.svg?branch=master)](https://travis-ci.org/aliyun/fc-go-sdk) 9 | 10 | 11 | 12 | ## VERSION 13 | 14 | go >= 1.8 15 | 16 | ## Overview 17 | 18 | Aliyun FunctionCompute Go SDK, sample 19 | 20 | ```go 21 | package main 22 | 23 | import ( 24 | "fmt" 25 | "os" 26 | "github.com/aliyun/fc-go-sdk" 27 | ) 28 | 29 | func main() { 30 | serviceName := "service555" 31 | client, _ := fc.NewClient(os.Getenv("ENDPOINT"), "2016-08-15", os.Getenv("ACCESS_KEY_ID"), os.Getenv("ACCESS_KEY_SECRET")) 32 | 33 | fmt.Println("Creating service") 34 | createServiceOutput, err := client.CreateService(fc.NewCreateServiceInput(). 35 | WithServiceName(serviceName). 36 | WithDescription("this is a smoke test for go sdk")) 37 | if err != nil { 38 | fmt.Fprintln(os.Stderr, err) 39 | } 40 | if createServiceOutput != nil { 41 | fmt.Printf("CreateService response: %s \n", createServiceOutput) 42 | } 43 | 44 | // GetService 45 | fmt.Println("Getting service") 46 | getServiceOutput, err := client.GetService(fc.NewGetServiceInput(serviceName)) 47 | if err != nil { 48 | fmt.Fprintln(os.Stderr, err) 49 | } else { 50 | fmt.Printf("GetService response: %s \n", getServiceOutput) 51 | } 52 | 53 | // UpdateService 54 | fmt.Println("Updating service") 55 | updateServiceInput := fc.NewUpdateServiceInput(serviceName).WithDescription("new description") 56 | updateServiceOutput, err := client.UpdateService(updateServiceInput) 57 | if err != nil { 58 | fmt.Fprintln(os.Stderr, err) 59 | } else { 60 | fmt.Printf("UpdateService response: %s \n", updateServiceOutput) 61 | } 62 | 63 | // UpdateService with IfMatch 64 | fmt.Println("Updating service with IfMatch") 65 | updateServiceInput2 := fc.NewUpdateServiceInput(serviceName).WithDescription("new description2"). 66 | WithIfMatch(updateServiceOutput.Header.Get("ETag")) 67 | updateServiceOutput2, err := client.UpdateService(updateServiceInput2) 68 | if err != nil { 69 | fmt.Fprintln(os.Stderr, err) 70 | } else { 71 | fmt.Printf("UpdateService response: %s \n", updateServiceOutput2) 72 | } 73 | 74 | // UpdateService with wrong IfMatch 75 | fmt.Println("Updating service with wrong IfMatch") 76 | updateServiceInput3 := fc.NewUpdateServiceInput(serviceName).WithDescription("new description2"). 77 | WithIfMatch("1234") 78 | updateServiceOutput3, err := client.UpdateService(updateServiceInput3) 79 | if err != nil { 80 | fmt.Fprintln(os.Stderr, err) 81 | } else { 82 | fmt.Printf("UpdateService response: %s \n", updateServiceOutput3) 83 | } 84 | 85 | // ListServices 86 | fmt.Println("Listing services") 87 | listServicesOutput, err := client.ListServices(fc.NewListServicesInput().WithLimit(100)) 88 | if err != nil { 89 | fmt.Fprintln(os.Stderr, err) 90 | } else { 91 | fmt.Printf("ListServices response: %s \n", listServicesOutput) 92 | } 93 | 94 | // CreateFunction 95 | fmt.Println("Creating function1") 96 | createFunctionInput1 := fc.NewCreateFunctionInput(serviceName).WithFunctionName("testf1"). 97 | WithDescription("go sdk test function"). 98 | WithHandler("main.my_handler").WithRuntime("python2.7"). 99 | WithCode(fc.NewCode().WithFiles("./testCode/hello_world.zip")). 100 | WithTimeout(5) 101 | 102 | createFunctionOutput, err := client.CreateFunction(createFunctionInput1) 103 | if err != nil { 104 | fmt.Fprintln(os.Stderr, err) 105 | } else { 106 | fmt.Printf("CreateFunction response: %s \n", createFunctionOutput) 107 | } 108 | fmt.Println("Creating function2") 109 | createFunctionOutput2, err := client.CreateFunction(createFunctionInput1.WithFunctionName("testf2")) 110 | if err != nil { 111 | fmt.Fprintln(os.Stderr, err) 112 | } else { 113 | fmt.Printf("CreateFunction response: %s \n", createFunctionOutput2) 114 | } 115 | 116 | // ListFunctions 117 | fmt.Println("Listing functions") 118 | listFunctionsOutput, err := client.ListFunctions(fc.NewListFunctionsInput(serviceName).WithPrefix("test")) 119 | if err != nil { 120 | fmt.Fprintln(os.Stderr, err) 121 | } else { 122 | fmt.Printf("ListFunctions response: %s \n", listFunctionsOutput) 123 | } 124 | 125 | // UpdateFunction 126 | fmt.Println("Updating function") 127 | updateFunctionOutput, err := client.UpdateFunction(fc.NewUpdateFunctionInput(serviceName, "testf1"). 128 | WithDescription("newdesc")) 129 | if err != nil { 130 | fmt.Fprintln(os.Stderr, err) 131 | } else { 132 | fmt.Printf("UpdateFunction response: %s \n", updateFunctionOutput) 133 | } 134 | 135 | // InvokeFunction 136 | fmt.Println("Invoking function, log type Tail") 137 | invokeInput := fc.NewInvokeFunctionInput(serviceName, "testf1").WithLogType("Tail") 138 | invokeOutput, err := client.InvokeFunction(invokeInput) 139 | if err != nil { 140 | fmt.Fprintln(os.Stderr, err) 141 | } else { 142 | fmt.Printf("InvokeFunction response: %s \n", invokeOutput) 143 | logResult, err := invokeOutput.GetLogResult() 144 | if err != nil { 145 | fmt.Printf("Failed to get LogResult due to %v\n", err) 146 | } else { 147 | fmt.Printf("Invoke function LogResult %s \n", logResult) 148 | } 149 | } 150 | 151 | fmt.Println("Invoking function, log type None") 152 | invokeInput = fc.NewInvokeFunctionInput(serviceName, "testf1").WithLogType("None") 153 | invokeOutput, err = client.InvokeFunction(invokeInput) 154 | if err != nil { 155 | fmt.Fprintln(os.Stderr, err) 156 | } else { 157 | fmt.Printf("InvokeFunction response: %s \n", invokeOutput) 158 | } 159 | 160 | // PublishServiceVersion 161 | fmt.Println("Publishing service version") 162 | publishServiceVersionInput := fc.NewPublishServiceVersionInput(serviceName) 163 | publishServiceVersionOutput, err := client.PublishServiceVersion(publishServiceVersionInput) 164 | if err != nil { 165 | fmt.Fprintln(os.Stderr, err) 166 | } else { 167 | fmt.Printf("PublishServiceVersion response: %s \n", publishServiceVersionOutput) 168 | } 169 | 170 | // PublishServiceVersion with IfMatch 171 | fmt.Println("Publishing service version with IfMatch") 172 | publishServiceVersionInput2 := fc.NewPublishServiceVersionInput(serviceName). 173 | WithIfMatch(getServiceOutput.Header.Get("ETag")) 174 | publishServiceVersionOutput2, err := client.PublishServiceVersion(publishServiceVersionInput2) 175 | if err != nil { 176 | fmt.Fprintln(os.Stderr, err) 177 | } else { 178 | fmt.Printf("PublishServiceVersion response: %s \n", publishServiceVersionOutput2) 179 | } 180 | 181 | // PublishServiceVersion with wrong IfMatch 182 | fmt.Println("Publishing service with wrong IfMatch") 183 | publishServiceVersionInput3 := fc.NewPublishServiceVersionInput(serviceName). 184 | WithIfMatch("1234") 185 | publishServiceVersionOutput3, err := client.PublishServiceVersion(publishServiceVersionInput3) 186 | if err != nil { 187 | fmt.Fprintln(os.Stderr, err) 188 | } else { 189 | fmt.Printf("PublishServiceVersion response: %s \n", publishServiceVersionOutput3) 190 | } 191 | 192 | // ListServiceVersions 193 | fmt.Println("Listing service versions") 194 | listServiceVersionsOutput, err := client.ListServiceVersions(fc.NewListServiceVersionsInput(serviceName).WithLimit(10)) 195 | if err != nil { 196 | fmt.Fprintln(os.Stderr, err) 197 | } else { 198 | fmt.Printf("ListServiceVersions response: %s \n", listServiceVersionsOutput) 199 | } 200 | 201 | // GetService with qualifier 202 | fmt.Println("Getting service with qualifier") 203 | getServiceOutput2, err := client.GetService(fc.NewGetServiceInput(serviceName).WithQualifier(publishServiceVersionOutput.VersionID)) 204 | if err != nil { 205 | fmt.Fprintln(os.Stderr, err) 206 | } else { 207 | fmt.Printf("GetService with qualifier response: %s \n", getServiceOutput2) 208 | } 209 | 210 | // CreateAlias 211 | aliasName := "alias" 212 | fmt.Println("Creating alias") 213 | createAliasOutput, err := client.CreateAlias(fc.NewCreateAliasInput(serviceName).WithAliasName(aliasName).WithVersionID(publishServiceVersionOutput.VersionID)) 214 | if err != nil { 215 | fmt.Fprintln(os.Stderr, err) 216 | } else { 217 | fmt.Printf("CreateAlias response: %s \n", createAliasOutput) 218 | } 219 | 220 | // GetAlias 221 | fmt.Println("Getting alias") 222 | getAliasOutput, err := client.GetAlias(fc.NewGetAliasInput(serviceName, aliasName)) 223 | if err != nil { 224 | fmt.Fprintln(os.Stderr, err) 225 | } else { 226 | fmt.Printf("GetAlias response: %s \n", getAliasOutput) 227 | } 228 | 229 | // UpdateAlias 230 | fmt.Println("Updating alias") 231 | updateAliasOutput, err := client.UpdateAlias(fc.NewUpdateAliasInput(serviceName, aliasName).WithVersionID(publishServiceVersionOutput2.VersionID)) 232 | if err != nil { 233 | fmt.Fprintln(os.Stderr, err) 234 | } else { 235 | fmt.Printf("UpdateAlias response: %s \n", updateAliasOutput) 236 | } 237 | 238 | // ListAliases 239 | fmt.Println("Listing aliases") 240 | listAliasesOutput, err := client.ListAliases(fc.NewListAliasesInput(serviceName)) 241 | if err != nil { 242 | fmt.Fprintln(os.Stderr, err) 243 | } else { 244 | fmt.Printf("ListAliases response: %s \n", listAliasesOutput) 245 | } 246 | 247 | // DeleteAlias 248 | fmt.Println("Deleting aliases") 249 | deleteAliasOutput, err := client.DeleteAlias(fc.NewDeleteAliasInput(serviceName, aliasName)) 250 | if err != nil { 251 | fmt.Fprintln(os.Stderr, err) 252 | } else { 253 | fmt.Printf("DeleteAlias response: %s \n", deleteAliasOutput) 254 | } 255 | 256 | // DeleteServiceVersion 257 | fmt.Println("Deleting service version") 258 | deleteServiceVersionOutput, err := client.DeleteServiceVersion(fc.NewDeleteServiceVersionInput(serviceName, publishServiceVersionOutput.VersionID)) 259 | if err != nil { 260 | fmt.Fprintln(os.Stderr, err) 261 | } else { 262 | fmt.Printf("DeleteServiceVersion response: %s \n", deleteServiceVersionOutput) 263 | } 264 | 265 | deleteServiceVersionOutput2, err := client.DeleteServiceVersion(fc.NewDeleteServiceVersionInput(serviceName, publishServiceVersionOutput2.VersionID)) 266 | if err != nil { 267 | fmt.Fprintln(os.Stderr, err) 268 | } else { 269 | fmt.Printf("DeleteServiceVersion response: %s \n", deleteServiceVersionOutput2) 270 | } 271 | 272 | // DeleteFunction 273 | fmt.Println("Deleting functions") 274 | listFunctionsOutput, err = client.ListFunctions(fc.NewListFunctionsInput(serviceName).WithLimit(10)) 275 | if err != nil { 276 | fmt.Fprintln(os.Stderr, err) 277 | } else { 278 | fmt.Printf("ListFunctions response: %s \n", listFunctionsOutput) 279 | for _, fuc := range listFunctionsOutput.Functions { 280 | fmt.Printf("Deleting function %s \n", *fuc.FunctionName) 281 | if output, err := client.DeleteFunction(fc.NewDeleteFunctionInput(serviceName, *fuc.FunctionName)); err != nil { 282 | fmt.Fprintln(os.Stderr, err) 283 | } else { 284 | fmt.Printf("DeleteFunction response: %s \n", output) 285 | } 286 | 287 | } 288 | } 289 | 290 | // DeleteService 291 | fmt.Println("Deleting service") 292 | deleteServiceOutput, err := client.DeleteService(fc.NewDeleteServiceInput(serviceName)) 293 | if err != nil { 294 | fmt.Fprintln(os.Stderr, err) 295 | } else { 296 | fmt.Printf("DeleteService response: %s \n", deleteServiceOutput) 297 | } 298 | 299 | // PutProvisionConfig 300 | fmt.Println("Putting provision config") 301 | putProvisionConfigOutput, err := client.PutProvisionConfig(fc.NewPutProvisionConfigInput(serviceName, "testAliasName", "testFunctionName").WithTarget(int64(100)) 302 | if err != nil { 303 | fmt.Fprintln(os.Stderr, err) 304 | } else { 305 | fmt.Printf("PutProvisionConfig response: %s \n", putProvisionConfigOutput) 306 | } 307 | 308 | // GetProvisionConfig 309 | fmt.Println("Getting provision config") 310 | getProvisionConfigOutput, err := client.GetProvisionConfig(fc.NewGetProvisionConfigInput(serviceName, "testAliasName", "testFunctionName")) 311 | if err != nil { 312 | fmt.Fprintln(os.Stderr, err) 313 | } else { 314 | fmt.Printf("GetProvisionConfig response: %s \n", getProvisionConfigOutput) 315 | } 316 | 317 | // ListProvisionConfigs 318 | fmt.Println("Listing provision configs") 319 | listProvisionConfigsOutput, err := client.ListProvisionConfigs(fc.NewListProvisionConfigsInput()) 320 | if err != nil { 321 | fmt.Fprintln(os.Stderr, err) 322 | } else { 323 | fmt.Printf("ListProvisionConfigs response: %s \n", listProvisionConfigsOutput) 324 | } 325 | } 326 | 327 | ``` 328 | 329 | ## More resources 330 | 331 | - [Aliyun FunctionCompute docs](https://help.aliyun.com/product/50980.html) 332 | 333 | ## Contacting us 334 | 335 | - [Links](https://help.aliyun.com/document_detail/53087.html) 336 | 337 | ## License 338 | 339 | - [MIT](https://github.com/aliyun/fc-python-sdk/blob/master/LICENSE) 340 | -------------------------------------------------------------------------------- /account.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | "net/url" 7 | ) 8 | 9 | const ( 10 | accountPath = "/account-settings" 11 | ) 12 | 13 | type accountSettings struct { 14 | AvailableAZs []string `json:"availableAZs"` 15 | } 16 | 17 | // GetAccountSettingsInput defines get account settings intput. 18 | type GetAccountSettingsInput struct { 19 | } 20 | 21 | func NewGetAccountSettingsInput() *GetAccountSettingsInput { 22 | return new(GetAccountSettingsInput) 23 | } 24 | 25 | func (o *GetAccountSettingsInput) GetQueryParams() url.Values { 26 | out := url.Values{} 27 | return out 28 | } 29 | 30 | func (o *GetAccountSettingsInput) GetPath() string { 31 | return accountPath 32 | } 33 | 34 | func (o *GetAccountSettingsInput) GetHeaders() Header { 35 | return make(Header, 0) 36 | } 37 | 38 | func (o *GetAccountSettingsInput) GetPayload() interface{} { 39 | return nil 40 | } 41 | 42 | func (o *GetAccountSettingsInput) Validate() error { 43 | return nil 44 | } 45 | 46 | // GetAccountSettingsOutput defines get account settings output. 47 | type GetAccountSettingsOutput struct { 48 | Header http.Header 49 | accountSettings 50 | } 51 | 52 | func (o GetAccountSettingsOutput) String() string { 53 | b, err := json.MarshalIndent(o, "", printIndent) 54 | if err != nil { 55 | return "" 56 | } 57 | return string(b) 58 | } 59 | 60 | func (o GetAccountSettingsOutput) GetRequestID() string { 61 | return GetRequestID(o.Header) 62 | } 63 | -------------------------------------------------------------------------------- /alias.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | "strconv" 9 | ) 10 | 11 | type aliasMetadata struct { 12 | AliasName *string `json:"aliasName"` 13 | VersionID *string `json:"versionId"` 14 | Description *string `json:"description"` 15 | AdditionalVersionWeight map[string]float64 `json:"additionalVersionWeight"` 16 | } 17 | 18 | type AliasCreateObject struct { 19 | AliasName *string `json:"aliasName"` 20 | VersionID *string `json:"versionId"` 21 | Description *string `json:"description"` 22 | AdditionalVersionWeight map[string]float64 `json:"additionalVersionWeight"` 23 | } 24 | 25 | type CreateAliasInput struct { 26 | ServiceName *string `json:"serviceName"` 27 | AliasCreateObject 28 | } 29 | 30 | func NewCreateAliasInput(serviceName string) *CreateAliasInput { 31 | return &CreateAliasInput{ServiceName: &serviceName} 32 | } 33 | 34 | func (i *CreateAliasInput) WithAliasName(aliasName string) *CreateAliasInput { 35 | i.AliasName = &aliasName 36 | return i 37 | } 38 | 39 | func (i *CreateAliasInput) WithDescription(description string) *CreateAliasInput { 40 | i.Description = &description 41 | return i 42 | } 43 | 44 | func (i *CreateAliasInput) WithVersionID(versionID string) *CreateAliasInput { 45 | i.VersionID = &versionID 46 | return i 47 | } 48 | 49 | func (i *CreateAliasInput) WithAdditionalVersionWeight(additionalVersionWeight map[string]float64) *CreateAliasInput { 50 | i.AdditionalVersionWeight = additionalVersionWeight 51 | return i 52 | } 53 | 54 | func (i *CreateAliasInput) GetQueryParams() url.Values { 55 | out := url.Values{} 56 | return out 57 | } 58 | 59 | func (i *CreateAliasInput) GetPath() string { 60 | return fmt.Sprintf(aliasesPath, pathEscape(*i.ServiceName)) 61 | } 62 | 63 | func (i *CreateAliasInput) GetHeaders() Header { 64 | return make(Header, 0) 65 | } 66 | 67 | func (i *CreateAliasInput) GetPayload() interface{} { 68 | return i.AliasCreateObject 69 | } 70 | 71 | func (i *CreateAliasInput) Validate() error { 72 | if IsBlank(i.ServiceName) { 73 | return fmt.Errorf("Service name is required but not provided") 74 | } 75 | return nil 76 | } 77 | 78 | type CreateAliasOutput struct { 79 | Header http.Header 80 | aliasMetadata 81 | } 82 | 83 | func (o CreateAliasOutput) String() string { 84 | b, err := json.MarshalIndent(o, "", printIndent) 85 | if err != nil { 86 | return "" 87 | } 88 | return string(b) 89 | } 90 | 91 | func (o CreateAliasOutput) GetRequestID() string { 92 | return GetRequestID(o.Header) 93 | } 94 | 95 | func (o CreateAliasOutput) GetEtag() string { 96 | return GetEtag(o.Header) 97 | } 98 | 99 | type AliasUpdateObject struct { 100 | VersionID *string `json:"versionId"` 101 | Description *string `json:"description"` 102 | AdditionalVersionWeight map[string]float64 `json:"additionalVersionWeight"` 103 | } 104 | 105 | type UpdateAliasInput struct { 106 | ServiceName *string 107 | AliasName *string 108 | AliasUpdateObject 109 | IfMatch *string 110 | } 111 | 112 | func NewUpdateAliasInput(serviceName, aliasName string) *UpdateAliasInput { 113 | return &UpdateAliasInput{ServiceName: &serviceName, AliasName: &aliasName} 114 | } 115 | 116 | func (s *UpdateAliasInput) WithDescription(description string) *UpdateAliasInput { 117 | s.Description = &description 118 | return s 119 | } 120 | 121 | func (s *UpdateAliasInput) WithVersionID(versionID string) *UpdateAliasInput { 122 | s.VersionID = &versionID 123 | return s 124 | } 125 | 126 | func (s *UpdateAliasInput) WithAdditionalVersionWeight(additionalVersionWeight map[string]float64) *UpdateAliasInput { 127 | s.AdditionalVersionWeight = additionalVersionWeight 128 | return s 129 | } 130 | 131 | func (s *UpdateAliasInput) WithIfMatch(ifMatch string) *UpdateAliasInput { 132 | s.IfMatch = &ifMatch 133 | return s 134 | } 135 | 136 | func (i *UpdateAliasInput) GetQueryParams() url.Values { 137 | out := url.Values{} 138 | return out 139 | } 140 | 141 | func (i *UpdateAliasInput) GetPath() string { 142 | return fmt.Sprintf(singleAliasPath, pathEscape(*i.ServiceName), pathEscape(*i.AliasName)) 143 | } 144 | 145 | func (i *UpdateAliasInput) GetHeaders() Header { 146 | header := make(Header) 147 | if i.IfMatch != nil { 148 | header[ifMatch] = *i.IfMatch 149 | } 150 | return header 151 | } 152 | 153 | func (i *UpdateAliasInput) GetPayload() interface{} { 154 | return i.AliasUpdateObject 155 | } 156 | 157 | func (i *UpdateAliasInput) Validate() error { 158 | if IsBlank(i.ServiceName) { 159 | return fmt.Errorf("Service name is required but not provided") 160 | } 161 | if IsBlank(i.AliasName) { 162 | return fmt.Errorf("Alias name is required but not provided") 163 | } 164 | return nil 165 | } 166 | 167 | type UpdateAliasOutput struct { 168 | Header http.Header 169 | aliasMetadata 170 | } 171 | 172 | func (o UpdateAliasOutput) String() string { 173 | b, err := json.MarshalIndent(o, "", printIndent) 174 | if err != nil { 175 | return "" 176 | } 177 | return string(b) 178 | } 179 | 180 | func (o UpdateAliasOutput) GetRequestID() string { 181 | return GetRequestID(o.Header) 182 | } 183 | 184 | func (o UpdateAliasOutput) GetEtag() string { 185 | return GetEtag(o.Header) 186 | } 187 | 188 | type ListAliasesInput struct { 189 | ServiceName *string 190 | Query 191 | } 192 | 193 | func NewListAliasesInput(serviceName string) *ListAliasesInput { 194 | return &ListAliasesInput{ServiceName: &serviceName} 195 | } 196 | 197 | func (i *ListAliasesInput) WithPrefix(prefix string) *ListAliasesInput { 198 | i.Prefix = &prefix 199 | return i 200 | } 201 | 202 | func (i *ListAliasesInput) WithStartKey(startKey string) *ListAliasesInput { 203 | i.StartKey = &startKey 204 | return i 205 | } 206 | 207 | func (i *ListAliasesInput) WithNextToken(nextToken string) *ListAliasesInput { 208 | i.NextToken = &nextToken 209 | return i 210 | } 211 | 212 | func (i *ListAliasesInput) WithLimit(limit int32) *ListAliasesInput { 213 | i.Limit = &limit 214 | return i 215 | } 216 | 217 | func (i *ListAliasesInput) GetQueryParams() url.Values { 218 | out := url.Values{} 219 | if i.Prefix != nil { 220 | out.Set("prefix", *i.Prefix) 221 | } 222 | 223 | if i.StartKey != nil { 224 | out.Set("startKey", *i.StartKey) 225 | } 226 | 227 | if i.NextToken != nil { 228 | out.Set("nextToken", *i.NextToken) 229 | } 230 | 231 | if i.Limit != nil { 232 | out.Set("limit", strconv.FormatInt(int64(*i.Limit), 10)) 233 | } 234 | 235 | return out 236 | } 237 | 238 | func (i *ListAliasesInput) GetPath() string { 239 | return fmt.Sprintf(aliasesPath, pathEscape(*i.ServiceName)) 240 | } 241 | 242 | func (i *ListAliasesInput) GetHeaders() Header { 243 | return make(Header, 0) 244 | } 245 | 246 | func (i *ListAliasesInput) GetPayload() interface{} { 247 | return nil 248 | } 249 | 250 | func (i *ListAliasesInput) Validate() error { 251 | if IsBlank(i.ServiceName) { 252 | return fmt.Errorf("Service name is required but not provided") 253 | } 254 | return nil 255 | } 256 | 257 | type ListAliasesOutput struct { 258 | Header http.Header 259 | Aliases []*aliasMetadata `json:"aliases"` 260 | NextToken *string `json:"nextToken,omitempty"` 261 | } 262 | 263 | func (o ListAliasesOutput) String() string { 264 | b, err := json.MarshalIndent(o, "", printIndent) 265 | if err != nil { 266 | return "" 267 | } 268 | return string(b) 269 | } 270 | 271 | func (o ListAliasesOutput) GetRequestID() string { 272 | return GetRequestID(o.Header) 273 | } 274 | 275 | type GetAliasInput struct { 276 | ServiceName *string 277 | AliasName *string 278 | } 279 | 280 | func NewGetAliasInput(serviceName, aliasName string) *GetAliasInput { 281 | return &GetAliasInput{ServiceName: &serviceName, AliasName: &aliasName} 282 | } 283 | 284 | func (i *GetAliasInput) GetQueryParams() url.Values { 285 | out := url.Values{} 286 | return out 287 | } 288 | 289 | func (i *GetAliasInput) GetPath() string { 290 | return fmt.Sprintf(singleAliasPath, pathEscape(*i.ServiceName), pathEscape(*i.AliasName)) 291 | } 292 | 293 | func (i *GetAliasInput) GetHeaders() Header { 294 | return make(Header, 0) 295 | } 296 | 297 | func (i *GetAliasInput) GetPayload() interface{} { 298 | return nil 299 | } 300 | 301 | func (i *GetAliasInput) Validate() error { 302 | if IsBlank(i.ServiceName) { 303 | return fmt.Errorf("Service name is required but not provided") 304 | } 305 | if IsBlank(i.AliasName) { 306 | return fmt.Errorf("Alias name is required but not provided") 307 | } 308 | return nil 309 | } 310 | 311 | type GetAliasOutput struct { 312 | Header http.Header 313 | aliasMetadata 314 | } 315 | 316 | func (o GetAliasOutput) String() string { 317 | b, err := json.MarshalIndent(o, "", printIndent) 318 | if err != nil { 319 | return "" 320 | } 321 | return string(b) 322 | } 323 | 324 | func (o GetAliasOutput) GetRequestID() string { 325 | return GetRequestID(o.Header) 326 | } 327 | 328 | func (o GetAliasOutput) GetEtag() string { 329 | return GetEtag(o.Header) 330 | } 331 | 332 | type DeleteAliasInput struct { 333 | ServiceName *string 334 | AliasName *string 335 | IfMatch *string 336 | } 337 | 338 | func NewDeleteAliasInput(serviceName, aliasName string) *DeleteAliasInput { 339 | return &DeleteAliasInput{ServiceName: &serviceName, AliasName: &aliasName} 340 | } 341 | 342 | func (s *DeleteAliasInput) WithIfMatch(ifMatch string) *DeleteAliasInput { 343 | s.IfMatch = &ifMatch 344 | return s 345 | } 346 | 347 | func (i *DeleteAliasInput) GetQueryParams() url.Values { 348 | out := url.Values{} 349 | return out 350 | } 351 | 352 | func (i *DeleteAliasInput) GetPath() string { 353 | return fmt.Sprintf(singleAliasPath, pathEscape(*i.ServiceName), pathEscape(*i.AliasName)) 354 | } 355 | 356 | func (i *DeleteAliasInput) GetHeaders() Header { 357 | header := make(Header) 358 | if i.IfMatch != nil { 359 | header[ifMatch] = *i.IfMatch 360 | } 361 | return header 362 | } 363 | 364 | func (i *DeleteAliasInput) GetPayload() interface{} { 365 | return nil 366 | } 367 | 368 | func (i *DeleteAliasInput) Validate() error { 369 | if IsBlank(i.ServiceName) { 370 | return fmt.Errorf("Service name is required but not provided") 371 | } 372 | if IsBlank(i.AliasName) { 373 | return fmt.Errorf("Alias name is required but not provided") 374 | } 375 | return nil 376 | } 377 | 378 | type DeleteAliasOutput struct { 379 | Header http.Header 380 | } 381 | 382 | func (o DeleteAliasOutput) String() string { 383 | b, err := json.MarshalIndent(o, "", printIndent) 384 | if err != nil { 385 | return "" 386 | } 387 | return string(b) 388 | } 389 | 390 | func (o DeleteAliasOutput) GetRequestID() string { 391 | return GetRequestID(o.Header) 392 | } 393 | -------------------------------------------------------------------------------- /async_config.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | "strconv" 9 | ) 10 | 11 | // AsyncConfig represents the async configuration. 12 | type AsyncConfig struct { 13 | StatefulInvocation *bool `json:"statefulInvocation"` 14 | DestinationConfig *DestinationConfig `json:"destinationConfig"` 15 | MaxAsyncEventAgeInSeconds *int64 `json:"maxAsyncEventAgeInSeconds"` 16 | MaxAsyncRetryAttempts *int64 `json:"maxAsyncRetryAttempts"` 17 | } 18 | 19 | // AsyncConfigResponse defines the detail async config object 20 | type AsyncConfigResponse struct { 21 | Service *string `json:"service"` 22 | Function *string `json:"function"` 23 | CreatedTime *string `json:"createdTime"` 24 | Qualifier *string `json:"qualifier"` 25 | LastModifiedTime *string `json:"lastModifiedTime"` 26 | AsyncConfig 27 | } 28 | 29 | // DestinationConfig represents the destination configuration. 30 | type DestinationConfig struct { 31 | OnSuccess *Destination `json:"onSuccess"` 32 | OnFailure *Destination `json:"onFailure"` 33 | } 34 | 35 | // Destination represents the destination arn. 36 | type Destination struct { 37 | Destination *string `json:"destination"` 38 | } 39 | 40 | // PutFunctionAsyncInvokeConfigInput defines function creation input 41 | type PutFunctionAsyncInvokeConfigInput struct { 42 | ServiceName *string `json:"serviceName"` 43 | Qualifier *string `json:"qualifier"` 44 | FunctionName *string `json:"functionName"` 45 | AsyncConfig 46 | } 47 | 48 | func NewPutFunctionAsyncInvokeConfigInput(serviceName, functionName string) *PutFunctionAsyncInvokeConfigInput { 49 | return &PutFunctionAsyncInvokeConfigInput{ServiceName: &serviceName, FunctionName: &functionName} 50 | } 51 | 52 | func (i *PutFunctionAsyncInvokeConfigInput) WithQualifier(qualifier string) *PutFunctionAsyncInvokeConfigInput { 53 | i.Qualifier = &qualifier 54 | return i 55 | } 56 | 57 | func (i *PutFunctionAsyncInvokeConfigInput) WithAsyncConfig(config AsyncConfig) *PutFunctionAsyncInvokeConfigInput { 58 | i.AsyncConfig = config 59 | return i 60 | } 61 | 62 | func (i *PutFunctionAsyncInvokeConfigInput) GetQueryParams() url.Values { 63 | out := url.Values{} 64 | return out 65 | } 66 | 67 | func (i *PutFunctionAsyncInvokeConfigInput) GetPath() string { 68 | if !IsBlank(i.Qualifier) { 69 | return fmt.Sprintf(asyncConfigWithQualifierPath, 70 | pathEscape(*i.ServiceName), pathEscape(*i.Qualifier), pathEscape(*i.FunctionName)) 71 | } 72 | return fmt.Sprintf(asyncConfigPath, pathEscape(*i.ServiceName), pathEscape(*i.FunctionName)) 73 | } 74 | 75 | func (i *PutFunctionAsyncInvokeConfigInput) GetHeaders() Header { 76 | header := make(Header) 77 | return header 78 | } 79 | 80 | func (i *PutFunctionAsyncInvokeConfigInput) GetPayload() interface{} { 81 | return i.AsyncConfig 82 | } 83 | 84 | func (i *PutFunctionAsyncInvokeConfigInput) Validate() error { 85 | if IsBlank(i.ServiceName) { 86 | return fmt.Errorf("Service name is required but not provided") 87 | } 88 | if IsBlank(i.FunctionName) { 89 | return fmt.Errorf("Function name is required but not provided") 90 | } 91 | return nil 92 | } 93 | 94 | // PutFunctionAsyncInvokeConfigOutput define get async config response 95 | type PutFunctionAsyncInvokeConfigOutput struct { 96 | Header http.Header 97 | AsyncConfigResponse 98 | } 99 | 100 | func (o PutFunctionAsyncInvokeConfigOutput) String() string { 101 | b, err := json.MarshalIndent(o, "", printIndent) 102 | if err != nil { 103 | return "" 104 | } 105 | return string(b) 106 | } 107 | 108 | func (o PutFunctionAsyncInvokeConfigOutput) GetRequestID() string { 109 | return GetRequestID(o.Header) 110 | } 111 | 112 | // GetFunctionAsyncInvokeConfigInput defines function creation input 113 | type GetFunctionAsyncInvokeConfigInput struct { 114 | ServiceName *string `json:"serviceName"` 115 | Qualifier *string `json:"qualifier"` 116 | FunctionName *string `json:"functionName"` 117 | } 118 | 119 | func NewGetFunctionAsyncInvokeConfigInput(serviceName, functionName string) *GetFunctionAsyncInvokeConfigInput { 120 | return &GetFunctionAsyncInvokeConfigInput{ServiceName: &serviceName, FunctionName: &functionName} 121 | } 122 | 123 | func (i *GetFunctionAsyncInvokeConfigInput) WithQualifier(qualifier string) *GetFunctionAsyncInvokeConfigInput { 124 | i.Qualifier = &qualifier 125 | return i 126 | } 127 | 128 | func (i *GetFunctionAsyncInvokeConfigInput) GetQueryParams() url.Values { 129 | out := url.Values{} 130 | return out 131 | } 132 | 133 | func (i *GetFunctionAsyncInvokeConfigInput) GetPath() string { 134 | if !IsBlank(i.Qualifier) { 135 | return fmt.Sprintf(asyncConfigWithQualifierPath, 136 | pathEscape(*i.ServiceName), pathEscape(*i.Qualifier), pathEscape(*i.FunctionName)) 137 | } 138 | return fmt.Sprintf(asyncConfigPath, pathEscape(*i.ServiceName), pathEscape(*i.FunctionName)) 139 | } 140 | 141 | func (i *GetFunctionAsyncInvokeConfigInput) GetHeaders() Header { 142 | header := make(Header) 143 | return header 144 | } 145 | 146 | func (i *GetFunctionAsyncInvokeConfigInput) GetPayload() interface{} { 147 | return nil 148 | } 149 | 150 | func (i *GetFunctionAsyncInvokeConfigInput) Validate() error { 151 | if IsBlank(i.ServiceName) { 152 | return fmt.Errorf("Service name is required but not provided") 153 | } 154 | if IsBlank(i.FunctionName) { 155 | return fmt.Errorf("Function name is required but not provided") 156 | } 157 | return nil 158 | } 159 | 160 | // GetFunctionAsyncInvokeConfigOutput define get data response 161 | type GetFunctionAsyncInvokeConfigOutput struct { 162 | Header http.Header 163 | AsyncConfigResponse 164 | } 165 | 166 | func (o GetFunctionAsyncInvokeConfigOutput) String() string { 167 | b, err := json.MarshalIndent(o, "", printIndent) 168 | if err != nil { 169 | return "" 170 | } 171 | return string(b) 172 | } 173 | 174 | func (o GetFunctionAsyncInvokeConfigOutput) GetRequestID() string { 175 | return GetRequestID(o.Header) 176 | } 177 | 178 | // DeleteFunctionAsyncInvokeConfigInput defines function creation input 179 | type DeleteFunctionAsyncInvokeConfigInput struct { 180 | ServiceName *string `json:"serviceName"` 181 | Qualifier *string `json:"qualifier"` 182 | FunctionName *string `json:"functionName"` 183 | } 184 | 185 | func NewDeleteFunctionAsyncInvokeConfigInput(serviceName, functionName string) *DeleteFunctionAsyncInvokeConfigInput { 186 | return &DeleteFunctionAsyncInvokeConfigInput{ServiceName: &serviceName, FunctionName: &functionName} 187 | } 188 | 189 | func (i *DeleteFunctionAsyncInvokeConfigInput) WithQualifier(qualifier string) *DeleteFunctionAsyncInvokeConfigInput { 190 | i.Qualifier = &qualifier 191 | return i 192 | } 193 | 194 | func (i *DeleteFunctionAsyncInvokeConfigInput) GetQueryParams() url.Values { 195 | out := url.Values{} 196 | return out 197 | } 198 | 199 | func (i *DeleteFunctionAsyncInvokeConfigInput) GetPath() string { 200 | if !IsBlank(i.Qualifier) { 201 | return fmt.Sprintf(asyncConfigWithQualifierPath, 202 | pathEscape(*i.ServiceName), pathEscape(*i.Qualifier), pathEscape(*i.FunctionName)) 203 | } 204 | return fmt.Sprintf(asyncConfigPath, pathEscape(*i.ServiceName), pathEscape(*i.FunctionName)) 205 | } 206 | 207 | func (i *DeleteFunctionAsyncInvokeConfigInput) GetHeaders() Header { 208 | header := make(Header) 209 | return header 210 | } 211 | 212 | func (i *DeleteFunctionAsyncInvokeConfigInput) GetPayload() interface{} { 213 | return nil 214 | } 215 | 216 | func (i *DeleteFunctionAsyncInvokeConfigInput) Validate() error { 217 | if IsBlank(i.ServiceName) { 218 | return fmt.Errorf("Service name is required but not provided") 219 | } 220 | if IsBlank(i.FunctionName) { 221 | return fmt.Errorf("Function name is required but not provided") 222 | } 223 | return nil 224 | } 225 | 226 | // DeleteFunctionAsyncInvokeConfigOutput define delete data response 227 | type DeleteFunctionAsyncInvokeConfigOutput struct { 228 | Header http.Header 229 | } 230 | 231 | func (o DeleteFunctionAsyncInvokeConfigOutput) String() string { 232 | b, err := json.MarshalIndent(o, "", printIndent) 233 | if err != nil { 234 | return "" 235 | } 236 | return string(b) 237 | } 238 | 239 | func (o DeleteFunctionAsyncInvokeConfigOutput) GetRequestID() string { 240 | return GetRequestID(o.Header) 241 | } 242 | 243 | // ListFunctionAsyncInvokeConfigsOutput defines ListFunctionAsyncInvokeConfigsOutput result 244 | type ListFunctionAsyncInvokeConfigsOutput struct { 245 | Header http.Header 246 | Configs []*AsyncConfigResponse `json:"configs"` 247 | NextToken *string `json:"nextToken,omitempty"` 248 | } 249 | 250 | func (o ListFunctionAsyncInvokeConfigsOutput) String() string { 251 | b, err := json.MarshalIndent(o, "", printIndent) 252 | if err != nil { 253 | return "" 254 | } 255 | return string(b) 256 | } 257 | func (o ListFunctionAsyncInvokeConfigsOutput) GetRequestID() string { 258 | return GetRequestID(o.Header) 259 | } 260 | 261 | type ListFunctionAsyncInvokeConfigsInput struct { 262 | ServiceName *string `json:"serviceName"` 263 | FunctionName *string `json:"functionName"` 264 | NextToken *string 265 | Limit *int32 266 | } 267 | 268 | func NewListFunctionAsyncInvokeConfigsInput(serviceName, functionName string) *ListFunctionAsyncInvokeConfigsInput { 269 | return &ListFunctionAsyncInvokeConfigsInput{ 270 | ServiceName: &serviceName, 271 | FunctionName: &functionName, 272 | } 273 | } 274 | 275 | func (i *ListFunctionAsyncInvokeConfigsInput) WithNextToken(nextToken string) *ListFunctionAsyncInvokeConfigsInput { 276 | i.NextToken = &nextToken 277 | return i 278 | } 279 | 280 | func (i *ListFunctionAsyncInvokeConfigsInput) WithLimit(limit int32) *ListFunctionAsyncInvokeConfigsInput { 281 | i.Limit = &limit 282 | return i 283 | } 284 | 285 | func (i *ListFunctionAsyncInvokeConfigsInput) GetQueryParams() url.Values { 286 | out := url.Values{} 287 | 288 | if i.NextToken != nil { 289 | out.Set("nextToken", *i.NextToken) 290 | } 291 | 292 | if i.Limit != nil { 293 | out.Set("limit", strconv.FormatInt(int64(*i.Limit), 10)) 294 | } 295 | 296 | return out 297 | } 298 | 299 | func (i *ListFunctionAsyncInvokeConfigsInput) GetPath() string { 300 | return fmt.Sprintf(listAsyncConfigsPath, pathEscape(*i.ServiceName), pathEscape(*i.FunctionName)) 301 | } 302 | 303 | func (i *ListFunctionAsyncInvokeConfigsInput) GetHeaders() Header { 304 | return make(Header, 0) 305 | } 306 | 307 | func (i *ListFunctionAsyncInvokeConfigsInput) GetPayload() interface{} { 308 | return nil 309 | } 310 | 311 | func (i *ListFunctionAsyncInvokeConfigsInput) Validate() error { 312 | return nil 313 | } 314 | -------------------------------------------------------------------------------- /cdn_events_trigger.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | // CDNEventsTriggerConfig defines the cdn events trigger config 4 | type CDNEventsTriggerConfig struct { 5 | EventName *string `json:"eventName"` 6 | EventVersion *string `json:"eventVersion"` 7 | Notes *string `json:"notes"` 8 | Filter map[string][]string `json:"filter"` 9 | } 10 | 11 | // NewCDNEventsTriggerConfig creates an empty CDNTEventsTriggerConfig 12 | func NewCDNEventsTriggerConfig() *CDNEventsTriggerConfig { 13 | return &CDNEventsTriggerConfig{} 14 | } 15 | 16 | func (ctc *CDNEventsTriggerConfig) WithEventName(eventName string) *CDNEventsTriggerConfig { 17 | ctc.EventName = &eventName 18 | return ctc 19 | } 20 | 21 | func (ctc *CDNEventsTriggerConfig) WithEventVersion(eventVersion string) *CDNEventsTriggerConfig { 22 | ctc.EventVersion = &eventVersion 23 | return ctc 24 | } 25 | 26 | func (ctc *CDNEventsTriggerConfig) WithNotes(notes string) *CDNEventsTriggerConfig { 27 | ctc.Notes = ¬es 28 | return ctc 29 | } 30 | 31 | func (ctc *CDNEventsTriggerConfig) WithFilter(filter map[string][]string) *CDNEventsTriggerConfig { 32 | ctc.Filter = make(map[string][]string, len(filter)) 33 | for k,v := range filter { 34 | ctc.Filter[k] = v 35 | } 36 | return ctc 37 | } 38 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | // Config defines fc config 4 | type Config struct { 5 | Endpoint string // fc地址 6 | APIVersion string // API版本 7 | AccountID string // Account ID 8 | AccessKeyID string // accessKeyID 9 | AccessKeySecret string // accessKeySecret 10 | SecurityToken string // STS securityToken 11 | UserAgent string // SDK名称/版本/系统信息 12 | IsDebug bool // 是否开启调试模式,默认false 13 | Timeout uint // 超时时间,默认60秒 14 | host string // Set host from endpoint 15 | } 16 | 17 | // NewConfig get default config 18 | func NewConfig() *Config { 19 | config := Config{} 20 | config.Endpoint = "" 21 | config.AccessKeyID = "" 22 | config.AccessKeySecret = "" 23 | config.SecurityToken = "" 24 | config.IsDebug = false 25 | config.UserAgent = "go-sdk-0.1" 26 | config.Timeout = 60 27 | config.APIVersion = "2016-08-15" 28 | config.host = "" 29 | return &config 30 | } 31 | -------------------------------------------------------------------------------- /connect.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/url" 7 | "reflect" 8 | "strings" 9 | "time" 10 | 11 | "gopkg.in/resty.v1" 12 | ) 13 | 14 | // default parameter 15 | const ( 16 | RequestTimeout = 60 17 | defaultIdleTimeout = 50 * time.Second 18 | ) 19 | 20 | // Connection with fc 21 | type Connection struct { 22 | Timeout uint // 超时时间,默认60秒 23 | } 24 | 25 | // NewConnection get default connection 26 | func NewConnection() *Connection { 27 | connection := &Connection{ 28 | Timeout: RequestTimeout, 29 | } 30 | 31 | resty.SetTransport(&http.Transport{ 32 | // Receiving proxy config from environment 33 | Proxy: http.ProxyFromEnvironment, 34 | // NOTE: FC server has a keepalive timeout of 90s, the 35 | // idle timeout on client side must be less than this 36 | // value. 37 | IdleConnTimeout: defaultIdleTimeout, 38 | }) 39 | resty.SetTimeout(time.Duration(connection.Timeout) * time.Second) 40 | return connection 41 | } 42 | 43 | // PrepareRequest prepare http request 44 | func (conn *Connection) PrepareRequest(postBody interface{}, 45 | headerParams map[string]string, 46 | queryParams url.Values) *resty.Request { 47 | 48 | request := resty.R() 49 | if postBody != nil { 50 | request.SetBody(postBody) 51 | } 52 | 53 | // add header parameter, if any 54 | if len(headerParams) > 0 { 55 | request.SetHeaders(headerParams) 56 | } 57 | 58 | // add query parameter, if any 59 | if len(queryParams) > 0 { 60 | request.SetMultiValueQueryParams(queryParams) 61 | } 62 | return request 63 | } 64 | 65 | // SendRequest send http request 66 | func (conn *Connection) SendRequest(path string, method string, 67 | postBody interface{}, 68 | headerParams map[string]string, 69 | queryParams url.Values) (*resty.Response, error) { 70 | 71 | request := conn.PrepareRequest(postBody, headerParams, queryParams) 72 | 73 | switch strings.ToUpper(method) { 74 | case http.MethodGet: 75 | response, err := request.Get(path) 76 | return response, err 77 | case http.MethodPost: 78 | response, err := request.Post(path) 79 | return response, err 80 | case http.MethodPut: 81 | response, err := request.Put(path) 82 | return response, err 83 | case http.MethodDelete: 84 | response, err := request.Delete(path) 85 | return response, err 86 | } 87 | return nil, fmt.Errorf("invalid method %v", method) 88 | } 89 | 90 | // ParameterToString serialize parameters 91 | func ParameterToString(obj interface{}, collectionFormat string) string { 92 | if reflect.TypeOf(obj).String() == "[]string" { 93 | switch collectionFormat { 94 | case "pipes": 95 | return strings.Join(obj.([]string), "|") 96 | case "ssv": 97 | return strings.Join(obj.([]string), " ") 98 | case "tsv": 99 | return strings.Join(obj.([]string), "\t") 100 | case "csv": 101 | return strings.Join(obj.([]string), ",") 102 | } 103 | } 104 | return fmt.Sprintf("%v", obj) 105 | } 106 | -------------------------------------------------------------------------------- /const.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | // OSSEvent represents the oss event type in oss trigger 4 | type OSSEvent string 5 | 6 | const ( 7 | OSSEventObjectCreatedAll OSSEvent = "oss:ObjectCreated:*" 8 | OSSEventObjectCreatedPutObject OSSEvent = "oss:ObjectCreated:PutObject" 9 | OSSEventObjectCreatedPutSymlink OSSEvent = "oss:ObjectCreated:PutSymlink" 10 | OSSEventObjectCreatedPostObject OSSEvent = "oss:ObjectCreated:PostObject" 11 | OSSEventObjectCreatedCopyObject OSSEvent = "oss:ObjectCreated:CopyObject" 12 | OSSEventObjectCreatedInitiateMultipartUpload OSSEvent = "oss:ObjectCreated:InitiateMultipartUpload" 13 | OSSEventObjectCreatedUploadPart OSSEvent = "oss:ObjectCreated:UploadPart" 14 | OSSEventObjectCreatedUploadPartCopy OSSEvent = "oss:ObjectCreated:UploadPartCopy" 15 | OSSEventObjectCreatedCompleteMultipartUpload OSSEvent = "oss:ObjectCreated:CompleteMultipartUpload" 16 | OSSEventObjectCreatedAppendObject OSSEvent = "oss:ObjectCreated:AppendObject" 17 | OSSEventObjectRemovedDeleteObject OSSEvent = "oss:ObjectRemoved:DeleteObject" 18 | OSSEventObjectRemovedDeleteObjects OSSEvent = "oss:ObjectRemoved:DeleteObjects" 19 | OSSEventObjectRemovedAbortMultipartUpload OSSEvent = "oss:ObjectRemoved:AbortMultipartUpload" 20 | OSSEventObjectReplicationObjectCreated OSSEvent = "oss:ObjectReplication:ObjectCreated" 21 | OSSEventObjectReplicationObjectRemoved OSSEvent = "oss:ObjectReplication:ObjectRemoved" 22 | OSSEventObjectReplicationObjectModified OSSEvent = "oss:ObjectReplication:ObjectModified" 23 | ) 24 | 25 | const ( 26 | // HTTPHeaderRequestID get request ID 27 | HTTPHeaderRequestID = "X-Fc-Request-Id" 28 | 29 | // HTTPHeaderInvocationType stores the invocation type. 30 | HTTPHeaderInvocationType = "X-Fc-Invocation-Type" 31 | 32 | // HTTPHeaderStatefulAsyncInvocationID get invocation ID 33 | HTTPHeaderStatefulAsyncInvocationID = "X-Fc-Stateful-Async-Invocation-Id" 34 | 35 | // HTTPHeaderAccountID stores the account ID 36 | HTTPHeaderAccountID = "X-Fc-Account-Id" 37 | 38 | // HTTPHeaderFCErrorType get the error type when invoke function 39 | HTTPHeaderFCErrorType = "X-Fc-Error-Type" 40 | 41 | // HTTPHeaderSecurityToken is the header key for STS security token 42 | HTTPHeaderSecurityToken = "X-Fc-Security-Token" 43 | 44 | // HTTPHeaderInvocationLogType is the header key for invoke function log type 45 | HTTPHeaderInvocationLogType = "X-Fc-Log-Type" 46 | 47 | // HTTPHeaderInvocationLogResult is the header key for invoke function log result 48 | HTTPHeaderInvocationLogResult = "X-Fc-Log-Result" 49 | 50 | // HTTPHeaderEtag get the etag of the resource 51 | HTTPHeaderEtag = "Etag" 52 | 53 | //HTTPHeaderPrefix :Prefix string in headers 54 | HTTPHeaderPrefix = "x-fc-" 55 | 56 | //HTTPHeaderContentMD5 :Key in request headers 57 | HTTPHeaderContentMD5 = "Content-MD5" 58 | 59 | //HTTPHeaderContentType :Key in request headers 60 | HTTPHeaderContentType = "Content-Type" 61 | 62 | // HTTPHeaderUserAgent : Key in request headers 63 | HTTPHeaderUserAgent = "User-Agent" 64 | 65 | //HTTPHeaderDate :Key in request headers 66 | HTTPHeaderDate = "Date" 67 | 68 | // CustomContainerConfigAccelerationTypeDefault : default acceleration type for custom-container runtime 69 | CustomContainerConfigAccelerationTypeDefault = "Default" 70 | 71 | // CustomContainerConfigAccelerationTypeNone : disable custom-container runtime acceleration 72 | CustomContainerConfigAccelerationTypeNone = "None" 73 | ) 74 | 75 | // Supported api versions 76 | const ( 77 | APIVersionV1 = "2016-08-15" 78 | ) 79 | 80 | // Supported tracing types 81 | const ( 82 | TracingTypeJaeger = "Jaeger" 83 | ) 84 | 85 | -------------------------------------------------------------------------------- /custom_domain.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | "strconv" 9 | ) 10 | 11 | const ( 12 | customDomainsPath = "/custom-domains" 13 | singleDomainPath = customDomainsPath + "/%s" 14 | ) 15 | 16 | type customDomainMetadata struct { 17 | DomainName *string `json:"domainName"` 18 | AccountID *string `json:"accountId"` 19 | Protocol *string `json:"protocol"` 20 | APIVersion *string `json:"apiVersion"` 21 | RouteConfig *RouteConfig `json:"routeConfig"` 22 | CertConfig *CertConfig `json:"certConfig"` 23 | CreatedTime string `json:"createdTime"` 24 | LastModifiedTime string `json:"lastModifiedTime"` 25 | } 26 | 27 | // CreateCustomDomainInput defines input to create custom domain 28 | type CreateCustomDomainInput struct { 29 | DomainName *string `json:"domainName"` 30 | Protocol *string `json:"protocol"` 31 | RouteConfig *RouteConfig `json:"routeConfig"` 32 | CertConfig *CertConfig `json:"certConfig"` 33 | } 34 | 35 | // NewCreateCustomDomainInput... 36 | func NewCreateCustomDomainInput() *CreateCustomDomainInput { 37 | return &CreateCustomDomainInput{} 38 | } 39 | 40 | func (c *CreateCustomDomainInput) WithDomainName(domainName string) *CreateCustomDomainInput { 41 | c.DomainName = &domainName 42 | return c 43 | } 44 | 45 | func (c *CreateCustomDomainInput) WithProtocol(protocol string) *CreateCustomDomainInput { 46 | c.Protocol = &protocol 47 | return c 48 | } 49 | 50 | func (c *CreateCustomDomainInput) WithRouteConfig(routeConfig *RouteConfig) *CreateCustomDomainInput { 51 | c.RouteConfig = routeConfig 52 | return c 53 | } 54 | 55 | func (c *CreateCustomDomainInput) WithCertConfig(certConfig *CertConfig) *CreateCustomDomainInput { 56 | c.CertConfig = certConfig 57 | return c 58 | } 59 | 60 | func (c *CreateCustomDomainInput) GetQueryParams() url.Values { 61 | out := url.Values{} 62 | return out 63 | } 64 | 65 | func (c *CreateCustomDomainInput) GetPath() string { 66 | return customDomainsPath 67 | } 68 | 69 | func (c *CreateCustomDomainInput) GetHeaders() Header { 70 | return make(Header, 0) 71 | } 72 | 73 | func (c *CreateCustomDomainInput) GetPayload() interface{} { 74 | return c 75 | } 76 | 77 | func (c *CreateCustomDomainInput) Validate() error { 78 | return nil 79 | } 80 | 81 | // RouteConfig represents route config for a single domain 82 | type RouteConfig struct { 83 | Routes []PathConfig `json:"routes" ` 84 | } 85 | 86 | func NewRouteConfig() *RouteConfig { 87 | return &RouteConfig{} 88 | } 89 | 90 | func (r *RouteConfig) WithRoutes(pathConfig []PathConfig) *RouteConfig { 91 | r.Routes = pathConfig 92 | return r 93 | } 94 | 95 | // PathConfig represents path-function mapping 96 | type PathConfig struct { 97 | Path *string `json:"path" ` 98 | ServiceName *string `json:"serviceName" ` 99 | FunctionName *string `json:"functionName" ` 100 | Qualifier *string `json:"qualifier" ` 101 | Methods []string `json:"methods"` 102 | } 103 | 104 | func NewPathConfig() *PathConfig { 105 | return &PathConfig{} 106 | } 107 | 108 | func (p *PathConfig) WithPath(path string) *PathConfig { 109 | p.Path = &path 110 | return p 111 | } 112 | 113 | func (p *PathConfig) WithServiceName(serviceName string) *PathConfig { 114 | p.ServiceName = &serviceName 115 | return p 116 | } 117 | 118 | func (p *PathConfig) WithFunctionName(functionName string) *PathConfig { 119 | p.FunctionName = &functionName 120 | return p 121 | } 122 | 123 | func (p *PathConfig) WithQualifier(qualifier string) *PathConfig { 124 | p.Qualifier = &qualifier 125 | return p 126 | } 127 | 128 | func (p *PathConfig) WithMethods(methods []string) *PathConfig { 129 | p.Methods = methods 130 | return p 131 | } 132 | 133 | type CertConfig struct { 134 | CertName *string `json:certName` 135 | PrivateKey *string `json:privateKey` 136 | Certificate *string `json:certificate` 137 | } 138 | 139 | func (c *CertConfig) WithCertName(certName string) *CertConfig { 140 | c.CertName = &certName 141 | return c 142 | } 143 | 144 | func (c *CertConfig) WithPrivateKey(privateKey string) *CertConfig { 145 | c.PrivateKey = &privateKey 146 | return c 147 | } 148 | 149 | func (c *CertConfig) WithCertificate(certificate string) *CertConfig { 150 | c.Certificate = &certificate 151 | return c 152 | } 153 | 154 | // CreateCustomDomainOutput define create custom domain response 155 | type CreateCustomDomainOutput struct { 156 | Header http.Header 157 | customDomainMetadata 158 | } 159 | 160 | func (o CreateCustomDomainOutput) String() string { 161 | b, err := json.MarshalIndent(o, "", printIndent) 162 | if err != nil { 163 | return "" 164 | } 165 | return string(b) 166 | } 167 | 168 | func (o CreateCustomDomainOutput) GetRequestID() string { 169 | return GetRequestID(o.Header) 170 | } 171 | 172 | // UpdateCustomDomainInput defines input to update custom domain 173 | type UpdateCustomDomainObject struct { 174 | Protocol *string `json:"protocol"` 175 | RouteConfig *RouteConfig `json:"routeConfig"` 176 | CertConfig *CertConfig `json:"certConfig"` 177 | } 178 | 179 | type UpdateCustomDomainInput struct { 180 | DomainName *string 181 | UpdateCustomDomainObject 182 | } 183 | 184 | func NewUpdateCustomDomainInput(domainName string) *UpdateCustomDomainInput { 185 | return &UpdateCustomDomainInput{DomainName: &domainName} 186 | } 187 | 188 | func (c *UpdateCustomDomainInput) WithProtocol(protocol string) *UpdateCustomDomainInput { 189 | c.Protocol = &protocol 190 | return c 191 | } 192 | 193 | func (c *UpdateCustomDomainInput) WithRouteConfig(routeConfig *RouteConfig) *UpdateCustomDomainInput { 194 | c.RouteConfig = routeConfig 195 | return c 196 | } 197 | 198 | func (c *UpdateCustomDomainInput) WithCertConfig(certConfig *CertConfig) *UpdateCustomDomainInput { 199 | c.CertConfig = certConfig 200 | return c 201 | } 202 | 203 | func (c *UpdateCustomDomainInput) GetQueryParams() url.Values { 204 | out := url.Values{} 205 | return out 206 | } 207 | 208 | func (c *UpdateCustomDomainInput) GetPath() string { 209 | return fmt.Sprintf(singleDomainPath, pathEscape(*c.DomainName)) 210 | } 211 | 212 | func (c *UpdateCustomDomainInput) GetHeaders() Header { 213 | header := make(Header) 214 | return header 215 | } 216 | 217 | func (c *UpdateCustomDomainInput) GetPayload() interface{} { 218 | return c.UpdateCustomDomainObject 219 | } 220 | 221 | func (c *UpdateCustomDomainInput) Validate() error { 222 | if IsBlank(c.DomainName) { 223 | return fmt.Errorf("Domain name is required but not provided") 224 | } 225 | return nil 226 | } 227 | 228 | // UpdateCustomDomainOutput define update custom domain response 229 | type UpdateCustomDomainOutput struct { 230 | Header http.Header 231 | customDomainMetadata 232 | } 233 | 234 | func (o UpdateCustomDomainOutput) String() string { 235 | b, err := json.MarshalIndent(o, "", printIndent) 236 | if err != nil { 237 | return "" 238 | } 239 | return string(b) 240 | } 241 | 242 | func (o UpdateCustomDomainOutput) GetRequestID() string { 243 | return GetRequestID(o.Header) 244 | } 245 | 246 | type GetCustomDomainInput struct { 247 | DomainName *string 248 | } 249 | 250 | func NewGetCustomDomainInput(domainName string) *GetCustomDomainInput { 251 | return &GetCustomDomainInput{DomainName: &domainName} 252 | } 253 | 254 | func (i *GetCustomDomainInput) GetQueryParams() url.Values { 255 | out := url.Values{} 256 | return out 257 | } 258 | 259 | func (i *GetCustomDomainInput) GetPath() string { 260 | return fmt.Sprintf(singleDomainPath, pathEscape(*i.DomainName)) 261 | } 262 | 263 | func (i *GetCustomDomainInput) GetHeaders() Header { 264 | return make(Header, 0) 265 | } 266 | 267 | func (i *GetCustomDomainInput) GetPayload() interface{} { 268 | return nil 269 | } 270 | 271 | func (i *GetCustomDomainInput) Validate() error { 272 | if IsBlank(i.DomainName) { 273 | return fmt.Errorf("Domain name is required but not provided") 274 | } 275 | return nil 276 | } 277 | 278 | // GetCustomDomainOutput define get custom domain response 279 | type GetCustomDomainOutput struct { 280 | Header http.Header 281 | customDomainMetadata 282 | } 283 | 284 | func (o GetCustomDomainOutput) String() string { 285 | b, err := json.MarshalIndent(o, "", printIndent) 286 | if err != nil { 287 | return "" 288 | } 289 | return string(b) 290 | } 291 | 292 | func (o GetCustomDomainOutput) GetRequestID() string { 293 | return GetRequestID(o.Header) 294 | } 295 | 296 | // ListCustomDomains defines listCustomDomainsMetadata result 297 | type ListCustomDomainsOutput struct { 298 | Header http.Header 299 | CustomDomains []*customDomainMetadata `json:"customDomains"` 300 | NextToken *string `json:"nextToken,omitempty"` 301 | } 302 | 303 | type ListCustomDomainsInput struct { 304 | Query 305 | } 306 | 307 | func NewListCustomDomainsInput() *ListCustomDomainsInput { 308 | return &ListCustomDomainsInput{} 309 | } 310 | 311 | func (i *ListCustomDomainsInput) WithPrefix(prefix string) *ListCustomDomainsInput { 312 | i.Prefix = &prefix 313 | return i 314 | } 315 | 316 | func (i *ListCustomDomainsInput) WithStartKey(startKey string) *ListCustomDomainsInput { 317 | i.StartKey = &startKey 318 | return i 319 | } 320 | 321 | func (i *ListCustomDomainsInput) WithNextToken(nextToken string) *ListCustomDomainsInput { 322 | i.NextToken = &nextToken 323 | return i 324 | } 325 | 326 | func (i *ListCustomDomainsInput) WithLimit(limit int32) *ListCustomDomainsInput { 327 | i.Limit = &limit 328 | return i 329 | } 330 | 331 | func (i *ListCustomDomainsInput) GetQueryParams() url.Values { 332 | out := url.Values{} 333 | if i.Prefix != nil { 334 | out.Set("prefix", *i.Prefix) 335 | } 336 | 337 | if i.StartKey != nil { 338 | out.Set("startKey", *i.StartKey) 339 | } 340 | 341 | if i.NextToken != nil { 342 | out.Set("nextToken", *i.NextToken) 343 | } 344 | 345 | if i.Limit != nil { 346 | out.Set("limit", strconv.FormatInt(int64(*i.Limit), 10)) 347 | } 348 | 349 | return out 350 | } 351 | 352 | func (i *ListCustomDomainsInput) GetPath() string { 353 | return customDomainsPath 354 | } 355 | 356 | func (i *ListCustomDomainsInput) GetHeaders() Header { 357 | return make(Header, 0) 358 | } 359 | 360 | func (i *ListCustomDomainsInput) GetPayload() interface{} { 361 | return nil 362 | } 363 | 364 | func (i *ListCustomDomainsInput) Validate() error { 365 | return nil 366 | } 367 | 368 | func (o ListCustomDomainsOutput) String() string { 369 | b, err := json.MarshalIndent(o, "", printIndent) 370 | if err != nil { 371 | return "" 372 | } 373 | return string(b) 374 | } 375 | 376 | func (o ListCustomDomainsOutput) GetRequestID() string { 377 | return GetRequestID(o.Header) 378 | } 379 | 380 | type DeleteCustomDomainInput struct { 381 | DomainName *string 382 | } 383 | 384 | func NewDeleteCustomDomainInput(domainName string) *DeleteCustomDomainInput { 385 | return &DeleteCustomDomainInput{DomainName: &domainName} 386 | } 387 | 388 | func (i *DeleteCustomDomainInput) GetQueryParams() url.Values { 389 | out := url.Values{} 390 | return out 391 | } 392 | 393 | func (i *DeleteCustomDomainInput) GetPath() string { 394 | return fmt.Sprintf(singleDomainPath, pathEscape(*i.DomainName)) 395 | } 396 | 397 | func (i *DeleteCustomDomainInput) GetHeaders() Header { 398 | header := make(Header) 399 | return header 400 | } 401 | 402 | func (i *DeleteCustomDomainInput) GetPayload() interface{} { 403 | return nil 404 | } 405 | 406 | func (i *DeleteCustomDomainInput) Validate() error { 407 | if IsBlank(i.DomainName) { 408 | return fmt.Errorf("Domain name is required but not provided") 409 | } 410 | return nil 411 | } 412 | 413 | type DeleteCustomDomainOutput struct { 414 | Header http.Header 415 | } 416 | 417 | func (o DeleteCustomDomainOutput) String() string { 418 | b, err := json.MarshalIndent(o, "", printIndent) 419 | if err != nil { 420 | return "" 421 | } 422 | return string(b) 423 | } 424 | 425 | func (o DeleteCustomDomainOutput) GetRequestID() string { 426 | return GetRequestID(o.Header) 427 | } 428 | -------------------------------------------------------------------------------- /custom_domain_test.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/suite" 7 | ) 8 | 9 | func TestCustomDomainStructs(t *testing.T) { 10 | suite.Run(t, new(CustomDomainStructsTestSuite)) 11 | } 12 | 13 | type CustomDomainStructsTestSuite struct { 14 | suite.Suite 15 | } 16 | 17 | func (s *CustomDomainStructsTestSuite) TestCreateCustomDomain() { 18 | assert := s.Require() 19 | 20 | input := NewCreateCustomDomainInput() 21 | assert.NotNil(input) 22 | 23 | input.WithDomainName("my-app.com") 24 | assert.NotNil(input.DomainName) 25 | assert.Equal("my-app.com", *input.DomainName) 26 | 27 | input.WithProtocol("HTTP") 28 | assert.NotNil(input.Protocol) 29 | assert.Equal("HTTP", *input.Protocol) 30 | 31 | input.WithProtocol("HTTPS") 32 | assert.NotNil(input.Protocol) 33 | assert.Equal("HTTPS", *input.Protocol) 34 | 35 | input.WithProtocol("HTTP,HTTPS") 36 | assert.NotNil(input.Protocol) 37 | assert.Equal("HTTP,HTTPS", *input.Protocol) 38 | 39 | cert := CertConfig{} 40 | cert.WithCertName("cert-name") 41 | cert.WithPrivateKey("server-privateKey") 42 | cert.WithCertificate("server-certificate") 43 | assert.Equal("server-privateKey", *cert.PrivateKey) 44 | assert.Equal("server-certificate", *cert.Certificate) 45 | 46 | input.WithCertConfig(&cert) 47 | assert.Equal("cert-name", *input.CertConfig.CertName) 48 | assert.Equal("server-privateKey", *input.CertConfig.PrivateKey) 49 | assert.Equal("server-certificate", *input.CertConfig.Certificate) 50 | 51 | input.WithRouteConfig(&RouteConfig{}) 52 | assert.NotNil(input.RouteConfig) 53 | 54 | pathConfig := NewPathConfig() 55 | assert.NotNil(pathConfig) 56 | 57 | pathConfig.WithPath("/login") 58 | assert.NotNil(pathConfig.Path) 59 | assert.Equal("/login", *pathConfig.Path) 60 | 61 | pathConfig.WithServiceName("service0") 62 | assert.NotNil(pathConfig.ServiceName) 63 | assert.Equal("service0", *pathConfig.ServiceName) 64 | 65 | pathConfig.WithFunctionName("function0") 66 | assert.NotNil(pathConfig.FunctionName) 67 | assert.Equal("function0", *pathConfig.FunctionName) 68 | 69 | pathConfig.WithQualifier("v1") 70 | assert.NotNil(pathConfig.Qualifier) 71 | assert.Equal("v1", *pathConfig.Qualifier) 72 | 73 | pathConfig.WithMethods([]string{"GET", "POST"}) 74 | assert.NotNil(pathConfig.Methods) 75 | assert.Equal([]string{"GET", "POST"}, pathConfig.Methods) 76 | 77 | routeConfig := NewRouteConfig() 78 | assert.NotNil(routeConfig) 79 | 80 | routeConfig.WithRoutes([]PathConfig{*pathConfig}) 81 | assert.NotNil(routeConfig.Routes) 82 | assert.Equal(1, len(routeConfig.Routes)) 83 | } 84 | 85 | func (s *CustomDomainStructsTestSuite) TestUpdateCustomDomain() { 86 | assert := s.Require() 87 | 88 | input := NewUpdateCustomDomainInput("my-app.com") 89 | assert.NotNil(input) 90 | assert.NotNil(input.DomainName) 91 | assert.Equal("my-app.com", *input.DomainName) 92 | 93 | input.WithProtocol("HTTP") 94 | assert.NotNil(input.Protocol) 95 | assert.Equal("HTTP", *input.Protocol) 96 | 97 | input.WithProtocol("HTTPS") 98 | assert.NotNil(input.Protocol) 99 | assert.Equal("HTTPS", *input.Protocol) 100 | 101 | input.WithProtocol("HTTP,HTTPS") 102 | assert.NotNil(input.Protocol) 103 | assert.Equal("HTTP,HTTPS", *input.Protocol) 104 | 105 | cert := CertConfig{} 106 | cert.WithCertName("cert-name") 107 | cert.WithPrivateKey("server-privateKey") 108 | cert.WithCertificate("server-certificate") 109 | assert.Equal("cert-name", *cert.CertName) 110 | assert.Equal("server-privateKey", *cert.PrivateKey) 111 | assert.Equal("server-certificate", *cert.Certificate) 112 | 113 | input.WithCertConfig(&cert) 114 | assert.Equal("cert-name", *cert.CertName) 115 | assert.Equal("server-privateKey", *input.CertConfig.PrivateKey) 116 | assert.Equal("server-certificate", *input.CertConfig.Certificate) 117 | 118 | input.WithRouteConfig(&RouteConfig{}) 119 | assert.NotNil(input.RouteConfig) 120 | 121 | pathConfig := NewPathConfig() 122 | assert.NotNil(pathConfig) 123 | 124 | pathConfig.WithPath("/login") 125 | assert.NotNil(pathConfig.Path) 126 | assert.Equal("/login", *pathConfig.Path) 127 | 128 | pathConfig.WithServiceName("service0") 129 | assert.NotNil(pathConfig.ServiceName) 130 | assert.Equal("service0", *pathConfig.ServiceName) 131 | 132 | pathConfig.WithFunctionName("function0") 133 | assert.NotNil(pathConfig.FunctionName) 134 | assert.Equal("function0", *pathConfig.FunctionName) 135 | 136 | pathConfig.WithQualifier("v1") 137 | assert.NotNil(pathConfig.Qualifier) 138 | assert.Equal("v1", *pathConfig.Qualifier) 139 | 140 | pathConfig.WithMethods([]string{"GET", "POST"}) 141 | assert.NotNil(pathConfig.Methods) 142 | assert.Equal([]string{"GET", "POST"}, pathConfig.Methods) 143 | 144 | routeConfig := NewRouteConfig() 145 | assert.NotNil(routeConfig) 146 | 147 | routeConfig.WithRoutes([]PathConfig{*pathConfig}) 148 | assert.NotNil(routeConfig.Routes) 149 | assert.Equal(1, len(routeConfig.Routes)) 150 | } 151 | 152 | func (s *CustomDomainStructsTestSuite) TestGetCustomDomain() { 153 | assert := s.Require() 154 | input := NewGetCustomDomainInput("my-app.com") 155 | assert.NotNil(input) 156 | assert.NotNil(input.DomainName) 157 | assert.Equal("my-app.com", *input.DomainName) 158 | } 159 | 160 | func (s *CustomDomainStructsTestSuite) TestDeleteCustomDomain() { 161 | assert := s.Require() 162 | input := NewDeleteCustomDomainInput("my-app.com") 163 | assert.NotNil(input) 164 | assert.NotNil(input.DomainName) 165 | assert.Equal("my-app.com", *input.DomainName) 166 | } 167 | 168 | func (s *CustomDomainStructsTestSuite) TestListCustomDomain() { 169 | assert := s.Require() 170 | input := NewListCustomDomainsInput() 171 | assert.NotNil(input) 172 | 173 | input.WithPrefix("app") 174 | assert.NotNil(input.Prefix) 175 | assert.Equal("app", *input.Prefix) 176 | 177 | input.WithNextToken("your-app.com") 178 | assert.NotNil(input.NextToken) 179 | assert.Equal("your-app.com", *input.NextToken) 180 | 181 | input.WithLimit(int32(10)) 182 | assert.NotNil(input.Limit) 183 | assert.Equal(int32(10), *input.Limit) 184 | 185 | input.WithStartKey("my") 186 | assert.NotNil(input.StartKey) 187 | assert.Equal("my", *input.StartKey) 188 | } 189 | -------------------------------------------------------------------------------- /error.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | ) 7 | 8 | var ( 9 | ErrUnknownTriggerType = errors.New("unknown trigger type") 10 | ) 11 | 12 | // ServiceError defines error from fc 13 | type ServiceError struct { 14 | HTTPStatus int `json:"HttpStatus"` 15 | RequestID string `json:"RequestId"` 16 | ErrorCode string `json:"ErrorCode"` 17 | ErrorMessage string `json:"ErrorMessage"` 18 | } 19 | 20 | func (e ServiceError) String() string { 21 | b, err := json.MarshalIndent(e, "", printIndent) 22 | if err != nil { 23 | return "" 24 | } 25 | return string(b) 26 | } 27 | 28 | func (e ServiceError) Error() string { 29 | return e.String() 30 | } 31 | -------------------------------------------------------------------------------- /eventbridge_trigger.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | // TriggerConfig defines the event bridge trigger config which maps to FunctionComputeConfiguration. 4 | type EventBridgeTriggerConfig struct { 5 | TriggerEnable *bool `json:"triggerEnable"` 6 | AsyncInvocationType *bool `json:"asyncInvocationType"` 7 | EventSourceConfig *EventSourceConfig `json:"eventSourceConfig"` 8 | EventRuleFilterPattern *string `json:"eventRuleFilterPattern"` 9 | } 10 | 11 | 12 | // NewEventBridgeTriggerConfig ... 13 | func NewEventBridgeTriggerConfig() *EventBridgeTriggerConfig { 14 | return &EventBridgeTriggerConfig{} 15 | } 16 | 17 | func (ebtc *EventBridgeTriggerConfig) WithTriggerEnable(triggerEnable bool) *EventBridgeTriggerConfig { 18 | ebtc.TriggerEnable = &triggerEnable 19 | return ebtc 20 | } 21 | 22 | func (ebtc *EventBridgeTriggerConfig) WithAsyncInvocationType(asyncInvocationType bool) *EventBridgeTriggerConfig { 23 | ebtc.AsyncInvocationType = &asyncInvocationType 24 | return ebtc 25 | } 26 | 27 | func (ebtc *EventBridgeTriggerConfig) WithEventSourceConfig(eventSourceConfig *EventSourceConfig) *EventBridgeTriggerConfig { 28 | ebtc.EventSourceConfig = eventSourceConfig 29 | return ebtc 30 | } 31 | 32 | func (ebtc *EventBridgeTriggerConfig) WithEventRuleFilterPattern(eventRuleFilterPattern string) *EventBridgeTriggerConfig { 33 | ebtc.EventRuleFilterPattern = &eventRuleFilterPattern 34 | return ebtc 35 | } 36 | 37 | // EventSourceConfig ... 38 | type EventSourceConfig struct { 39 | EventSourceType *string `json:"eventSourceType"` 40 | EventSourceParameters *EventSourceParameters `json:"eventSourceParameters"` 41 | } 42 | 43 | // NewEventSourceConfig ... 44 | func NewEventSourceConfig() *EventSourceConfig { 45 | return &EventSourceConfig{} 46 | } 47 | 48 | // WithEventSourceType ... 49 | func (esc *EventSourceConfig) WithEventSourceType(eventSourceType string) *EventSourceConfig { 50 | esc.EventSourceType = &eventSourceType 51 | return esc 52 | } 53 | 54 | // WithEventSourceParameters ... 55 | func (esc *EventSourceConfig) WithEventSourceParameters(eventSourceParameters *EventSourceParameters) *EventSourceConfig { 56 | esc.EventSourceParameters = eventSourceParameters 57 | return esc 58 | } 59 | 60 | // EventSourceParameters ... 61 | type EventSourceParameters struct { 62 | SourceMNSParameters *SourceMNSParameters `json:"sourceMNSParameters"` 63 | SourceRocketMQParameters *SourceRocketMQParameters `json:"sourceRocketMQParameters"` 64 | 65 | SourceRabbitMQParameters *SourceRabbitMQParameters `json:"sourceRabbitMQParameters"` 66 | } 67 | 68 | // NewEventSourceParameters ... 69 | func NewEventSourceParameters() *EventSourceParameters { 70 | return &EventSourceParameters{} 71 | } 72 | 73 | // WithSourceMNSParameters 74 | func (esp *EventSourceParameters) WithSourceMNSParameters(sourceMNSParameters *SourceMNSParameters) *EventSourceParameters { 75 | esp.SourceMNSParameters = sourceMNSParameters 76 | return esp 77 | } 78 | 79 | // WithSourceRocketMQParameters 80 | func (esp *EventSourceParameters) WithSourceRocketMQParameters(sourceRocketMQParameters *SourceRocketMQParameters) *EventSourceParameters { 81 | esp.SourceRocketMQParameters = sourceRocketMQParameters 82 | return esp 83 | } 84 | 85 | // WithSourceRabbitMQParameters 86 | func (esp *EventSourceParameters) WithSourceRabbitMQParameters(sourceRabbitMQParameters *SourceRabbitMQParameters) *EventSourceParameters { 87 | esp.SourceRabbitMQParameters = sourceRabbitMQParameters 88 | return esp 89 | } 90 | 91 | // SourceMNSParameters refers to github.com/alibabacloud-go/eventbridge-sdk v1.2.10 92 | type SourceMNSParameters struct { 93 | RegionId *string `json:"RegionId,omitempty"` 94 | QueueName *string `json:"QueueName,omitempty"` 95 | IsBase64Decode *bool `json:"IsBase64Decode,omitempty"` 96 | } 97 | 98 | // NewSourceMNSParameters ... 99 | func NewSourceMNSParameters() *SourceMNSParameters { 100 | return &SourceMNSParameters{} 101 | } 102 | 103 | // WithRegionId ... 104 | func (mns *SourceMNSParameters) WithRegionId(regionId string) *SourceMNSParameters { 105 | mns.RegionId = ®ionId 106 | return mns 107 | } 108 | 109 | // WithQueueName ... 110 | func (mns *SourceMNSParameters) WithQueueName(queueName string) *SourceMNSParameters { 111 | mns.QueueName = &queueName 112 | return mns 113 | } 114 | 115 | // WithIsBase64Decode ... 116 | func (mns *SourceMNSParameters) WithIsBase64Decode(isBase64Decode bool) *SourceMNSParameters { 117 | mns.IsBase64Decode = &isBase64Decode 118 | return mns 119 | } 120 | 121 | // SourceRocketMQParameters refers to github.com/alibabacloud-go/eventbridge-sdk v1.2.10 122 | type SourceRocketMQParameters struct { 123 | RegionId *string `json:"RegionId,omitempty"` 124 | InstanceId *string `json:"InstanceId,omitempty"` 125 | Topic *string `json:"Topic,omitempty"` 126 | Tag *string `json:"Tag,omitempty"` 127 | Offset *string `json:"Offset,omitempty"` 128 | GroupID *string `json:"GroupID,omitempty"` 129 | Timestamp *int `json:"Timestamp,omitempty"` 130 | } 131 | 132 | // NewSourceRocketMQParameters ... 133 | func NewSourceRocketMQParameters() *SourceRocketMQParameters { 134 | return &SourceRocketMQParameters{} 135 | } 136 | 137 | // WithRegionId ... 138 | func (rocket *SourceRocketMQParameters) WithRegionId(regionId string) *SourceRocketMQParameters { 139 | rocket.RegionId = ®ionId 140 | return rocket 141 | } 142 | 143 | // WithInstanceId ... 144 | func (rocket *SourceRocketMQParameters) WithInstanceId(instanceId string) *SourceRocketMQParameters { 145 | rocket.InstanceId = &instanceId 146 | return rocket 147 | } 148 | 149 | // WithTopic ... 150 | func (rocket *SourceRocketMQParameters) WithTopic(topic string) *SourceRocketMQParameters { 151 | rocket.Topic = &topic 152 | return rocket 153 | } 154 | 155 | // WithTag ... 156 | func (rocket *SourceRocketMQParameters) WithTag(tag string) *SourceRocketMQParameters { 157 | rocket.Tag = &tag 158 | return rocket 159 | } 160 | 161 | // WithOffset ... 162 | func (rocket *SourceRocketMQParameters) WithOffset(offset string) *SourceRocketMQParameters { 163 | rocket.Offset = &offset 164 | return rocket 165 | } 166 | 167 | // WithGroupID ... 168 | func (rocket *SourceRocketMQParameters) WithGroupID(groupID string) *SourceRocketMQParameters { 169 | rocket.GroupID = &groupID 170 | return rocket 171 | } 172 | 173 | // WithTimestamp ... 174 | func (rocket *SourceRocketMQParameters) WithTimestamp(timestamp int) *SourceRocketMQParameters { 175 | rocket.Timestamp = ×tamp 176 | return rocket 177 | } 178 | 179 | // SourceRocketMQParameters refers to ithub.com/alibabacloud-go/eventbridge-sdk v1.2.10 180 | type SourceRabbitMQParameters struct { 181 | RegionId *string `json:"RegionId,omitempty"` 182 | InstanceId *string `json:"InstanceId,omitempty"` 183 | VirtualHostName *string `json:"VirtualHostName,omitempty"` 184 | QueueName *string `json:"QueueName,omitempty"` 185 | } 186 | 187 | // SourceRabbitMQParameters ... 188 | func NewSourceRabbitMQParameters() *SourceRabbitMQParameters { 189 | return &SourceRabbitMQParameters{} 190 | } 191 | 192 | // WithRegionId ... 193 | func (rabbit *SourceRabbitMQParameters) WithRegionId(regionId string) *SourceRabbitMQParameters { 194 | rabbit.RegionId = ®ionId 195 | return rabbit 196 | } 197 | 198 | // WithInstanceId ... 199 | func (rabbit *SourceRabbitMQParameters) WithInstanceId(instanceId string) *SourceRabbitMQParameters { 200 | rabbit.InstanceId = &instanceId 201 | return rabbit 202 | } 203 | 204 | // WithVirtualHostName ... 205 | func (rabbit *SourceRabbitMQParameters) WithVirtualHostName(virtualHostName string) *SourceRabbitMQParameters { 206 | rabbit.VirtualHostName = &virtualHostName 207 | return rabbit 208 | } 209 | 210 | // WithQueueName ... 211 | func (rabbit *SourceRabbitMQParameters) WithQueueName(queueName string) *SourceRabbitMQParameters { 212 | rabbit.QueueName = &queueName 213 | return rabbit 214 | } 215 | -------------------------------------------------------------------------------- /function_test.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/suite" 7 | ) 8 | 9 | func getStringPointer(str string) *string { 10 | return &str 11 | } 12 | 13 | type FunctionStructsTestSuite struct { 14 | suite.Suite 15 | } 16 | 17 | func (s *FunctionStructsTestSuite) TestHeaders() { 18 | assert := s.Require() 19 | 20 | input := NewInvokeFunctionInput("service", "func") 21 | assert.Equal("service", *input.ServiceName) 22 | assert.Equal("func", *input.FunctionName) 23 | 24 | input.WithAsyncInvocation() 25 | headers := input.GetHeaders() 26 | assert.Equal("Async", headers["X-Fc-Invocation-Type"]) 27 | 28 | input.WithHeader("X-Fc-Invocation-Code-Version", "Latest") 29 | headers = input.GetHeaders() 30 | assert.Equal("Latest", headers["X-Fc-Invocation-Code-Version"]) 31 | 32 | deleteFunctionInput := NewDeleteFunctionInput("sn", "fn") 33 | deleteFunctionInput.WithHeader("header", "value") 34 | headers = deleteFunctionInput.GetHeaders() 35 | assert.Equal("value", headers["header"]) 36 | } 37 | 38 | func (s *FunctionStructsTestSuite) TestEnvironmentVariables() { 39 | assert := s.Require() 40 | 41 | { 42 | input := NewCreateFunctionInput("service") 43 | assert.Equal("service", *input.ServiceName) 44 | assert.Nil(input.EnvironmentVariables) 45 | 46 | input.WithEnvironmentVariables(map[string]string{}) 47 | assert.NotNil(input.EnvironmentVariables) 48 | assert.Len(input.EnvironmentVariables, 0) 49 | 50 | input.WithEnvironmentVariables(map[string]string{"a": "b"}) 51 | assert.NotNil(input.EnvironmentVariables) 52 | assert.Equal(map[string]string{"a": "b"}, input.EnvironmentVariables) 53 | } 54 | 55 | { 56 | input := NewUpdateFunctionInput("service", "func") 57 | assert.Equal("service", *input.ServiceName) 58 | assert.Equal("func", *input.FunctionName) 59 | assert.Nil(input.EnvironmentVariables) 60 | 61 | input.WithEnvironmentVariables(map[string]string{}) 62 | assert.NotNil(input.EnvironmentVariables) 63 | assert.Len(input.EnvironmentVariables, 0) 64 | 65 | input.WithEnvironmentVariables(map[string]string{"a": "b"}) 66 | assert.NotNil(input.EnvironmentVariables) 67 | assert.Equal(map[string]string{"a": "b"}, input.EnvironmentVariables) 68 | } 69 | 70 | output := &GetFunctionOutput{} 71 | assert.Nil(output.EnvironmentVariables) 72 | } 73 | 74 | func (s *FunctionStructsTestSuite) TestInstanceConcurrency() { 75 | assert := s.Require() 76 | 77 | { 78 | input := NewCreateFunctionInput("service") 79 | assert.Equal("service", *input.ServiceName) 80 | assert.Nil(input.InstanceConcurrency) 81 | 82 | input.WithInstanceConcurrency(int32(0)) 83 | assert.NotNil(input.InstanceConcurrency) 84 | assert.Equal(int32(0), *input.InstanceConcurrency) 85 | 86 | input.WithInstanceConcurrency(int32(1)) 87 | assert.NotNil(input.InstanceConcurrency) 88 | assert.Equal(int32(1), *input.InstanceConcurrency) 89 | } 90 | { 91 | input := NewUpdateFunctionInput("service", "func") 92 | assert.Equal("service", *input.ServiceName) 93 | assert.Equal("func", *input.FunctionName) 94 | assert.Nil(input.InstanceConcurrency) 95 | 96 | input.WithInstanceConcurrency(int32(0)) 97 | assert.NotNil(input.InstanceConcurrency) 98 | assert.Equal(int32(0), *input.InstanceConcurrency) 99 | 100 | input.WithInstanceConcurrency(int32(1)) 101 | assert.NotNil(input.InstanceConcurrency) 102 | assert.Equal(int32(1), *input.InstanceConcurrency) 103 | } 104 | 105 | output := &GetFunctionOutput{} 106 | assert.Nil(output.InstanceConcurrency) 107 | } 108 | 109 | func (s *FunctionStructsTestSuite) TestCustomContainerArgs() { 110 | assert := s.Require() 111 | 112 | { 113 | input := NewCreateFunctionInput("service") 114 | assert.Equal("service", *input.ServiceName) 115 | assert.Nil(input.CustomContainerConfig) 116 | assert.Nil(input.CAPort) 117 | 118 | input.WithCustomContainerConfig(&CustomContainerConfig{}) 119 | assert.NotNil(input.CustomContainerConfig) 120 | assert.Nil(input.CustomContainerConfig.Image) 121 | assert.Nil(input.CustomContainerConfig.Command) 122 | assert.Nil(input.CustomContainerConfig.Args) 123 | 124 | port := int32(9000) 125 | input.WithCAPort(port) 126 | assert.NotNil(input.CAPort) 127 | assert.Equal(int32(9000), *input.CAPort) 128 | 129 | input.WithCustomContainerConfig(&CustomContainerConfig{ 130 | Image: getStringPointer("registry.cn-hangzhou.aliyuncs.com/fc-test/busybox"), 131 | Command: getStringPointer(`["python", "server.py"]`), 132 | Args: getStringPointer(`["9000"]`), 133 | AccelerationType: getStringPointer(CustomContainerConfigAccelerationTypeNone), 134 | }) 135 | assert.NotNil(input.CustomContainerConfig) 136 | assert.Equal("registry.cn-hangzhou.aliyuncs.com/fc-test/busybox", *input.CustomContainerConfig.Image) 137 | assert.Equal(`["python", "server.py"]`, *input.CustomContainerConfig.Command) 138 | assert.Equal(`["9000"]`, *input.CustomContainerConfig.Args) 139 | assert.Equal("None", *input.CustomContainerConfig.AccelerationType) 140 | } 141 | 142 | { 143 | input := NewUpdateFunctionInput("service", "func") 144 | assert.Equal("service", *input.ServiceName) 145 | assert.Equal("func", *input.FunctionName) 146 | assert.Nil(input.CustomContainerConfig) 147 | assert.Nil(input.CAPort) 148 | 149 | input.WithCustomContainerConfig(&CustomContainerConfig{}) 150 | assert.NotNil(input.CustomContainerConfig) 151 | assert.Nil(input.CustomContainerConfig.Image) 152 | assert.Nil(input.CustomContainerConfig.Command) 153 | assert.Nil(input.CustomContainerConfig.Args) 154 | 155 | port := int32(9000) 156 | input.WithCAPort(port) 157 | assert.NotNil(input.CAPort) 158 | assert.Equal(int32(9000), *input.CAPort) 159 | 160 | input.WithCustomContainerConfig(&CustomContainerConfig{ 161 | Image: getStringPointer("registry.cn-hangzhou.aliyuncs.com/fc-test/busybox"), 162 | Command: getStringPointer(`["python", "server.py"]`), 163 | Args: getStringPointer(`["9000"]`), 164 | AccelerationType: getStringPointer("Default"), 165 | }) 166 | assert.NotNil(input.CustomContainerConfig) 167 | assert.Equal("registry.cn-hangzhou.aliyuncs.com/fc-test/busybox", *input.CustomContainerConfig.Image) 168 | assert.Equal(`["python", "server.py"]`, *input.CustomContainerConfig.Command) 169 | assert.Equal(`["9000"]`, *input.CustomContainerConfig.Args) 170 | assert.Equal(CustomContainerConfigAccelerationTypeDefault, *input.CustomContainerConfig.AccelerationType) 171 | } 172 | 173 | output := &GetFunctionOutput{} 174 | assert.Nil(output.CustomContainerConfig) 175 | assert.Nil(output.CAPort) 176 | 177 | ccc := &CustomContainerConfig{} 178 | assert.Nil(ccc.AccelerationType) 179 | ccc.WithAccelerationType("Default") 180 | assert.Equal("Default", *ccc.AccelerationType) 181 | ccc.WithAccelerationType("None") 182 | assert.Equal("None", *ccc.AccelerationType) 183 | } 184 | 185 | func TestFunctionStructs(t *testing.T) { 186 | suite.Run(t, new(FunctionStructsTestSuite)) 187 | } 188 | -------------------------------------------------------------------------------- /glide.lock: -------------------------------------------------------------------------------- 1 | hash: fdd43ad59a285ff07439be4314c17f424b5487b74d6449feb873aba25132dab2 2 | updated: 2021-11-23T14:40:28.95717+08:00 3 | imports: 4 | - name: github.com/gorilla/websocket 5 | version: c3dd95aea9779669bb3daafbd84ee0530c8ce1c1 6 | - name: github.com/stretchr/testify 7 | version: f6abca593680b2315d2075e0f5e2a9751e3f431a 8 | subpackages: 9 | - assert 10 | - mock 11 | - require 12 | - suite 13 | - name: golang.org/x/net 14 | version: c44066c5c816ec500d459a2a324a753f78531ae0 15 | subpackages: 16 | - publicsuffix 17 | - name: gopkg.in/resty.v1 18 | version: 03c09fa32a21b7b27b8dbb3877826c1ab3d2daa2 19 | testImports: 20 | - name: github.com/davecgh/go-spew 21 | version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9 22 | subpackages: 23 | - spew 24 | - name: github.com/pmezard/go-difflib 25 | version: d8ed2627bdf02c080bf22230dbb337003b7aba2d 26 | subpackages: 27 | - difflib 28 | -------------------------------------------------------------------------------- /glide.yaml: -------------------------------------------------------------------------------- 1 | package: aliyun/serverless/lambda-go-sdk 2 | import: 3 | - package: gopkg.in/resty.v1 4 | version: v1.11.0 5 | - package: github.com/stretchr/testify 6 | version: f6abca593680b2315d2075e0f5e2a9751e3f431a 7 | subpackages: 8 | - assert 9 | - mock 10 | - require 11 | - suite 12 | - package: github.com/gorilla/websocket 13 | version: c3dd95aea9779669bb3daafbd84ee0530c8ce1c1 14 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/aliyun/fc-go-sdk 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/gorilla/websocket v1.4.2 7 | github.com/stretchr/testify v1.3.0 8 | gopkg.in/resty.v1 v1.11.0 9 | ) 10 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= 4 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 8 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= 9 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 10 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis= 11 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 12 | gopkg.in/resty.v1 v1.11.0 h1:z5nqGs/W/h91PLOc+WZefPj8rRZe8Ctlgxg/AtbJ+NE= 13 | gopkg.in/resty.v1 v1.11.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 14 | -------------------------------------------------------------------------------- /http_trigger.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | const ( 4 | // AuthAnonymous defines http trigger without authorized 5 | AuthAnonymous = "anonymous" 6 | 7 | // AuthFunction defines http trigger authorized by AK 8 | AuthFunction = "function" 9 | ) 10 | 11 | // DefaultAuthType ... 12 | var DefaultAuthType = AuthFunction 13 | 14 | // HTTPTriggerConfig .. 15 | type HTTPTriggerConfig struct { 16 | AuthType *string `json:"authType"` 17 | Methods []string `json:"methods"` 18 | } 19 | 20 | // NewHTTPTriggerConfig ... 21 | func NewHTTPTriggerConfig() *HTTPTriggerConfig { 22 | return &HTTPTriggerConfig{} 23 | } 24 | 25 | // WithMethods ... 26 | func (t *HTTPTriggerConfig) WithMethods(methods ...string) *HTTPTriggerConfig { 27 | t.Methods = make([]string, len(methods)) 28 | for i := range methods { 29 | t.Methods[i] = methods[i] 30 | } 31 | return t 32 | } 33 | 34 | // WithAuthType ... 35 | func (t *HTTPTriggerConfig) WithAuthType(authType string) *HTTPTriggerConfig { 36 | t.AuthType = &authType 37 | return t 38 | } 39 | -------------------------------------------------------------------------------- /instance_exec.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/url" 7 | "sync" 8 | "context" 9 | "time" 10 | 11 | "github.com/gorilla/websocket" 12 | ) 13 | 14 | const ( 15 | listInstancesPathName = "/instances" 16 | listInstancesSourcesPath = singleFunctionPath + listInstancesPathName 17 | listInstancesWithQualifierPath = singleFunctionWithQualifierPath + listInstancesPathName 18 | 19 | instanceExecPathName = "/instances/%s/exec" 20 | instanceExecSourcesPath = singleFunctionPath + instanceExecPathName 21 | instanceExecWithQualifierPath = singleFunctionWithQualifierPath + instanceExecPathName 22 | 23 | messageStdin byte = 0 24 | messageStdout byte = 1 25 | messageStderr byte = 2 26 | serverErr byte = 3 27 | reSize byte = 4 28 | serverClose byte = 5 29 | ) 30 | 31 | type MessageCallbackFunction func(data []byte) 32 | 33 | func boolToString(b bool) string { 34 | if b { 35 | return "true" 36 | } 37 | return "false" 38 | } 39 | 40 | 41 | type InstanceExecOutput struct { 42 | Header http.Header 43 | WebsocketConnection *websocket.Conn 44 | ctx context.Context 45 | cancel context.CancelFunc 46 | errChan chan error 47 | lock sync.Mutex 48 | } 49 | 50 | func (o *InstanceExecOutput) start(input *InstanceExecInput) error { 51 | o.ctx, o.cancel = context.WithCancel(context.Background()) 52 | if o.WebsocketConnection == nil { 53 | return fmt.Errorf("WebSocket is not initialized") 54 | } 55 | o.errChan = make(chan error) 56 | go o.reader(input.onStdout, input.onStderr) 57 | o.WebsocketConnection.SetPingHandler(func(data string) error { 58 | o.lock.Lock() 59 | defer o.lock.Unlock() 60 | return o.WebsocketConnection.WriteControl(websocket.PingMessage, []byte(data), time.Now().Add(time.Second*5)) 61 | }) 62 | return nil 63 | } 64 | 65 | func (o *InstanceExecOutput) writeMessage(messageType int, data []byte) error { 66 | o.lock.Lock() 67 | defer o.lock.Unlock() 68 | 69 | return o.WebsocketConnection.WriteMessage(messageType, data) 70 | } 71 | 72 | func (o *InstanceExecOutput) reader(stdout, stderr MessageCallbackFunction) { 73 | for { 74 | select { 75 | case <-o.ctx.Done(): 76 | return 77 | default: 78 | _, msg, err := o.WebsocketConnection.ReadMessage() 79 | if err != nil { 80 | o.reportError(err) 81 | } 82 | if len(msg) > 0 { 83 | var out MessageCallbackFunction 84 | switch msg[0] { 85 | case messageStdout: 86 | out = stdout 87 | case messageStderr: 88 | out = stderr 89 | case serverErr: 90 | o.reportError(fmt.Errorf(string(msg))) 91 | default: 92 | o.reportError(fmt.Errorf("unknown message type %d, message: %s", msg[0], msg)) 93 | } 94 | data := msg[1:] 95 | if out != nil && len(data) > 0 { 96 | out(data) 97 | } 98 | } 99 | } 100 | } 101 | } 102 | 103 | func (o *InstanceExecOutput) reportError(err error) { 104 | if err != nil { 105 | select { 106 | case o.errChan <- err: 107 | default: 108 | } 109 | o.cancel() 110 | } 111 | } 112 | 113 | func (o *InstanceExecOutput) Closed() bool { 114 | select { 115 | case <-o.ctx.Done(): 116 | return true 117 | default: 118 | return false 119 | } 120 | } 121 | 122 | func (o *InstanceExecOutput) ErrorChannel() chan error { 123 | return o.errChan 124 | } 125 | 126 | func (o *InstanceExecOutput) WriteStdin(msg []byte) error { 127 | if o.Closed() { 128 | return fmt.Errorf("WebSocket has closed") 129 | } 130 | return o.writeMessage(websocket.TextMessage, append([]byte{messageStdin}, msg...)) 131 | } 132 | 133 | // InstanceExecInput define publish layer version response 134 | type InstanceExecInput struct { 135 | Header http.Header 136 | ServiceName *string 137 | FunctionName *string 138 | Qualifier *string 139 | InstanceID *string 140 | 141 | Command []string 142 | Stdin bool 143 | Stdout bool 144 | Stderr bool 145 | TTY bool 146 | IdleTimeout *int 147 | 148 | onStdout MessageCallbackFunction 149 | onStderr MessageCallbackFunction 150 | } 151 | 152 | func NewInstanceExecInput( 153 | serviceName, functionName, instanceID string, command []string, 154 | ) *InstanceExecInput { 155 | return &InstanceExecInput{ 156 | ServiceName: &serviceName, 157 | FunctionName: &functionName, 158 | InstanceID: &instanceID, 159 | Command: command, 160 | } 161 | } 162 | 163 | func (i *InstanceExecInput) WithServiceName(serviceName string) *InstanceExecInput { 164 | i.ServiceName = &serviceName 165 | return i 166 | } 167 | 168 | func (i *InstanceExecInput) WithFunctionName(functionName string) *InstanceExecInput { 169 | i.FunctionName = &functionName 170 | return i 171 | } 172 | 173 | func (i *InstanceExecInput) WithQualifier(qualifier string) *InstanceExecInput { 174 | i.Qualifier = &qualifier 175 | return i 176 | } 177 | 178 | func (i *InstanceExecInput) WithInstance(instanceID string) *InstanceExecInput { 179 | i.InstanceID = &instanceID 180 | return i 181 | } 182 | 183 | func (i *InstanceExecInput) WithCommand(command []string) *InstanceExecInput { 184 | i.Command = command 185 | return i 186 | } 187 | 188 | func (i *InstanceExecInput) WithStdin(stdin bool) *InstanceExecInput { 189 | i.Stdin = stdin 190 | return i 191 | } 192 | 193 | func (i *InstanceExecInput) WithStdout(stdout bool) *InstanceExecInput { 194 | i.Stdout = stdout 195 | return i 196 | } 197 | 198 | func (i *InstanceExecInput) WithStderr(stderr bool) *InstanceExecInput { 199 | i.Stderr = stderr 200 | return i 201 | } 202 | 203 | func (i *InstanceExecInput) WithTTY(tty bool) *InstanceExecInput { 204 | i.TTY = tty 205 | return i 206 | } 207 | 208 | func (i *InstanceExecInput) WithIdleTimeout(idleTimeout int) *InstanceExecInput { 209 | i.IdleTimeout = &idleTimeout 210 | return i 211 | } 212 | 213 | func (i *InstanceExecInput) OnStdout(callback MessageCallbackFunction) *InstanceExecInput { 214 | i.onStdout = callback 215 | return i 216 | } 217 | 218 | func (i *InstanceExecInput) OnStderr(callback MessageCallbackFunction) *InstanceExecInput { 219 | i.onStderr = callback 220 | return i 221 | } 222 | 223 | func (i *InstanceExecInput) GetQueryParams() url.Values { 224 | queries := make(url.Values) 225 | for _, cmd := range i.Command { 226 | queries.Add("command", cmd) 227 | } 228 | queries.Add("stdin", boolToString(i.Stdin)) 229 | queries.Add("stdout", boolToString(i.Stdout)) 230 | queries.Add("stderr", boolToString(i.Stderr)) 231 | queries.Add("tty", boolToString(i.TTY)) 232 | if i.IdleTimeout != nil { 233 | queries.Add("idleTimeout", fmt.Sprint(*i.IdleTimeout)) 234 | } 235 | return queries 236 | } 237 | 238 | func (i *InstanceExecInput) GetPath() string { 239 | if i.Qualifier != nil { 240 | return fmt.Sprintf(instanceExecWithQualifierPath, pathEscape(*i.ServiceName), pathEscape(*i.Qualifier), pathEscape(*i.FunctionName), pathEscape(*i.InstanceID)) 241 | } else { 242 | return fmt.Sprintf(instanceExecSourcesPath, pathEscape(*i.ServiceName), pathEscape(*i.FunctionName), pathEscape(*i.InstanceID)) 243 | } 244 | } 245 | 246 | func (i *InstanceExecInput) GetHeaders() Header { 247 | return make(Header) 248 | } 249 | 250 | func (i *InstanceExecInput) GetPayload() interface{} { 251 | return nil 252 | } 253 | 254 | func (i *InstanceExecInput) Validate() error { 255 | if IsBlank(i.ServiceName) { 256 | return fmt.Errorf("Service name is required but not provided") 257 | } 258 | if IsBlank(i.FunctionName) { 259 | return fmt.Errorf("Function name is required but not provided") 260 | } 261 | if IsBlank(i.InstanceID) { 262 | return fmt.Errorf("InstanceID is required but not provided") 263 | } 264 | if i.Command == nil || len(i.Command) == 0 { 265 | return fmt.Errorf("Command is required but not provided") 266 | } 267 | return nil 268 | } 269 | -------------------------------------------------------------------------------- /layers.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | "strconv" 9 | ) 10 | 11 | const ( 12 | layersPath = "/layers" 13 | singleLayerPath = layersPath + "/%s" 14 | singleLayerVersionPath = singleLayerPath + "/versions/%d" 15 | layerArnPath = "/layerarn" 16 | adminLayersPath = "/adminlayers/%s/%s/versions/%d" 17 | AnyRunTime = "Any" 18 | ) 19 | 20 | // OutputCodeLocation represents the output code location. 21 | type OutputCodeLocation struct { 22 | RepositoryType *string `json:"repositoryType"` 23 | Location *string `json:"location"` 24 | } 25 | 26 | type Layer struct { 27 | LayerName string `json:"layerName"` 28 | Version int32 `json:"version"` 29 | Description string `json:"description"` 30 | Code OutputCodeLocation `json:"code"` 31 | CodeSize int64 `json:"codeSize"` 32 | CodeChecksum string `json:"codeChecksum"` 33 | CreateTime string `json:"createTime"` 34 | ACL int32 `json:"acl"` 35 | CompatibleRuntime []string `json:"compatibleRuntime"` 36 | Arn string `json:"arn"` 37 | } 38 | 39 | // PublishLayerVersionInput defines input to create layer version 40 | type PublishLayerVersionInput struct { 41 | LayerName string `json:"layerName"` 42 | Description string `json:"description"` 43 | Code *Code `json:"code"` 44 | CompatibleRuntime []string `json:"compatibleRuntime"` 45 | } 46 | 47 | func NewPublishLayerVersionInput() *PublishLayerVersionInput { 48 | return &PublishLayerVersionInput{} 49 | } 50 | 51 | func (s *PublishLayerVersionInput) WithLayerName(layerName string) *PublishLayerVersionInput { 52 | s.LayerName = layerName 53 | return s 54 | } 55 | 56 | func (s *PublishLayerVersionInput) WithDescription(description string) *PublishLayerVersionInput { 57 | s.Description = description 58 | return s 59 | } 60 | 61 | func (s *PublishLayerVersionInput) WithCompatibleRuntime(compatibleRuntime []string) *PublishLayerVersionInput { 62 | s.CompatibleRuntime = compatibleRuntime 63 | return s 64 | } 65 | 66 | func (s *PublishLayerVersionInput) WithCode(code *Code) *PublishLayerVersionInput { 67 | s.Code = code 68 | return s 69 | } 70 | 71 | func (i *PublishLayerVersionInput) GetQueryParams() url.Values { 72 | out := url.Values{} 73 | return out 74 | } 75 | 76 | func (i *PublishLayerVersionInput) GetPath() string { 77 | return layersPath + "/" + i.LayerName + "/versions" 78 | } 79 | 80 | func (i *PublishLayerVersionInput) GetHeaders() Header { 81 | return make(Header, 0) 82 | } 83 | 84 | func (i *PublishLayerVersionInput) GetPayload() interface{} { 85 | return i 86 | } 87 | 88 | func (i *PublishLayerVersionInput) Validate() error { 89 | return nil 90 | } 91 | 92 | type PublishPublicLayerVersionOutput struct { 93 | Header http.Header 94 | } 95 | 96 | // PublishLayerVersionOutput define publish layer version response 97 | type PublishLayerVersionOutput struct { 98 | Header http.Header 99 | Layer 100 | } 101 | 102 | func (o PublishLayerVersionInput) String() string { 103 | b, err := json.MarshalIndent(o, "", printIndent) 104 | if err != nil { 105 | return "" 106 | } 107 | return string(b) 108 | } 109 | 110 | func (o PublishLayerVersionOutput) GetRequestID() string { 111 | return GetRequestID(o.Header) 112 | } 113 | 114 | func (o PublishLayerVersionOutput) GetEtag() string { 115 | return GetEtag(o.Header) 116 | } 117 | 118 | // GetLayerVersionOutput define get layer version response 119 | type GetLayerVersionOutput struct { 120 | Header http.Header 121 | Layer 122 | } 123 | 124 | func (o GetLayerVersionOutput) String() string { 125 | b, err := json.MarshalIndent(o, "", printIndent) 126 | if err != nil { 127 | return "" 128 | } 129 | return string(b) 130 | } 131 | 132 | func (o GetLayerVersionOutput) GetRequestID() string { 133 | return GetRequestID(o.Header) 134 | } 135 | 136 | func (o GetLayerVersionOutput) GetEtag() string { 137 | return GetEtag(o.Header) 138 | } 139 | 140 | // ListLayersOutput defines List layers result 141 | type ListLayersOutput struct { 142 | Header http.Header 143 | Layers []*Layer `json:"layers"` 144 | NextToken *string `json:"nextToken,omitempty"` 145 | } 146 | 147 | func (o ListLayersOutput) String() string { 148 | b, err := json.MarshalIndent(o, "", printIndent) 149 | if err != nil { 150 | return "" 151 | } 152 | return string(b) 153 | } 154 | 155 | func (o ListLayersOutput) GetRequestID() string { 156 | return GetRequestID(o.Header) 157 | } 158 | 159 | type ListLayersInput struct { 160 | Query 161 | public bool 162 | } 163 | 164 | func NewListLayersInput() *ListLayersInput { 165 | return &ListLayersInput{} 166 | } 167 | 168 | func (i *ListLayersInput) WithPrefix(prefix string) *ListLayersInput { 169 | i.Prefix = &prefix 170 | return i 171 | } 172 | 173 | func (i *ListLayersInput) WithStartKey(startKey string) *ListLayersInput { 174 | i.StartKey = &startKey 175 | return i 176 | } 177 | 178 | func (i *ListLayersInput) WithNextToken(nextToken string) *ListLayersInput { 179 | i.NextToken = &nextToken 180 | return i 181 | } 182 | 183 | func (i *ListLayersInput) WithLimit(limit int32) *ListLayersInput { 184 | i.Limit = &limit 185 | return i 186 | } 187 | 188 | func (i *ListLayersInput) WithPublic(public bool) *ListLayersInput { 189 | i.public = public 190 | return i 191 | } 192 | 193 | func (i *ListLayersInput) GetQueryParams() url.Values { 194 | out := url.Values{} 195 | if i.Prefix != nil { 196 | out.Set("prefix", *i.Prefix) 197 | } 198 | 199 | if i.StartKey != nil { 200 | out.Set("startKey", *i.StartKey) 201 | } 202 | 203 | if i.NextToken != nil { 204 | out.Set("nextToken", *i.NextToken) 205 | } 206 | 207 | if i.Limit != nil { 208 | out.Set("limit", strconv.FormatInt(int64(*i.Limit), 10)) 209 | } 210 | 211 | if i.public { 212 | out.Set("public", "true") 213 | } 214 | 215 | if i.Tags != nil { 216 | for k, v := range i.Tags { 217 | out.Set(tagQueryPrefix+k, v) 218 | } 219 | } 220 | 221 | return out 222 | } 223 | 224 | func (i *ListLayersInput) GetPath() string { 225 | return layersPath 226 | } 227 | 228 | func (i *ListLayersInput) GetHeaders() Header { 229 | return make(Header, 0) 230 | } 231 | 232 | func (i *ListLayersInput) GetPayload() interface{} { 233 | return nil 234 | } 235 | 236 | func (i *ListLayersInput) Validate() error { 237 | return nil 238 | } 239 | 240 | type GetLayerVersionInput struct { 241 | LayerName string 242 | Version int32 243 | } 244 | 245 | func NewGetLayerVersionInput(layerName string, version int32) *GetLayerVersionInput { 246 | return &GetLayerVersionInput{LayerName: layerName, Version: version} 247 | } 248 | 249 | func (i *GetLayerVersionInput) GetQueryParams() url.Values { 250 | out := url.Values{} 251 | return out 252 | } 253 | 254 | func (i *GetLayerVersionInput) GetPath() string { 255 | return fmt.Sprintf(singleLayerVersionPath, pathEscape(i.LayerName), i.Version) 256 | } 257 | 258 | func (i *GetLayerVersionInput) GetHeaders() Header { 259 | return make(Header, 0) 260 | } 261 | 262 | func (i *GetLayerVersionInput) GetPayload() interface{} { 263 | return nil 264 | } 265 | 266 | func (i *GetLayerVersionInput) Validate() error { 267 | if i.Version <= 0 { 268 | return fmt.Errorf("Version must be a positive number.") 269 | } 270 | 271 | return nil 272 | } 273 | 274 | type GetLayerVersionByArnInput struct { 275 | Arn string 276 | } 277 | 278 | func NewGetLayerVersionByArnInput(arn string) *GetLayerVersionByArnInput { 279 | return &GetLayerVersionByArnInput{Arn: arn} 280 | } 281 | 282 | func (i *GetLayerVersionByArnInput) GetQueryParams() url.Values { 283 | out := url.Values{} 284 | return out 285 | } 286 | 287 | func (i *GetLayerVersionByArnInput) GetPath() string { 288 | return layerArnPath + "/" + pathEscape(i.Arn) 289 | } 290 | 291 | func (i *GetLayerVersionByArnInput) GetHeaders() Header { 292 | return make(Header, 0) 293 | } 294 | 295 | func (i *GetLayerVersionByArnInput) GetPayload() interface{} { 296 | return nil 297 | } 298 | 299 | func (i *GetLayerVersionByArnInput) Validate() error { 300 | if len(i.Arn) == 0 { 301 | return fmt.Errorf("Arm should not be empty.") 302 | } 303 | 304 | return nil 305 | } 306 | 307 | type DeleteLayerVersionInput struct { 308 | LayerName string 309 | Version int32 310 | } 311 | 312 | func NewDeleteLayerVersionInput(layerName string, version int32) *DeleteLayerVersionInput { 313 | return &DeleteLayerVersionInput{LayerName: layerName, Version: version} 314 | } 315 | 316 | func (i *DeleteLayerVersionInput) GetQueryParams() url.Values { 317 | out := url.Values{} 318 | return out 319 | } 320 | 321 | func (i *DeleteLayerVersionInput) GetPath() string { 322 | return fmt.Sprintf(singleLayerVersionPath, pathEscape(i.LayerName), i.Version) 323 | } 324 | 325 | func (i *DeleteLayerVersionInput) GetHeaders() Header { 326 | header := make(Header) 327 | return header 328 | } 329 | 330 | func (i *DeleteLayerVersionInput) GetPayload() interface{} { 331 | return nil 332 | } 333 | 334 | func (i *DeleteLayerVersionInput) Validate() error { 335 | if i.Version <= 0 { 336 | return fmt.Errorf("Layer version must be a positive number.") 337 | } 338 | return nil 339 | } 340 | 341 | type DeleteLayerVersionOutput struct { 342 | Header http.Header 343 | } 344 | 345 | func (o DeleteLayerVersionOutput) String() string { 346 | b, err := json.MarshalIndent(o, "", printIndent) 347 | if err != nil { 348 | return "" 349 | } 350 | return string(b) 351 | } 352 | 353 | func (o DeleteLayerVersionOutput) GetRequestID() string { 354 | return GetRequestID(o.Header) 355 | } 356 | 357 | type ListLayerVersionsInput struct { 358 | LayerName string 359 | StartVersion int32 360 | Limit int32 361 | } 362 | 363 | func NewListLayerVersionsInput(layerName string, version int32) *ListLayerVersionsInput { 364 | return &ListLayerVersionsInput{LayerName: layerName, StartVersion: version, Limit: 20} 365 | } 366 | 367 | func (i *ListLayerVersionsInput) WithLimit(limit int32) *ListLayerVersionsInput { 368 | i.Limit = limit 369 | return i 370 | } 371 | 372 | func (i *ListLayerVersionsInput) GetQueryParams() url.Values { 373 | out := url.Values{} 374 | out.Set("startVersion", strconv.FormatInt(int64(i.StartVersion), 10)) 375 | 376 | if i.Limit != 0 { 377 | out.Set("limit", strconv.FormatInt(int64(i.Limit), 10)) 378 | } 379 | 380 | return out 381 | } 382 | 383 | func (i *ListLayerVersionsInput) GetPath() string { 384 | return fmt.Sprintf(singleLayerPath, pathEscape(i.LayerName)) + "/versions" 385 | } 386 | 387 | func (i *ListLayerVersionsInput) GetHeaders() Header { 388 | return make(Header, 0) 389 | } 390 | 391 | func (i *ListLayerVersionsInput) GetPayload() interface{} { 392 | return nil 393 | } 394 | 395 | func (i *ListLayerVersionsInput) Validate() error { 396 | if i.StartVersion <= 0 { 397 | return fmt.Errorf("Version must be a positive number.") 398 | } 399 | 400 | return nil 401 | } 402 | 403 | type ListLayerVersionsOutput struct { 404 | Header http.Header 405 | Layers []*Layer `json:"layers"` 406 | NextVersion *int32 `json:"nextVersion,omitempty"` 407 | } 408 | 409 | func (o ListLayerVersionsOutput) String() string { 410 | b, err := json.MarshalIndent(o, "", printIndent) 411 | if err != nil { 412 | return "" 413 | } 414 | return string(b) 415 | } 416 | 417 | func (o ListLayerVersionsOutput) GetRequestID() string { 418 | return GetRequestID(o.Header) 419 | } 420 | 421 | type PermanentDeleteLayerVersionInput struct { 422 | LayerName string 423 | Version int32 424 | LayerOwnerUserID string 425 | } 426 | 427 | func NewPermanentDeleteLayerVersionInput(layerOwnerUserID, layerName string, version int32) *PermanentDeleteLayerVersionInput { 428 | return &PermanentDeleteLayerVersionInput{LayerOwnerUserID: layerOwnerUserID, LayerName: layerName, Version: version} 429 | } 430 | 431 | func (i *PermanentDeleteLayerVersionInput) GetQueryParams() url.Values { 432 | out := url.Values{} 433 | return out 434 | } 435 | 436 | func (i *PermanentDeleteLayerVersionInput) GetPath() string { 437 | return fmt.Sprintf(adminLayersPath, i.LayerOwnerUserID, pathEscape(i.LayerName), i.Version) 438 | } 439 | 440 | func (i *PermanentDeleteLayerVersionInput) GetHeaders() Header { 441 | return make(Header, 0) 442 | } 443 | 444 | func (i *PermanentDeleteLayerVersionInput) GetPayload() interface{} { 445 | return nil 446 | } 447 | 448 | func (i *PermanentDeleteLayerVersionInput) Validate() error { 449 | if i.Version <= 0 { 450 | return fmt.Errorf("Version must be a positive number") 451 | } 452 | 453 | if len(i.LayerOwnerUserID) <= 0 { 454 | return fmt.Errorf("LayerOwnerUserID must be specified") 455 | } 456 | 457 | return nil 458 | } 459 | -------------------------------------------------------------------------------- /list_instances.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/url" 7 | ) 8 | 9 | type Instance struct { 10 | InstanceID string `json:"instanceId"` 11 | VersionID int `json:"versionId"` 12 | } 13 | 14 | type ListInstancesOutput struct { 15 | Header http.Header 16 | Instances []*Instance 17 | } 18 | 19 | // ListInstancesInput define publish layer version response 20 | type ListInstancesInput struct { 21 | Header http.Header 22 | ServiceName *string 23 | FunctionName *string 24 | Qualifier *string 25 | Limit *int 26 | NextToken *string 27 | } 28 | 29 | func NewListInstancesInput(serviceName, functionName string) *ListInstancesInput { 30 | return &ListInstancesInput{ 31 | ServiceName: &serviceName, 32 | FunctionName: &functionName, 33 | } 34 | } 35 | 36 | func (i *ListInstancesInput) WithServiceName(serviceName string) *ListInstancesInput { 37 | i.ServiceName = &serviceName 38 | return i 39 | } 40 | 41 | func (i *ListInstancesInput) WithFunctionName(functionName string) *ListInstancesInput { 42 | i.FunctionName = &functionName 43 | return i 44 | } 45 | 46 | func (i *ListInstancesInput) WithQualifier(qualifier string) *ListInstancesInput { 47 | i.Qualifier = &qualifier 48 | return i 49 | } 50 | 51 | func (i *ListInstancesInput) WithLimit(limit int) *ListInstancesInput { 52 | i.Limit = &limit 53 | return i 54 | } 55 | 56 | func (i *ListInstancesInput) WithNextToken(nextToken string) *ListInstancesInput { 57 | i.NextToken = &nextToken 58 | return i 59 | } 60 | 61 | func (i ListInstancesInput) GetQueryParams() url.Values { 62 | queries := make(url.Values) 63 | if i.Limit != nil { 64 | queries.Add("limit", fmt.Sprint(*i.Limit)) 65 | } 66 | if i.NextToken != nil { 67 | queries.Add("nextToken", *i.NextToken) 68 | } 69 | return queries 70 | } 71 | 72 | func (i ListInstancesInput) GetPath() string { 73 | if i.Qualifier != nil { 74 | return fmt.Sprintf(listInstancesWithQualifierPath, pathEscape(*i.ServiceName), pathEscape(*i.Qualifier), pathEscape(*i.FunctionName)) 75 | } else { 76 | return fmt.Sprintf(listInstancesSourcesPath, pathEscape(*i.ServiceName), pathEscape(*i.FunctionName)) 77 | } 78 | } 79 | 80 | func (i ListInstancesInput) GetHeaders() Header { 81 | return make(Header) 82 | } 83 | 84 | func (i ListInstancesInput) GetPayload() interface{} { 85 | return nil 86 | } 87 | 88 | func (i ListInstancesInput) Validate() error { 89 | if IsBlank(i.ServiceName) { 90 | return fmt.Errorf("Service name is required but not provided") 91 | } 92 | if IsBlank(i.FunctionName) { 93 | return fmt.Errorf("Function name is required but not provided") 94 | } 95 | return nil 96 | } -------------------------------------------------------------------------------- /log_trigger.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | // LogTriggerConfig .. 4 | type LogTriggerConfig struct { 5 | SourceConfig *SourceConfig `json:"sourceConfig"` 6 | JobConfig *JobConfig `json:"jobConfig"` 7 | FunctionParameter map[string]interface{} `json:"functionParameter"` 8 | LogConfig *JobLogConfig `json:"logConfig"` 9 | Enable *bool `json:"enable"` 10 | } 11 | 12 | func NewLogTriggerConfig() *LogTriggerConfig { 13 | return &LogTriggerConfig{} 14 | } 15 | 16 | func (ltc *LogTriggerConfig) WithSourceConfig(c *SourceConfig) *LogTriggerConfig { 17 | ltc.SourceConfig = c 18 | return ltc 19 | } 20 | 21 | func (ltc *LogTriggerConfig) WithJobConfig(c *JobConfig) *LogTriggerConfig { 22 | ltc.JobConfig = c 23 | return ltc 24 | } 25 | 26 | func (ltc *LogTriggerConfig) WithFunctionParameter(p map[string]interface{}) *LogTriggerConfig { 27 | ltc.FunctionParameter = p 28 | return ltc 29 | } 30 | 31 | func (ltc *LogTriggerConfig) WithLogConfig(c *JobLogConfig) *LogTriggerConfig { 32 | ltc.LogConfig = c 33 | return ltc 34 | } 35 | 36 | func (ltc *LogTriggerConfig) WithEnable(enable bool) *LogTriggerConfig { 37 | ltc.Enable = &enable 38 | return ltc 39 | } 40 | 41 | // SourceConfig .. 42 | type SourceConfig struct { 43 | Logstore *string `json:"logstore"` 44 | } 45 | 46 | func NewSourceConfig() *SourceConfig { 47 | return &SourceConfig{} 48 | } 49 | 50 | func (sc *SourceConfig) WithLogstore(store string) *SourceConfig { 51 | sc.Logstore = &store 52 | return sc 53 | } 54 | 55 | // JobConfig maps to Log service's trigger config. 56 | type JobConfig struct { 57 | MaxRetryTime *int `json:"maxRetryTime"` 58 | TriggerInterval *int `json:"triggerInterval"` 59 | } 60 | 61 | func NewJobConfig() *JobConfig { 62 | return &JobConfig{} 63 | } 64 | 65 | func (jc *JobConfig) WithMaxRetryTime(retry int) *JobConfig { 66 | jc.MaxRetryTime = &retry 67 | return jc 68 | } 69 | 70 | func (jc *JobConfig) WithTriggerInterval(interval int) *JobConfig { 71 | jc.TriggerInterval = &interval 72 | return jc 73 | } 74 | 75 | // LogConfig .. 76 | type JobLogConfig struct { 77 | Project *string `json:"project"` 78 | Logstore *string `json:"logstore"` 79 | } 80 | 81 | func NewJobLogConfig() *JobLogConfig { 82 | return &JobLogConfig{} 83 | } 84 | 85 | func (jlc *JobLogConfig) WithProject(p string) *JobLogConfig { 86 | jlc.Project = &p 87 | return jlc 88 | } 89 | 90 | func (jlc *JobLogConfig) WithLogstore(s string) *JobLogConfig { 91 | jlc.Logstore = &s 92 | return jlc 93 | } 94 | -------------------------------------------------------------------------------- /mns_trigger.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | // MnsTopicTriggerConfig .. 4 | type MnsTopicTriggerConfig struct { 5 | FilterTag *string `json:"filterTag"` 6 | NotifyContentFormat *string `json:"notifyContentFormat"` 7 | NotifyStrategy *string `json:"notifyStrategy"` 8 | } 9 | 10 | // NewMnsTopicTriggerConfig .. 11 | func NewMnsTopicTriggerConfig() *MnsTopicTriggerConfig { 12 | return &MnsTopicTriggerConfig{} 13 | } 14 | 15 | func (mtc *MnsTopicTriggerConfig) WithFilterTag(filterTag string) *MnsTopicTriggerConfig { 16 | mtc.FilterTag = &filterTag 17 | return mtc 18 | } 19 | 20 | func (mtc *MnsTopicTriggerConfig) WithNotifyContentFormat(notifyContentFormat string) *MnsTopicTriggerConfig { 21 | mtc.NotifyContentFormat = ¬ifyContentFormat 22 | return mtc 23 | } 24 | 25 | func (mtc *MnsTopicTriggerConfig) WithNotifyStrategy(notifyStrategy string) *MnsTopicTriggerConfig { 26 | mtc.NotifyStrategy = ¬ifyStrategy 27 | return mtc 28 | } 29 | -------------------------------------------------------------------------------- /on_demand_config.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | ) 9 | 10 | const ( 11 | DefaultListLimit = 100 12 | ) 13 | 14 | type OnDemandConfig struct { 15 | Resource *string `json:"resource"` 16 | MaximumInstanceCount *int64 `json:"maximumInstanceCount"` 17 | } 18 | 19 | type OnDemandConfigs struct { 20 | Configs []*OnDemandConfig `json:"configs"` 21 | NextToken *string `json:"nextToken,omitempty"` 22 | } 23 | 24 | type ListOnDemandConfigsInput struct { 25 | Prefix *string `json:"prefix"` 26 | StartKey *string `json:"startKey"` 27 | NextToken *string `json:"nextToken,omitempty"` 28 | Limit int `json:"limit,omitempty"` 29 | } 30 | 31 | type ListOnDemandConfigsOutput struct { 32 | Header http.Header 33 | OnDemandConfigs 34 | } 35 | 36 | func NewListOnDemandConfigsInput() *ListOnDemandConfigsInput { 37 | emptyStr := "" 38 | return &ListOnDemandConfigsInput{ 39 | Prefix: &emptyStr, 40 | StartKey: &emptyStr, 41 | NextToken: &emptyStr, 42 | Limit: DefaultListLimit, 43 | } 44 | } 45 | 46 | func (i *ListOnDemandConfigsInput) WithPrefix(prefix string) *ListOnDemandConfigsInput { 47 | i.Prefix = &prefix 48 | return i 49 | } 50 | 51 | func (i *ListOnDemandConfigsInput) WithStartKey(startKey string) *ListOnDemandConfigsInput { 52 | i.StartKey = &startKey 53 | return i 54 | } 55 | 56 | func (i *ListOnDemandConfigsInput) WithNextToken(nextToken string) *ListOnDemandConfigsInput { 57 | i.NextToken = &nextToken 58 | return i 59 | } 60 | 61 | func (i *ListOnDemandConfigsInput) WithLimit(limit int) *ListOnDemandConfigsInput { 62 | i.Limit = limit 63 | return i 64 | } 65 | 66 | func (i *ListOnDemandConfigsInput) GetPath() string { 67 | return onDemandConfigPath 68 | } 69 | 70 | func (i *ListOnDemandConfigsInput) GetHeaders() Header { 71 | return make(Header) 72 | } 73 | 74 | func (i *ListOnDemandConfigsInput) GetPayload() interface{} { 75 | return nil 76 | } 77 | 78 | func (i *ListOnDemandConfigsInput) GetQueryParams() url.Values { 79 | return url.Values{ 80 | "prefix": []string{*i.Prefix}, 81 | "startKey": []string{*i.StartKey}, 82 | "nextToken": []string{*i.NextToken}, 83 | "limit": []string{fmt.Sprintf("%d", i.Limit)}, 84 | } 85 | } 86 | 87 | func (i *ListOnDemandConfigsInput) Validate() error { 88 | return nil 89 | } 90 | 91 | func (o ListOnDemandConfigsOutput) String() string { 92 | b, err := json.MarshalIndent(o, "", printIndent) 93 | if err != nil { 94 | return "" 95 | } 96 | return string(b) 97 | } 98 | 99 | func (o ListOnDemandConfigsOutput) GetRequestID() string { 100 | return GetRequestID(o.Header) 101 | } 102 | 103 | type PutOnDemandConfigObject struct { 104 | MaximumInstanceCount *int64 `json:"maximumInstanceCount"` 105 | } 106 | 107 | type PutOnDemandConfigInput struct { 108 | PutOnDemandConfigObject 109 | ServiceName *string `json:"serviceName"` 110 | Qualifier *string `json:"qualifier"` 111 | FunctionName *string `json:"functionName"` 112 | IfMatch *string 113 | } 114 | 115 | func NewPutOnDemandConfigInput(serviceName, qualifier, functionName string) *PutOnDemandConfigInput { 116 | return &PutOnDemandConfigInput{ 117 | ServiceName: &serviceName, 118 | Qualifier: &qualifier, 119 | FunctionName: &functionName, 120 | } 121 | } 122 | 123 | func (i *PutOnDemandConfigInput) WithMaximumInstanceCount(maximumInstanceCount int64) *PutOnDemandConfigInput { 124 | i.MaximumInstanceCount = &maximumInstanceCount 125 | return i 126 | } 127 | 128 | func (i *PutOnDemandConfigInput) WithIfMatch(ifMatch string) *PutOnDemandConfigInput { 129 | i.IfMatch = &ifMatch 130 | return i 131 | } 132 | 133 | func (i *PutOnDemandConfigInput) GetPath() string { 134 | return fmt.Sprintf(onDemandConfigWithQualifierPath, pathEscape(*i.ServiceName), pathEscape(*i.Qualifier), pathEscape(*i.FunctionName)) 135 | } 136 | 137 | func (i *PutOnDemandConfigInput) GetHeaders() Header { 138 | header := make(Header) 139 | if i.IfMatch != nil { 140 | header[ifMatch] = *i.IfMatch 141 | } 142 | return header 143 | } 144 | 145 | func (i *PutOnDemandConfigInput) GetPayload() interface{} { 146 | return i.PutOnDemandConfigObject 147 | } 148 | 149 | func (i *PutOnDemandConfigInput) GetQueryParams() url.Values { 150 | return url.Values{} 151 | } 152 | 153 | func (i *PutOnDemandConfigInput) Validate() error { 154 | return nil 155 | } 156 | 157 | type PutOnDemandConfigOutput struct { 158 | Header http.Header 159 | OnDemandConfig 160 | } 161 | 162 | func (o PutOnDemandConfigOutput) String() string { 163 | b, err := json.MarshalIndent(o, "", printIndent) 164 | if err != nil { 165 | return "" 166 | } 167 | return string(b) 168 | } 169 | 170 | func (o PutOnDemandConfigOutput) GetRequestID() string { 171 | return GetRequestID(o.Header) 172 | } 173 | 174 | func (o PutOnDemandConfigOutput) GetEtag() string { 175 | return GetEtag(o.Header) 176 | } 177 | 178 | type GetOnDemandConfigInput struct { 179 | ServiceName *string `json:"serviceName"` 180 | Qualifier *string `json:"qualifier"` 181 | FunctionName *string `json:"functionName"` 182 | } 183 | 184 | func NewGetOnDemandConfigInput(serviceName, qualifier, functionName string) *GetOnDemandConfigInput { 185 | return &GetOnDemandConfigInput{ 186 | ServiceName: &serviceName, 187 | Qualifier: &qualifier, 188 | FunctionName: &functionName, 189 | } 190 | } 191 | 192 | func (i *GetOnDemandConfigInput) GetPath() string { 193 | return fmt.Sprintf(onDemandConfigWithQualifierPath, pathEscape(*i.ServiceName), pathEscape(*i.Qualifier), pathEscape(*i.FunctionName)) 194 | } 195 | 196 | func (i *GetOnDemandConfigInput) GetHeaders() Header { 197 | return make(Header, 0) 198 | } 199 | 200 | func (i *GetOnDemandConfigInput) GetPayload() interface{} { 201 | return nil 202 | } 203 | 204 | func (i *GetOnDemandConfigInput) GetQueryParams() url.Values { 205 | return url.Values{} 206 | } 207 | 208 | func (i *GetOnDemandConfigInput) Validate() error { 209 | return nil 210 | } 211 | 212 | type GetOnDemandConfigOutput struct { 213 | Header http.Header 214 | OnDemandConfig 215 | } 216 | 217 | func (o GetOnDemandConfigOutput) String() string { 218 | b, err := json.MarshalIndent(o, "", printIndent) 219 | if err != nil { 220 | return "" 221 | } 222 | return string(b) 223 | } 224 | 225 | func (o GetOnDemandConfigOutput) GetRequestID() string { 226 | return GetRequestID(o.Header) 227 | } 228 | 229 | func (o GetOnDemandConfigOutput) GetEtag() string { 230 | return GetEtag(o.Header) 231 | } 232 | 233 | type DeleteOnDemandConfigInput struct { 234 | ServiceName *string `json:"serviceName"` 235 | Qualifier *string `json:"qualifier"` 236 | FunctionName *string `json:"functionName"` 237 | IfMatch *string 238 | } 239 | 240 | func NewDeleteOnDemandConfigInput(serviceName, qualifier, functionName string) *DeleteOnDemandConfigInput { 241 | return &DeleteOnDemandConfigInput{ 242 | ServiceName: &serviceName, 243 | Qualifier: &qualifier, 244 | FunctionName: &functionName, 245 | } 246 | } 247 | 248 | func (s *DeleteOnDemandConfigInput) WithIfMatch(ifMatch string) *DeleteOnDemandConfigInput { 249 | s.IfMatch = &ifMatch 250 | return s 251 | } 252 | 253 | func (i *DeleteOnDemandConfigInput) GetPath() string { 254 | return fmt.Sprintf(onDemandConfigWithQualifierPath, pathEscape(*i.ServiceName), pathEscape(*i.Qualifier), pathEscape(*i.FunctionName)) 255 | } 256 | 257 | func (i *DeleteOnDemandConfigInput) GetHeaders() Header { 258 | header := make(Header) 259 | if i.IfMatch != nil { 260 | header[ifMatch] = *i.IfMatch 261 | } 262 | return header 263 | } 264 | 265 | func (i *DeleteOnDemandConfigInput) GetPayload() interface{} { 266 | return nil 267 | } 268 | 269 | func (i *DeleteOnDemandConfigInput) GetQueryParams() url.Values { 270 | return url.Values{} 271 | } 272 | 273 | func (i *DeleteOnDemandConfigInput) Validate() error { 274 | return nil 275 | } 276 | 277 | type DeleteOnDemandConfigOutput struct { 278 | Header http.Header 279 | } 280 | 281 | func (o DeleteOnDemandConfigOutput) String() string { 282 | b, err := json.MarshalIndent(o, "", printIndent) 283 | if err != nil { 284 | return "" 285 | } 286 | return string(b) 287 | } 288 | 289 | func (o DeleteOnDemandConfigOutput) GetRequestID() string { 290 | return GetRequestID(o.Header) 291 | } 292 | -------------------------------------------------------------------------------- /on_demand_config_test.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/suite" 9 | ) 10 | 11 | var ( 12 | maximumInstanceCount = int64(10) 13 | ) 14 | 15 | func TestOnDemandConfigStruct(t *testing.T) { 16 | suite.Run(t, new(OnDemandConfigStructsTestSuite)) 17 | } 18 | 19 | type OnDemandConfigStructsTestSuite struct { 20 | suite.Suite 21 | } 22 | 23 | func (s *OnDemandConfigStructsTestSuite) TestPutOnDemandConfig_Success() { 24 | assert := s.Require() 25 | 26 | input := NewPutOnDemandConfigInput(serviceName, qualifier, functionName) 27 | assert.NotNil(input) 28 | assert.Equal(serviceName, *input.ServiceName) 29 | assert.Equal(qualifier, *input.Qualifier) 30 | assert.Equal(functionName, *input.FunctionName) 31 | assert.NotNil(input.PutOnDemandConfigObject) 32 | assert.Nil(input.MaximumInstanceCount) 33 | assert.Nil(input.IfMatch) 34 | assert.Equal(fmt.Sprintf(onDemandConfigWithQualifierPath, pathEscape(serviceName), pathEscape(qualifier), pathEscape(functionName)), input.GetPath()) 35 | assert.Equal(input.PutOnDemandConfigObject, input.GetPayload()) 36 | 37 | input.WithMaximumInstanceCount(maximumInstanceCount) 38 | assert.NotNil(input.PutOnDemandConfigObject) 39 | assert.NotNil(input.MaximumInstanceCount) 40 | assert.Equal(maximumInstanceCount, *input.MaximumInstanceCount) 41 | assert.Equal(input.PutOnDemandConfigObject, input.GetPayload()) 42 | 43 | input.WithIfMatch(ifMatch) 44 | assert.NotNil(input.IfMatch) 45 | assert.Equal(ifMatch, *input.IfMatch) 46 | 47 | err := input.Validate() 48 | assert.Nil(err) 49 | } 50 | 51 | func (s *OnDemandConfigStructsTestSuite) TestPutOnDemandConfig_EmptyParams() { 52 | assert := s.Require() 53 | 54 | input := NewPutOnDemandConfigInput("", qualifier, functionName) 55 | err := input.Validate() 56 | assert.Nil(err) 57 | 58 | input = NewPutOnDemandConfigInput(serviceName, "", functionName) 59 | err = input.Validate() 60 | assert.Nil(err) 61 | 62 | input = NewPutOnDemandConfigInput(serviceName, qualifier, "") 63 | err = input.Validate() 64 | assert.Nil(err) 65 | } 66 | 67 | func (s *OnDemandConfigStructsTestSuite) TestGetOnDemandConfig_Success() { 68 | assert := s.Require() 69 | 70 | input := NewGetOnDemandConfigInput(serviceName, qualifier, functionName) 71 | assert.NotNil(input) 72 | assert.Equal(serviceName, *input.ServiceName) 73 | assert.Equal(qualifier, *input.Qualifier) 74 | assert.Equal(functionName, *input.FunctionName) 75 | assert.Equal(fmt.Sprintf(onDemandConfigWithQualifierPath, pathEscape(serviceName), pathEscape(qualifier), pathEscape(functionName)), input.GetPath()) 76 | 77 | err := input.Validate() 78 | assert.Nil(err) 79 | } 80 | 81 | func (s *OnDemandConfigStructsTestSuite) TestGetOnDemandConfig_EmptyParam() { 82 | assert := s.Require() 83 | 84 | input := NewGetOnDemandConfigInput("", qualifier, functionName) 85 | err := input.Validate() 86 | assert.Nil(err) 87 | 88 | input = NewGetOnDemandConfigInput(serviceName, "", functionName) 89 | err = input.Validate() 90 | assert.Nil(err) 91 | 92 | input = NewGetOnDemandConfigInput(serviceName, qualifier, "") 93 | err = input.Validate() 94 | assert.Nil(err) 95 | } 96 | 97 | func (s *OnDemandConfigStructsTestSuite) TestDeleteOnDemandConfig_Success() { 98 | assert := s.Require() 99 | 100 | input := NewDeleteOnDemandConfigInput(serviceName, qualifier, functionName) 101 | assert.NotNil(input) 102 | assert.Equal(serviceName, *input.ServiceName) 103 | assert.Equal(qualifier, *input.Qualifier) 104 | assert.Equal(functionName, *input.FunctionName) 105 | assert.Equal(fmt.Sprintf(onDemandConfigWithQualifierPath, pathEscape(serviceName), pathEscape(qualifier), pathEscape(functionName)), input.GetPath()) 106 | assert.Nil(input.IfMatch) 107 | 108 | input.WithIfMatch(ifMatch) 109 | assert.NotNil(input.IfMatch) 110 | assert.Equal(ifMatch, *input.IfMatch) 111 | 112 | err := input.Validate() 113 | assert.Nil(err) 114 | } 115 | 116 | func (s *OnDemandConfigStructsTestSuite) TestDeleteOnDemandConfig_EmptyParams() { 117 | assert := s.Require() 118 | 119 | input := NewDeleteOnDemandConfigInput("", qualifier, functionName) 120 | err := input.Validate() 121 | assert.Nil(err) 122 | 123 | input = NewDeleteOnDemandConfigInput(serviceName, "", functionName) 124 | err = input.Validate() 125 | assert.Nil(err) 126 | 127 | input = NewDeleteOnDemandConfigInput(serviceName, qualifier, "") 128 | err = input.Validate() 129 | assert.Nil(err) 130 | } 131 | 132 | func (s *OnDemandConfigStructsTestSuite) TestListOnDemandConfigs_Success() { 133 | assert := s.Require() 134 | 135 | limit := 100 136 | prefix := "prefix" 137 | nextToken := "nextToken" 138 | startKey := "startKey" 139 | 140 | input := NewListOnDemandConfigsInput().WithPrefix(prefix).WithLimit(limit).WithNextToken(nextToken).WithStartKey(startKey) 141 | assert.NotNil(input) 142 | assert.Equal(limit, input.Limit) 143 | assert.Equal(fmt.Sprintf("%d", input.Limit), input.GetQueryParams().Get("limit")) 144 | assert.Equal(prefix, input.GetQueryParams().Get("prefix")) 145 | assert.Equal(nextToken, input.GetQueryParams().Get("nextToken")) 146 | assert.Equal(startKey, input.GetQueryParams().Get("startKey")) 147 | 148 | assert.Equal(onDemandConfigPath, input.GetPath()) 149 | 150 | expectedValues := map[string][]string{ 151 | "limit": {"100"}, 152 | "prefix": {"prefix"}, 153 | "nextToken": {"nextToken"}, 154 | "startKey": {"startKey"}, 155 | } 156 | values := input.GetQueryParams() 157 | assert.Equal(url.Values(expectedValues), values) 158 | 159 | err := input.Validate() 160 | assert.Nil(err) 161 | } 162 | 163 | func (s *OnDemandConfigStructsTestSuite) TestListOnDemandConfigs_InvalidLimit() { 164 | assert := s.Require() 165 | 166 | input := NewListOnDemandConfigsInput() 167 | input.WithLimit(-1) 168 | err := input.Validate() 169 | assert.Nil(err) 170 | } 171 | -------------------------------------------------------------------------------- /option.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | 7 | "gopkg.in/resty.v1" 8 | ) 9 | 10 | // ClientOption : defines client options type 11 | type ClientOption func(*Client) 12 | 13 | // WithTimeout : set request timeout in second 14 | func WithTimeout(t uint) ClientOption { 15 | return func(c *Client) { 16 | c.Connect.Timeout = t 17 | resty.SetTimeout(time.Duration(t) * time.Second) 18 | } 19 | } 20 | 21 | // WithTransport : overrides default http.Transport with customized transport 22 | func WithTransport(ts *http.Transport) ClientOption { 23 | return func(c *Client) { 24 | if ts != nil { 25 | resty.SetTransport(ts) 26 | } 27 | } 28 | } 29 | 30 | // WithSecurityToken : sets the STS security token 31 | func WithSecurityToken(token string) ClientOption { 32 | return func(c *Client) { c.Config.SecurityToken = token } 33 | } 34 | 35 | // WithAccountID sets the account id in header, this enables accessing 36 | // FC using IP address: 37 | // 38 | // client, _ := fc.NewClient("127.0.0.1", "api-version", "id", "key", 39 | // fc.WithAccountID("1234776887")) 40 | func WithAccountID(aid string) ClientOption { 41 | return func(c *Client) { c.Config.AccountID = aid } 42 | } 43 | 44 | // WithRetryCount : config the retry count for resty 45 | func WithRetryCount(count int) ClientOption { 46 | return func(c *Client) { 47 | resty.SetRetryCount(count) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /oss_temp_token.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "net/http" 5 | "net/url" 6 | ) 7 | 8 | // Credentials defines the returned credential 9 | type Credentials struct { 10 | AccessKeyID string `json:"AccessKeyId"` 11 | AccessKeySecret string `json:"AccessKeySecret"` 12 | Expiration string `json:"Expiration"` 13 | SecurityToken string `json:"SecurityToken"` 14 | } 15 | 16 | // GetTempBucketTokenOutput ... 17 | type GetTempBucketTokenOutput struct { 18 | Header http.Header `json:"header"` 19 | Credentials Credentials `json:"credentials"` 20 | OssRegion string `json:"ossRegion"` 21 | OssBucket string `json:"ossBucket"` 22 | ObjectName string `json:"objectName"` 23 | } 24 | 25 | // GetTempBucketTokenInput is empty 26 | type GetTempBucketTokenInput struct{} 27 | 28 | func (i GetTempBucketTokenInput) GetQueryParams() url.Values { 29 | return make(url.Values) 30 | } 31 | 32 | func (i GetTempBucketTokenInput) GetPath() string { 33 | return "/tempBucketToken" 34 | } 35 | 36 | func (i GetTempBucketTokenInput) GetHeaders() Header { 37 | return make(Header) 38 | } 39 | 40 | func (i GetTempBucketTokenInput) GetPayload() interface{} { 41 | return nil 42 | } 43 | 44 | func (i GetTempBucketTokenInput) Validate() error { 45 | return nil 46 | } 47 | -------------------------------------------------------------------------------- /provision_config.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | "strconv" 9 | ) 10 | 11 | type provisionTarget struct { 12 | Resource *string `json:"resource"` 13 | Target *int64 `json:"target"` 14 | } 15 | 16 | type provisionConfig struct { 17 | Resource *string `json:"resource"` 18 | Target *int64 `json:"target"` 19 | Current *int64 `json:"current"` 20 | } 21 | 22 | type PutProvisionConfigObject struct { 23 | Target *int64 `json:"target"` 24 | } 25 | 26 | type PutProvisionConfigInput struct { 27 | PutProvisionConfigObject 28 | ServiceName *string `json:"serviceName"` 29 | Qualifier *string `json:"qualifier"` 30 | FunctionName *string `json:"functionName"` 31 | IfMatch *string 32 | } 33 | 34 | func NewPutProvisionConfigInput(serviceName, qualifier, functionName string) *PutProvisionConfigInput { 35 | return &PutProvisionConfigInput{ 36 | ServiceName: &serviceName, 37 | Qualifier: &qualifier, 38 | FunctionName: &functionName, 39 | } 40 | } 41 | 42 | func (i *PutProvisionConfigInput) WithTarget(target int64) *PutProvisionConfigInput { 43 | i.Target = &target 44 | return i 45 | } 46 | 47 | func (i *PutProvisionConfigInput) WithIfMatch(ifMatch string) *PutProvisionConfigInput { 48 | i.IfMatch = &ifMatch 49 | return i 50 | } 51 | 52 | func (i *PutProvisionConfigInput) GetPath() string { 53 | return fmt.Sprintf(provisionConfigWithQualifierPath, pathEscape(*i.ServiceName), pathEscape(*i.Qualifier), pathEscape(*i.FunctionName)) 54 | } 55 | 56 | func (i *PutProvisionConfigInput) GetHeaders() Header { 57 | header := make(Header) 58 | if i.IfMatch != nil { 59 | header[ifMatch] = *i.IfMatch 60 | } 61 | return header 62 | } 63 | 64 | func (i *PutProvisionConfigInput) GetPayload() interface{} { 65 | return i.PutProvisionConfigObject 66 | } 67 | 68 | func (i *PutProvisionConfigInput) GetQueryParams() url.Values { 69 | return url.Values{} 70 | } 71 | 72 | func (i *PutProvisionConfigInput) Validate() error { 73 | if IsBlank(i.ServiceName) { 74 | return fmt.Errorf("Service name is required but not provided") 75 | } 76 | if IsBlank(i.Qualifier) { 77 | return fmt.Errorf("Qualifier is required but not provided") 78 | } 79 | if IsBlank(i.FunctionName) { 80 | return fmt.Errorf("Function name is required but not provided") 81 | } 82 | return nil 83 | } 84 | 85 | type PutProvisionConfigOutput struct { 86 | Header http.Header 87 | provisionTarget 88 | } 89 | 90 | func (o PutProvisionConfigOutput) String() string { 91 | b, err := json.MarshalIndent(o, "", printIndent) 92 | if err != nil { 93 | return "" 94 | } 95 | return string(b) 96 | } 97 | 98 | func (o PutProvisionConfigOutput) GetRequestID() string { 99 | return GetRequestID(o.Header) 100 | } 101 | 102 | func (o PutProvisionConfigOutput) GetEtag() string { 103 | return GetEtag(o.Header) 104 | } 105 | 106 | type GetProvisionConfigInput struct { 107 | ServiceName *string `json:"serviceName"` 108 | Qualifier *string `json:"qualifier"` 109 | FunctionName *string `json:"functionName"` 110 | } 111 | 112 | func NewGetProvisionConfigInput(serviceName, qualifier, functionName string) *GetProvisionConfigInput { 113 | return &GetProvisionConfigInput{ 114 | ServiceName: &serviceName, 115 | Qualifier: &qualifier, 116 | FunctionName: &functionName, 117 | } 118 | } 119 | 120 | func (i *GetProvisionConfigInput) GetPath() string { 121 | return fmt.Sprintf(provisionConfigWithQualifierPath, pathEscape(*i.ServiceName), pathEscape(*i.Qualifier), pathEscape(*i.FunctionName)) 122 | } 123 | 124 | func (i *GetProvisionConfigInput) GetHeaders() Header { 125 | return make(Header, 0) 126 | } 127 | 128 | func (i *GetProvisionConfigInput) GetPayload() interface{} { 129 | return nil 130 | } 131 | 132 | func (i *GetProvisionConfigInput) GetQueryParams() url.Values { 133 | return url.Values{} 134 | } 135 | 136 | func (i *GetProvisionConfigInput) Validate() error { 137 | if IsBlank(i.ServiceName) { 138 | return fmt.Errorf("Service name is required but not provided") 139 | } 140 | if IsBlank(i.Qualifier) { 141 | return fmt.Errorf("Qualifier is required but not provided") 142 | } 143 | if IsBlank(i.FunctionName) { 144 | return fmt.Errorf("Function name is required but not provided") 145 | } 146 | return nil 147 | } 148 | 149 | type GetProvisionConfigOutput struct { 150 | Header http.Header 151 | provisionConfig 152 | } 153 | 154 | func (o GetProvisionConfigOutput) String() string { 155 | b, err := json.MarshalIndent(o, "", printIndent) 156 | if err != nil { 157 | return "" 158 | } 159 | return string(b) 160 | } 161 | 162 | func (o GetProvisionConfigOutput) GetRequestID() string { 163 | return GetRequestID(o.Header) 164 | } 165 | 166 | func (o GetProvisionConfigOutput) GetEtag() string { 167 | return GetEtag(o.Header) 168 | } 169 | 170 | type ListProvisionConfigsInput struct { 171 | ServiceName *string `json:"serviceName"` 172 | Qualifier *string `json:"qualifier"` 173 | NextToken *string `json:"nextToken"` 174 | Limit *int32 `json:"limit"` 175 | } 176 | 177 | func NewListProvisionConfigsInput() *ListProvisionConfigsInput { 178 | return &ListProvisionConfigsInput{} 179 | } 180 | 181 | func (i *ListProvisionConfigsInput) WithServiceName(serviceName string) *ListProvisionConfigsInput { 182 | i.ServiceName = &serviceName 183 | return i 184 | } 185 | 186 | func (i *ListProvisionConfigsInput) WithQualifier(qualifier string) *ListProvisionConfigsInput { 187 | i.Qualifier = &qualifier 188 | return i 189 | } 190 | 191 | func (i *ListProvisionConfigsInput) WithNextToken(nextToken string) *ListProvisionConfigsInput { 192 | i.NextToken = &nextToken 193 | return i 194 | } 195 | 196 | func (i *ListProvisionConfigsInput) WithLimit(limit int32) *ListProvisionConfigsInput { 197 | i.Limit = &limit 198 | return i 199 | } 200 | 201 | func (i *ListProvisionConfigsInput) GetQueryParams() url.Values { 202 | out := url.Values{} 203 | if i.ServiceName != nil { 204 | out.Set("serviceName", *i.ServiceName) 205 | } 206 | 207 | if i.Qualifier != nil { 208 | out.Set("qualifier", *i.Qualifier) 209 | } 210 | 211 | if i.NextToken != nil { 212 | out.Set("nextToken", *i.NextToken) 213 | } 214 | 215 | if i.Limit != nil { 216 | out.Set("limit", strconv.FormatInt(int64(*i.Limit), 10)) 217 | } 218 | 219 | return out 220 | } 221 | 222 | func (i *ListProvisionConfigsInput) GetPath() string { 223 | return provisionConfigPath 224 | } 225 | 226 | func (i *ListProvisionConfigsInput) GetHeaders() Header { 227 | return make(Header, 0) 228 | } 229 | 230 | func (i *ListProvisionConfigsInput) GetPayload() interface{} { 231 | return nil 232 | } 233 | 234 | func (i *ListProvisionConfigsInput) Validate() error { 235 | if IsBlank(i.ServiceName) && !IsBlank(i.Qualifier) { 236 | return fmt.Errorf("Service name is required if qualifier is provided") 237 | } 238 | return nil 239 | } 240 | 241 | type ListProvisionConfigsOutput struct { 242 | Header http.Header 243 | ProvisionConfigs []*provisionConfig `json:"provisionConfigs"` 244 | NextToken *string `json:"nextToken,omitempty"` 245 | } 246 | 247 | func (o ListProvisionConfigsOutput) String() string { 248 | b, err := json.MarshalIndent(o, "", printIndent) 249 | if err != nil { 250 | return "" 251 | } 252 | return string(b) 253 | } 254 | 255 | func (o ListProvisionConfigsOutput) GetRequestID() string { 256 | return GetRequestID(o.Header) 257 | } 258 | -------------------------------------------------------------------------------- /provision_config_test.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/suite" 8 | ) 9 | 10 | var ( 11 | serviceName = "sn" 12 | qualifier = "q" 13 | functionName = "fn" 14 | target = int64(10) 15 | ) 16 | 17 | func TestProvisionConfigStruct(t *testing.T) { 18 | suite.Run(t, new(ProvisionConfigStructsTestSuite)) 19 | } 20 | 21 | type ProvisionConfigStructsTestSuite struct { 22 | suite.Suite 23 | } 24 | 25 | func (s *ProvisionConfigStructsTestSuite) TestPutProvisionConfig_Success() { 26 | assert := s.Require() 27 | 28 | input := NewPutProvisionConfigInput(serviceName, qualifier, functionName) 29 | assert.NotNil(input) 30 | assert.Equal(serviceName, *input.ServiceName) 31 | assert.Equal(qualifier, *input.Qualifier) 32 | assert.Equal(functionName, *input.FunctionName) 33 | assert.NotNil(input.PutProvisionConfigObject) 34 | assert.Nil(input.Target) 35 | assert.Nil(input.IfMatch) 36 | assert.Equal(fmt.Sprintf(provisionConfigWithQualifierPath, pathEscape(serviceName), pathEscape(qualifier), pathEscape(functionName)), input.GetPath()) 37 | assert.Equal(input.PutProvisionConfigObject, input.GetPayload()) 38 | 39 | input.WithTarget(target) 40 | assert.NotNil(input.PutProvisionConfigObject) 41 | assert.NotNil(input.Target) 42 | assert.Equal(target, *input.Target) 43 | assert.Equal(input.PutProvisionConfigObject, input.GetPayload()) 44 | 45 | input.WithIfMatch(ifMatch) 46 | assert.NotNil(input.IfMatch) 47 | assert.Equal(ifMatch, *input.IfMatch) 48 | 49 | err := input.Validate() 50 | assert.Nil(err) 51 | } 52 | 53 | func (s *ProvisionConfigStructsTestSuite) TestPutProvisionConfig_Fail() { 54 | assert := s.Require() 55 | 56 | input := NewPutProvisionConfigInput("", qualifier, functionName) 57 | err := input.Validate() 58 | assert.NotNil(err) 59 | assert.Equal("Service name is required but not provided", err.Error()) 60 | 61 | input = NewPutProvisionConfigInput(serviceName, "", functionName) 62 | err = input.Validate() 63 | assert.NotNil(err) 64 | assert.Equal("Qualifier is required but not provided", err.Error()) 65 | 66 | input = NewPutProvisionConfigInput(serviceName, qualifier, "") 67 | err = input.Validate() 68 | assert.NotNil(err) 69 | assert.Equal("Function name is required but not provided", err.Error()) 70 | } 71 | 72 | func (s *ProvisionConfigStructsTestSuite) TestGetProvisionConfig_Success() { 73 | assert := s.Require() 74 | 75 | input := NewGetProvisionConfigInput(serviceName, qualifier, functionName) 76 | assert.NotNil(input) 77 | assert.Equal(serviceName, *input.ServiceName) 78 | assert.Equal(qualifier, *input.Qualifier) 79 | assert.Equal(functionName, *input.FunctionName) 80 | assert.Equal(fmt.Sprintf(provisionConfigWithQualifierPath, pathEscape(serviceName), pathEscape(qualifier), pathEscape(functionName)), input.GetPath()) 81 | 82 | err := input.Validate() 83 | assert.Nil(err) 84 | } 85 | 86 | func (s *ProvisionConfigStructsTestSuite) TestGetProvisionConfig_Fail() { 87 | assert := s.Require() 88 | 89 | input := NewGetProvisionConfigInput("", qualifier, functionName) 90 | err := input.Validate() 91 | assert.NotNil(err) 92 | assert.Equal("Service name is required but not provided", err.Error()) 93 | 94 | input = NewGetProvisionConfigInput(serviceName, "", functionName) 95 | err = input.Validate() 96 | assert.NotNil(err) 97 | assert.Equal("Qualifier is required but not provided", err.Error()) 98 | 99 | input = NewGetProvisionConfigInput(serviceName, qualifier, "") 100 | err = input.Validate() 101 | assert.NotNil(err) 102 | assert.Equal("Function name is required but not provided", err.Error()) 103 | } 104 | 105 | func (s *ProvisionConfigStructsTestSuite) TestListProvisionConfigs_Success() { 106 | assert := s.Require() 107 | 108 | input := NewListProvisionConfigsInput() 109 | assert.NotNil(input) 110 | assert.Equal(provisionConfigPath, input.GetPath()) 111 | 112 | input.WithServiceName(serviceName) 113 | assert.Equal(serviceName, *input.ServiceName) 114 | err := input.Validate() 115 | assert.Nil(err) 116 | 117 | input.WithQualifier(qualifier) 118 | assert.Equal(qualifier, *input.Qualifier) 119 | err = input.Validate() 120 | assert.Nil(err) 121 | 122 | input.WithNextToken("does-not-matter") 123 | assert.Equal("does-not-matter", *input.NextToken) 124 | 125 | input.WithLimit(int32(2)) 126 | assert.Equal(int32(2), *input.Limit) 127 | 128 | params := input.GetQueryParams() 129 | assert.Equal(serviceName, params.Get("serviceName")) 130 | assert.Equal(qualifier, params.Get("qualifier")) 131 | assert.Equal("does-not-matter", params.Get("nextToken")) 132 | assert.Equal("2", params.Get("limit")) 133 | } 134 | 135 | func (s *ProvisionConfigStructsTestSuite) TestListProvisionConfigs_Fail() { 136 | assert := s.Require() 137 | 138 | input := NewListProvisionConfigsInput() 139 | input.WithQualifier(qualifier) 140 | assert.Equal(qualifier, *input.Qualifier) 141 | err := input.Validate() 142 | assert.NotNil(err) 143 | assert.Equal("Service name is required if qualifier is provided", err.Error()) 144 | } 145 | -------------------------------------------------------------------------------- /reserved_capacity.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | "net/url" 7 | "strconv" 8 | ) 9 | 10 | const ( 11 | reservedCapacitiesPath = "/reservedCapacities" 12 | ) 13 | 14 | type reservedCapacityMetadata struct { 15 | InstanceID *string `json:"instanceId"` 16 | CU *int64 `json:"cu"` 17 | Deadline *string `json:"deadline"` 18 | CreatedTime *string `json:"createdTime"` 19 | LastModifiedTime *string `json:"lastModifiedTime"` 20 | IsRefunded *string `json:"isRefunded"` 21 | } 22 | 23 | // ListReservedCapacitiesOutput : ... 24 | type ListReservedCapacitiesOutput struct { 25 | Header http.Header 26 | ReservedCapacities []*reservedCapacityMetadata `json:"reservedCapacities"` 27 | NextToken *string `json:"nextToken,omitempty"` 28 | } 29 | 30 | // ListReservedCapacitiesInput : ... 31 | type ListReservedCapacitiesInput struct { 32 | Query 33 | } 34 | 35 | // NewListReservedCapacitiesInput : ... 36 | func NewListReservedCapacitiesInput() *ListReservedCapacitiesInput { 37 | return &ListReservedCapacitiesInput{} 38 | } 39 | 40 | func (i *ListReservedCapacitiesInput) WithNextToken(nextToken string) *ListReservedCapacitiesInput { 41 | i.NextToken = &nextToken 42 | return i 43 | } 44 | 45 | func (i *ListReservedCapacitiesInput) WithLimit(limit int32) *ListReservedCapacitiesInput { 46 | i.Limit = &limit 47 | return i 48 | } 49 | 50 | func (i *ListReservedCapacitiesInput) GetQueryParams() url.Values { 51 | out := url.Values{} 52 | if i.NextToken != nil { 53 | out.Set("nextToken", *i.NextToken) 54 | } 55 | 56 | if i.Limit != nil { 57 | out.Set("limit", strconv.FormatInt(int64(*i.Limit), 10)) 58 | } 59 | 60 | return out 61 | } 62 | 63 | func (i *ListReservedCapacitiesInput) GetPath() string { 64 | return reservedCapacitiesPath 65 | } 66 | 67 | func (i *ListReservedCapacitiesInput) GetHeaders() Header { 68 | return make(Header, 0) 69 | } 70 | 71 | func (i *ListReservedCapacitiesInput) GetPayload() interface{} { 72 | return nil 73 | } 74 | 75 | func (i *ListReservedCapacitiesInput) Validate() error { 76 | return nil 77 | } 78 | 79 | func (o ListReservedCapacitiesOutput) String() string { 80 | b, err := json.MarshalIndent(o, "", printIndent) 81 | if err != nil { 82 | return "" 83 | } 84 | return string(b) 85 | } 86 | 87 | func (o ListReservedCapacitiesOutput) GetRequestID() string { 88 | return GetRequestID(o.Header) 89 | } 90 | -------------------------------------------------------------------------------- /reserved_capacity_test.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "github.com/stretchr/testify/suite" 5 | 6 | "testing" 7 | ) 8 | 9 | func TestReservedCapacityStructs(t *testing.T) { 10 | suite.Run(t, new(ReservedCapacityStructsTestSuite)) 11 | } 12 | 13 | type ReservedCapacityStructsTestSuite struct { 14 | suite.Suite 15 | } 16 | 17 | func (s *ReservedCapacityStructsTestSuite) TestListReservedCapacities() { 18 | assert := s.Require() 19 | input := NewListReservedCapacitiesInput() 20 | assert.NotNil(input) 21 | 22 | input.WithNextToken("nextToken") 23 | assert.NotNil(input.NextToken) 24 | assert.Equal("nextToken", *input.NextToken) 25 | 26 | input.WithLimit(int32(10)) 27 | assert.NotNil(input.Limit) 28 | assert.Equal(int32(10), *input.Limit) 29 | } -------------------------------------------------------------------------------- /samples/glide.lock: -------------------------------------------------------------------------------- 1 | hash: fdd43ad59a285ff07439be4314c17f424b5487b74d6449feb873aba25132dab2 2 | updated: 2021-11-23T14:44:33.641688+08:00 3 | imports: 4 | - name: github.com/aliyun/fc-go-sdk 5 | version: 4855d486e2f8785539fb2ef5e617a0f7d68b7bfe 6 | - name: github.com/gorilla/websocket 7 | version: c3dd95aea9779669bb3daafbd84ee0530c8ce1c1 8 | - name: github.com/stretchr/testify 9 | version: f6abca593680b2315d2075e0f5e2a9751e3f431a 10 | subpackages: 11 | - assert 12 | - mock 13 | - require 14 | - suite 15 | - name: golang.org/x/net 16 | version: c44066c5c816ec500d459a2a324a753f78531ae0 17 | subpackages: 18 | - publicsuffix 19 | - name: gopkg.in/resty.v1 20 | version: 03c09fa32a21b7b27b8dbb3877826c1ab3d2daa2 21 | testImports: [] 22 | -------------------------------------------------------------------------------- /samples/hello_world.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliyun/fc-go-sdk/3a1b2ede1e1e9ead26a9979f294588e8d39263a9/samples/hello_world.zip -------------------------------------------------------------------------------- /samples/instance_exec.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | "time" 8 | 9 | fc "github.com/aliyun/fc-go-sdk" 10 | ) 11 | 12 | const ( 13 | ACCOUNT_ID = "" 14 | serviceName = "" 15 | functionName = "" 16 | ) 17 | 18 | func main() { 19 | client, _ := fc.NewClient( 20 | os.Getenv("ENDPOINT"), "2016-08-15", os.Getenv("ACCESS_KEY_ID"), os.Getenv("ACCESS_KEY_SECRET"), 21 | fc.WithTransport(&http.Transport{MaxIdleConnsPerHost: 100}), 22 | ) 23 | client.Config.AccountID = ACCOUNT_ID 24 | 25 | instances, err := client.ListInstances(fc.NewListInstancesInput(serviceName, functionName)) 26 | if err != nil { 27 | fmt.Printf("List instance failed: %s\n", err) 28 | return 29 | } 30 | instanceID := "" 31 | for _, ins := range instances.Instances { 32 | instanceID = ins.InstanceID 33 | fmt.Println(ins.InstanceID, ins.VersionID) 34 | } 35 | 36 | // Exec command without -it, stdin=false, tty=false 37 | if instanceID != "" { 38 | command := []string{"pwd"} 39 | _, err := client.InstanceExec( 40 | fc.NewInstanceExecInput( 41 | serviceName, functionName, instanceID, command, 42 | ).WithStdin(false). 43 | WithStdout(true). 44 | WithStderr(true). 45 | WithTTY(false). 46 | WithIdleTimeout(120). 47 | OnStdout(func(data []byte) { 48 | fmt.Printf("STDOUT: %s\n", data) 49 | }).OnStderr(func(data []byte) { 50 | fmt.Printf("STDERR: %s\n", data) 51 | }), 52 | ) 53 | if err != nil { 54 | fmt.Printf("%v", err) 55 | return 56 | } 57 | time.Sleep(time.Second * 1) 58 | } 59 | 60 | // Exec command with stdout, stderr in different stream 61 | if instanceID != "" { 62 | //command := []string{"pwd"} 63 | command := []string{"bash", "-c", "echo stdout-text && echo stderr-text 1>&2;"} 64 | _, err := client.InstanceExec( 65 | fc.NewInstanceExecInput( 66 | serviceName, functionName, instanceID, command, 67 | ).WithStdin(false). 68 | WithStdout(true). 69 | WithStderr(true). 70 | WithTTY(false). 71 | WithIdleTimeout(120). 72 | OnStdout(func(data []byte) { 73 | fmt.Printf("STDOUT: %s\n", data) 74 | }).OnStderr(func(data []byte) { 75 | fmt.Printf("STDERR: %s\n", data) 76 | }), 77 | ) 78 | if err != nil { 79 | fmt.Printf("%v", err) 80 | return 81 | } 82 | time.Sleep(time.Second * 1) 83 | } 84 | 85 | 86 | // Exec command with -it : stdin=true, tty=true 87 | if instanceID != "" { 88 | command := []string{"/bin/bash"} 89 | exec, err := client.InstanceExec( 90 | fc.NewInstanceExecInput( 91 | serviceName, functionName, instanceID, command, 92 | ).WithStdin(true). 93 | WithStdout(true). 94 | WithStderr(false). 95 | WithTTY(true). 96 | WithIdleTimeout(120). 97 | OnStdout( 98 | func(data []byte) { fmt.Printf("STDOUT: %s\n", data) }). 99 | OnStderr( 100 | func(data []byte) { fmt.Printf("STDERR: %s\n", data) })) 101 | if err != nil { 102 | fmt.Printf("%v", err) 103 | return 104 | } 105 | go func() { 106 | fmt.Println("error:", <-exec.ErrorChannel()) 107 | }() 108 | if err := exec.WriteStdin([]byte("ls\r")); err != nil { 109 | fmt.Println("error", err) 110 | } 111 | time.Sleep(time.Second * 1) 112 | if err := exec.WriteStdin([]byte("ls --color\r")); err != nil { 113 | fmt.Println("error", err) 114 | } 115 | time.Sleep(time.Second * 1) 116 | 117 | if err := exec.WriteStdin([]byte("exit\r")); err != nil { 118 | fmt.Println("error", err) 119 | } 120 | time.Sleep(time.Second * 1) 121 | } 122 | } -------------------------------------------------------------------------------- /samples/layer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/aliyun/fc-go-sdk" 10 | ) 11 | 12 | func main() { 13 | client, _ := fc.NewClient( 14 | os.Getenv("ENDPOINT"), "2016-08-15", 15 | os.Getenv("ACCESS_KEY_ID"), 16 | os.Getenv("ACCESS_KEY_SECRET"), 17 | fc.WithTransport(&http.Transport{MaxIdleConnsPerHost: 100})) 18 | 19 | // 层名称 20 | layerName := "test-layer" 21 | // 准备 Zip 格式的层文件 22 | layZipFile := "./hello_world.zip" 23 | // 指定兼容的运行时环境 24 | compatibleRuntime := []string{"python3", "nodejs12"} 25 | 26 | // 1. 发布层版本 27 | fmt.Println("Publish layer versions") 28 | data, err := ioutil.ReadFile(layZipFile) 29 | if err != nil { 30 | fmt.Fprintln(os.Stderr, err) 31 | return 32 | } 33 | publishLayerVersionOutput, err := client.PublishLayerVersion(fc.NewPublishLayerVersionInput(). 34 | WithLayerName(layerName). 35 | WithCode(fc.NewCode().WithZipFile(data)). 36 | WithCompatibleRuntime(compatibleRuntime). 37 | WithDescription("my layer"), 38 | ) 39 | if err != nil { 40 | fmt.Fprintln(os.Stderr, err) 41 | } else { 42 | fmt.Printf("PublishLayerVersion response: %+v \n\n", publishLayerVersionOutput) 43 | } 44 | 45 | // 2. 查询指定层版本信息 46 | fmt.Printf("Get the layer of version %d\n", publishLayerVersionOutput.Layer.Version) 47 | getLayerVersionOutput, err := client.GetLayerVersion( 48 | fc.NewGetLayerVersionInput(layerName, publishLayerVersionOutput.Layer.Version)) 49 | if err != nil { 50 | fmt.Fprintln(os.Stderr, err) 51 | } else { 52 | fmt.Printf("GetLayerVersion response: %+v \n\n", getLayerVersionOutput.Layer) 53 | } 54 | 55 | // 3. 获取层列表 56 | fmt.Println("List layers") 57 | nextToken := "" 58 | layers := []*fc.Layer{} 59 | for { 60 | listLayersOutput, err := client.ListLayers( 61 | fc.NewListLayersInput(). 62 | WithLimit(100). 63 | WithNextToken(nextToken)) 64 | if err != nil { 65 | fmt.Fprintln(os.Stderr, err) 66 | break 67 | } 68 | if len(listLayersOutput.Layers) != 0 { 69 | layers = append(layers, listLayersOutput.Layers...) 70 | } 71 | if listLayersOutput.NextToken == nil { 72 | break 73 | } 74 | nextToken = *listLayersOutput.NextToken 75 | 76 | } 77 | fmt.Println("ListLayers response:") 78 | for _, layer := range layers { 79 | fmt.Printf("- layerName: %s, layerMaxVersion: %d\n", layer.LayerName, layer.Version) 80 | } 81 | 82 | // 4. 获取层版本列表 83 | fmt.Println("List layer versions") 84 | // 层的起始版本,默认从1开始 85 | startVersion := int32(1) 86 | fmt.Println("ListLayerVersions response:") 87 | layerVersions := []*fc.Layer{} 88 | for { 89 | listLayerVersionsOutput, err := client.ListLayerVersions( 90 | fc.NewListLayerVersionsInput(layerName, startVersion). 91 | WithLimit(100)) 92 | if err != nil { 93 | if err, ok := err.(*fc.ServiceError); ok && 94 | err.HTTPStatus == http.StatusNotFound { 95 | break 96 | } 97 | fmt.Fprintln(os.Stderr, err) 98 | break 99 | } 100 | if len(listLayerVersionsOutput.Layers) > 0 { 101 | layerVersions = append(layerVersions, listLayerVersionsOutput.Layers...) 102 | } 103 | if listLayerVersionsOutput.NextVersion == nil || 104 | *listLayerVersionsOutput.NextVersion == 0 { 105 | break 106 | } 107 | startVersion = *listLayerVersionsOutput.NextVersion 108 | } 109 | 110 | for _, layer := range layerVersions { 111 | fmt.Printf("- layerName: %s, layerVersion: %d\n", layer.LayerName, layer.Version) 112 | } 113 | 114 | // 5. 删除层版本 115 | fmt.Printf("Delete the layer of version %d \n", publishLayerVersionOutput.Layer.Version) 116 | deleteLayerVersionOutput, err := client.DeleteLayerVersion( 117 | fc.NewDeleteLayerVersionInput(layerName, publishLayerVersionOutput.Layer.Version)) 118 | if err != nil { 119 | fmt.Fprintln(os.Stderr, err) 120 | } else { 121 | fmt.Printf("DeleteLayerVersion response: %+v \n\n", deleteLayerVersionOutput) 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /samples/sample.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "time" 7 | 8 | "net/http" 9 | 10 | "github.com/aliyun/fc-go-sdk" 11 | ) 12 | 13 | func main() { 14 | serviceName := "service555" 15 | client, _ := fc.NewClient(os.Getenv("ENDPOINT"), "2016-08-15", os.Getenv("ACCESS_KEY_ID"), os.Getenv("ACCESS_KEY_SECRET"), 16 | fc.WithTransport(&http.Transport{MaxIdleConnsPerHost: 100})) 17 | 18 | fmt.Println("Creating service") 19 | createServiceOutput, err := client.CreateService(fc.NewCreateServiceInput(). 20 | WithServiceName(serviceName). 21 | WithDescription("this is a smoke test for go sdk")) 22 | if err != nil { 23 | fmt.Fprintln(os.Stderr, err) 24 | } 25 | if createServiceOutput != nil { 26 | fmt.Printf("CreateService response: %s \n", createServiceOutput) 27 | } 28 | 29 | // GetService 30 | fmt.Println("Getting service") 31 | getServiceOutput, err := client.GetService(fc.NewGetServiceInput(serviceName)) 32 | if err != nil { 33 | fmt.Fprintln(os.Stderr, err) 34 | } else { 35 | fmt.Printf("GetService response: %s \n", getServiceOutput) 36 | } 37 | 38 | // UpdateService 39 | fmt.Println("Updating service") 40 | updateServiceInput := fc.NewUpdateServiceInput(serviceName).WithDescription("new description") 41 | updateServiceOutput, err := client.UpdateService(updateServiceInput) 42 | if err != nil { 43 | fmt.Fprintln(os.Stderr, err) 44 | } else { 45 | fmt.Printf("UpdateService response: %s \n", updateServiceOutput) 46 | } 47 | 48 | // UpdateService with IfMatch 49 | fmt.Println("Updating service with IfMatch") 50 | updateServiceInput2 := fc.NewUpdateServiceInput(serviceName).WithDescription("new description2"). 51 | WithIfMatch(updateServiceOutput.Header.Get("ETag")) 52 | updateServiceOutput2, err := client.UpdateService(updateServiceInput2) 53 | if err != nil { 54 | fmt.Fprintln(os.Stderr, err) 55 | } else { 56 | fmt.Printf("UpdateService response: %s \n", updateServiceOutput2) 57 | } 58 | 59 | // UpdateService with wrong IfMatch 60 | fmt.Println("Updating service with wrong IfMatch") 61 | updateServiceInput3 := fc.NewUpdateServiceInput(serviceName).WithDescription("new description2"). 62 | WithIfMatch("1234") 63 | updateServiceOutput3, err := client.UpdateService(updateServiceInput3) 64 | if err != nil { 65 | fmt.Fprintln(os.Stderr, err) 66 | } else { 67 | fmt.Printf("UpdateService response: %s \n", updateServiceOutput3) 68 | } 69 | 70 | // ListServices 71 | fmt.Println("Listing services") 72 | listServicesOutput, err := client.ListServices(fc.NewListServicesInput().WithLimit(100)) 73 | if err != nil { 74 | fmt.Fprintln(os.Stderr, err) 75 | } else { 76 | fmt.Printf("ListServices response: %s \n", listServicesOutput) 77 | } 78 | 79 | // CreateFunction 80 | fmt.Println("Creating function1") 81 | createFunctionInput1 := fc.NewCreateFunctionInput(serviceName).WithFunctionName("testf1"). 82 | WithDescription("testf1"). 83 | WithHandler("hello.index").WithRuntime("nodejs6"). 84 | WithCode(fc.NewCode().WithFiles("hello_world.zip")). 85 | WithTimeout(5) 86 | createFunctionOutput, err := client.CreateFunction(createFunctionInput1) 87 | if err != nil { 88 | fmt.Fprintln(os.Stderr, err) 89 | } else { 90 | fmt.Printf("CreateFunction response1: %s \n", createFunctionOutput) 91 | } 92 | fmt.Println("Creating function2") 93 | createFunctionOutput2, err := client.CreateFunction(createFunctionInput1.WithFunctionName("testf2")) 94 | if err != nil { 95 | fmt.Fprintln(os.Stderr, err) 96 | } else { 97 | fmt.Printf("CreateFunction response2: %s \n", createFunctionOutput2) 98 | } 99 | 100 | // CreateFunction with initializer 101 | fmt.Println("Creating function3") 102 | createFunctionOutput3, err := client.CreateFunction(createFunctionInput1.WithFunctionName("testf3"). 103 | WithInitializer("init.index"). 104 | WithInitializationTimeout(5)) 105 | if err != nil { 106 | fmt.Fprintln(os.Stderr, err) 107 | } else { 108 | fmt.Printf("CreateFunction response3: %s \n", createFunctionOutput3) 109 | } 110 | 111 | // ListFunctions 112 | fmt.Println("Listing functions") 113 | listFunctionsOutput, err := client.ListFunctions(fc.NewListFunctionsInput(serviceName).WithPrefix("test")) 114 | if err != nil { 115 | fmt.Fprintln(os.Stderr, err) 116 | } else { 117 | fmt.Printf("ListFunctions response: %s \n", listFunctionsOutput) 118 | } 119 | 120 | // UpdateFunction 121 | fmt.Println("Updating function") 122 | updateFunctionOutput, err := client.UpdateFunction(fc.NewUpdateFunctionInput(serviceName, "testf1"). 123 | WithDescription("newdesc")) 124 | if err != nil { 125 | fmt.Fprintln(os.Stderr, err) 126 | } else { 127 | fmt.Printf("UpdateFunction response: %s \n", updateFunctionOutput) 128 | } 129 | 130 | updateFunctionOutput1, err := client.UpdateFunction(fc.NewUpdateFunctionInput(serviceName, "testf3"). 131 | WithInitializationTimeout(10)) 132 | if err != nil { 133 | fmt.Fprintln(os.Stderr, err) 134 | } else { 135 | fmt.Printf("UpdateFunction response: %s \n", updateFunctionOutput1) 136 | } 137 | 138 | // InvokeFunction 139 | fmt.Println("Invoking function, log type Tail") 140 | invokeInput := fc.NewInvokeFunctionInput(serviceName, "testf1").WithLogType("Tail") 141 | invokeOutput, err := client.InvokeFunction(invokeInput) 142 | if err != nil { 143 | fmt.Fprintln(os.Stderr, err) 144 | } else { 145 | fmt.Printf("InvokeFunction response: %s \n", invokeOutput) 146 | logResult, err := invokeOutput.GetLogResult() 147 | if err != nil { 148 | fmt.Printf("Failed to get LogResult due to %v\n", err) 149 | } else { 150 | fmt.Printf("Invoke function LogResult %s \n", logResult) 151 | } 152 | } 153 | 154 | // PublishServiceVersion 155 | fmt.Println("Publishing service version") 156 | publishServiceVersionInput := fc.NewPublishServiceVersionInput(serviceName) 157 | publishServiceVersionOutput, err := client.PublishServiceVersion(publishServiceVersionInput) 158 | if err != nil { 159 | fmt.Fprintln(os.Stderr, err) 160 | } else { 161 | fmt.Printf("PublishServiceVersion response: %s \n", publishServiceVersionOutput) 162 | } 163 | 164 | time.Sleep(time.Duration(1) * time.Second) 165 | 166 | // PublishServiceVersion with IfMatch 167 | fmt.Println("Publishing service version with IfMatch") 168 | publishServiceVersionInput2 := fc.NewPublishServiceVersionInput(serviceName). 169 | WithIfMatch(getServiceOutput.Header.Get("ETag")) 170 | publishServiceVersionOutput2, err := client.PublishServiceVersion(publishServiceVersionInput2) 171 | if err != nil { 172 | fmt.Fprintln(os.Stderr, err) 173 | } else { 174 | fmt.Printf("PublishServiceVersion response: %s \n", publishServiceVersionOutput2) 175 | } 176 | 177 | // PublishServiceVersion with wrong IfMatch 178 | fmt.Println("Publishing service with wrong IfMatch") 179 | publishServiceVersionInput3 := fc.NewPublishServiceVersionInput(serviceName). 180 | WithIfMatch("1234") 181 | publishServiceVersionOutput3, err := client.PublishServiceVersion(publishServiceVersionInput3) 182 | if err != nil { 183 | fmt.Fprintln(os.Stderr, err) 184 | } else { 185 | fmt.Printf("PublishServiceVersion response: %s \n", publishServiceVersionOutput3) 186 | } 187 | 188 | // ListServiceVersions 189 | fmt.Println("Listing service versions") 190 | listServiceVersionsOutput, err := client.ListServiceVersions(fc.NewListServiceVersionsInput(serviceName).WithLimit(10)) 191 | if err != nil { 192 | fmt.Fprintln(os.Stderr, err) 193 | } else { 194 | fmt.Printf("ListServiceVersions response: %s \n", listServiceVersionsOutput) 195 | } 196 | 197 | // GetService with qualifier 198 | fmt.Println("Getting service with qualifier") 199 | getServiceOutput2, err := client.GetService(fc.NewGetServiceInput(serviceName).WithQualifier(*publishServiceVersionOutput.VersionID)) 200 | if err != nil { 201 | fmt.Fprintln(os.Stderr, err) 202 | } else { 203 | fmt.Printf("GetService with qualifier response: %s \n", getServiceOutput2) 204 | } 205 | 206 | // CreateAlias 207 | aliasName := "alias" 208 | fmt.Println("Creating alias") 209 | createAliasOutput, err := client.CreateAlias(fc.NewCreateAliasInput(serviceName).WithAliasName(aliasName).WithVersionID(*publishServiceVersionOutput.VersionID)) 210 | if err != nil { 211 | fmt.Fprintln(os.Stderr, err) 212 | } else { 213 | fmt.Printf("CreateAlias response: %s \n", createAliasOutput) 214 | } 215 | 216 | // GetAlias 217 | fmt.Println("Getting alias") 218 | getAliasOutput, err := client.GetAlias(fc.NewGetAliasInput(serviceName, aliasName)) 219 | if err != nil { 220 | fmt.Fprintln(os.Stderr, err) 221 | } else { 222 | fmt.Printf("GetAlias response: %s \n", getAliasOutput) 223 | } 224 | 225 | // UpdateAlias 226 | fmt.Println("Updating alias") 227 | updateAliasOutput, err := client.UpdateAlias(fc.NewUpdateAliasInput(serviceName, aliasName).WithVersionID(*publishServiceVersionOutput.VersionID)) 228 | if err != nil { 229 | fmt.Fprintln(os.Stderr, err) 230 | } else { 231 | fmt.Printf("UpdateAlias response: %s \n", updateAliasOutput) 232 | } 233 | 234 | // ListAliases 235 | fmt.Println("Listing aliases") 236 | listAliasesOutput, err := client.ListAliases(fc.NewListAliasesInput(serviceName)) 237 | if err != nil { 238 | fmt.Fprintln(os.Stderr, err) 239 | } else { 240 | fmt.Printf("ListAliases response: %s \n", listAliasesOutput) 241 | } 242 | 243 | // PutProvisionConfig 244 | fmt.Println("Putting provision config") 245 | putProvisionConfigOutput, err := client.PutProvisionConfig( 246 | fc.NewPutProvisionConfigInput(serviceName, aliasName, "testf1"). 247 | WithTarget(int64(10))) 248 | if err != nil { 249 | fmt.Fprintln(os.Stderr, err) 250 | } else { 251 | fmt.Printf("PutProvisionConfig response: %s \n", putProvisionConfigOutput) 252 | } 253 | 254 | // GetProvisionConfig 255 | fmt.Println("Getting provision config") 256 | getProvisionConfigOutput, err := client.GetProvisionConfig( 257 | fc.NewGetProvisionConfigInput(serviceName, aliasName, "testf1")) 258 | if err != nil { 259 | fmt.Fprintln(os.Stderr, err) 260 | } else { 261 | fmt.Printf("GetProvisionConfig response: %s \n", getProvisionConfigOutput) 262 | } 263 | 264 | // ListProvisionConfigs 265 | fmt.Println("Listing provision configs") 266 | listProvisionConfigsOutput, err := client.ListProvisionConfigs( 267 | fc.NewListProvisionConfigsInput()) 268 | if err != nil { 269 | fmt.Fprintln(os.Stderr, err) 270 | } else { 271 | fmt.Printf("ListProvisionConfigs response: %s \n", listProvisionConfigsOutput) 272 | } 273 | 274 | // PutProvisionConfig 0, Delete provision config 275 | fmt.Println("Delete provision config") 276 | putProvisionConfigOutput, err = client.PutProvisionConfig( 277 | fc.NewPutProvisionConfigInput(serviceName, aliasName, "testf1"). 278 | WithTarget(int64(0))) 279 | if err != nil { 280 | fmt.Fprintln(os.Stderr, err) 281 | } else { 282 | fmt.Printf("PutProvisionConfig response: %s \n", putProvisionConfigOutput) 283 | } 284 | 285 | // DeleteAlias 286 | fmt.Println("Deleting aliases") 287 | deleteAliasOutput, err := client.DeleteAlias(fc.NewDeleteAliasInput(serviceName, aliasName)) 288 | if err != nil { 289 | fmt.Fprintln(os.Stderr, err) 290 | } else { 291 | fmt.Printf("DeleteAlias response: %s \n", deleteAliasOutput) 292 | } 293 | 294 | // DeleteServiceVersion 295 | fmt.Println("Deleting service version") 296 | vResp, _ := client.ListServiceVersions(fc.NewListServiceVersionsInput(serviceName)) 297 | for _, f := range vResp.Versions { 298 | 299 | deleteServiceVersionOutput, err := client.DeleteServiceVersion(fc.NewDeleteServiceVersionInput(serviceName, *f.VersionID)) 300 | if err != nil { 301 | fmt.Fprintln(os.Stderr, err) 302 | } else { 303 | fmt.Printf("DeleteServiceVersion response: %s \n", deleteServiceVersionOutput) 304 | } 305 | } 306 | 307 | fmt.Println("Invoking function, log type None") 308 | invokeInput = fc.NewInvokeFunctionInput(serviceName, "testf1").WithLogType("None") 309 | invokeOutput, err = client.InvokeFunction(invokeInput) 310 | if err != nil { 311 | fmt.Fprintln(os.Stderr, err) 312 | } else { 313 | fmt.Printf("InvokeFunction response: %s \n", invokeOutput) 314 | } 315 | 316 | // DeleteFunction 317 | fmt.Println("Deleting functions") 318 | listFunctionsOutput, err = client.ListFunctions(fc.NewListFunctionsInput(serviceName).WithLimit(10)) 319 | if err != nil { 320 | fmt.Fprintln(os.Stderr, err) 321 | } else { 322 | // fmt.Printf("ListFunctions response: %s \n", listFunctionsOutput) 323 | for _, fuc := range listFunctionsOutput.Functions { 324 | fmt.Printf("Deleting function %s \n", *fuc.FunctionName) 325 | if output, err := client.DeleteFunction(fc.NewDeleteFunctionInput(serviceName, *fuc.FunctionName)); err != nil { 326 | fmt.Fprintln(os.Stderr, err) 327 | } else { 328 | fmt.Printf("DeleteFunction response: %s \n", output) 329 | } 330 | } 331 | } 332 | 333 | // DeleteService 334 | fmt.Println("Deleting service") 335 | deleteServiceOutput, err := client.DeleteService(fc.NewDeleteServiceInput(serviceName)) 336 | if err != nil { 337 | fmt.Fprintln(os.Stderr, err) 338 | } else { 339 | fmt.Printf("DeleteService response: %s \n", deleteServiceOutput) 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /samples/trigger.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/aliyun/fc-go-sdk" 8 | ) 9 | 10 | func main() { 11 | client, _ := fc.NewClient(os.Getenv("ENDPOINT"), "2016-08-15", os.Getenv("ACCESS_KEY_ID"), os.Getenv("ACCESS_KEY_SECRETE")) 12 | 13 | serviceName := "wanghq_async_invoke" 14 | functionName := "hello_world" 15 | triggerName := "trigger3" 16 | triggerName2 := "trigger4" 17 | qualifier := "LATEST" 18 | 19 | // Create trigger 20 | fmt.Println("Creating trigger") 21 | createTriggerInput := fc.NewCreateTriggerInput(serviceName, functionName).WithTriggerName(triggerName). 22 | WithDescription("create trigger").WithInvocationRole("acs:ram:cn-hangzhou:123:role1").WithTriggerType("oss"). 23 | WithSourceARN("acs:oss:cn-hangzhou:123:fcbucket").WithTriggerConfig( 24 | fc.NewOSSTriggerConfig().WithEvents([]string{"oss:ObjectCreated:PostObject"}).WithFilterKeyPrefix("r").WithFilterKeySuffix("s")) 25 | 26 | createTriggerOutput, err := client.CreateTrigger(createTriggerInput) 27 | if err != nil { 28 | fmt.Fprintln(os.Stderr, err) 29 | } else { 30 | fmt.Printf("CreateTrigger response: %s \n", createTriggerOutput) 31 | } 32 | 33 | createTriggerInput2 := fc.NewCreateTriggerInput(serviceName, functionName).WithTriggerName(triggerName2). 34 | WithDescription("create trigger").WithInvocationRole("acs:ram:cn-hangzhou:123:role1").WithTriggerType("oss"). 35 | WithSourceARN("acs:oss:cn-hangzhou:123:fcbucket").WithQualifier(qualifier).WithTriggerConfig( 36 | fc.NewOSSTriggerConfig().WithEvents([]string{"oss:ObjectCreated:PostObject"}).WithFilterKeyPrefix("r").WithFilterKeySuffix("s")) 37 | 38 | createTriggerOutput2, err := client.CreateTrigger(createTriggerInput2) 39 | if err != nil { 40 | fmt.Fprintln(os.Stderr, err) 41 | } else { 42 | fmt.Printf("CreateTrigger response: %s \n", createTriggerOutput2) 43 | } 44 | 45 | getTriggerOutput, err := client.GetTrigger(fc.NewGetTriggerInput(serviceName, functionName, triggerName)) 46 | if err != nil { 47 | fmt.Fprintln(os.Stderr, err) 48 | } else { 49 | fmt.Printf("GetTrigger response: %s \n", getTriggerOutput) 50 | } 51 | 52 | getTriggerOutput2, err := client.GetTrigger(fc.NewGetTriggerInput(serviceName, functionName, triggerName2)) 53 | if err != nil { 54 | fmt.Fprintln(os.Stderr, err) 55 | } else { 56 | fmt.Printf("GetTrigger response: %s \n", getTriggerOutput2) 57 | } 58 | 59 | updateTriggerOutput, err := client.UpdateTrigger(fc.NewUpdateTriggerInput(serviceName, functionName, triggerName).WithDescription("update trigger").WithInvocationRole("acs:ram:cn-hangzhou:123:role2")) 60 | if err != nil { 61 | fmt.Fprintln(os.Stderr, err) 62 | } else { 63 | fmt.Printf("UpdateTrigger response: %s \n", updateTriggerOutput) 64 | } 65 | 66 | updateTriggerOutput2, err := client.UpdateTrigger(fc.NewUpdateTriggerInput(serviceName, functionName, triggerName2).WithDescription("update trigger").WithInvocationRole("acs:ram:cn-hangzhou:123:role2")) 67 | if err != nil { 68 | fmt.Fprintln(os.Stderr, err) 69 | } else { 70 | fmt.Printf("UpdateTrigger response: %s \n", updateTriggerOutput2) 71 | } 72 | 73 | deleteTriggerOutput, err := client.DeleteTrigger(fc.NewDeleteTriggerInput(serviceName, functionName, triggerName)) 74 | if err != nil { 75 | fmt.Fprintln(os.Stderr, err) 76 | } else { 77 | fmt.Printf("DeleteTrigger response: %s \n", deleteTriggerOutput) 78 | } 79 | 80 | deleteTriggerOutput2, err := client.DeleteTrigger(fc.NewDeleteTriggerInput(serviceName, functionName, triggerName2)) 81 | if err != nil { 82 | fmt.Fprintln(os.Stderr, err) 83 | } else { 84 | fmt.Printf("DeleteTrigger response: %s \n", deleteTriggerOutput2) 85 | } 86 | 87 | listTriggersOutput, err := client.ListTriggers(fc.NewListTriggersInput(serviceName, functionName)) 88 | if err != nil { 89 | fmt.Fprintln(os.Stderr, err) 90 | } else { 91 | fmt.Printf("ListTriggers response: %s \n", listTriggersOutput) 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /service_test.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/suite" 7 | ) 8 | 9 | func TestServiceStructs(t *testing.T) { 10 | suite.Run(t, new(ServiceStructsTestSuite)) 11 | } 12 | 13 | type ServiceStructsTestSuite struct { 14 | suite.Suite 15 | } 16 | 17 | func (s *ServiceStructsTestSuite) TestCreateService() { 18 | assert := s.Require() 19 | 20 | tracingConfigInput := NewTracingConfig() 21 | tracingConfigInput.WithType(TracingTypeJaeger) 22 | assert.Equal(TracingTypeJaeger, *tracingConfigInput.Type) 23 | tracingConfigInput.WithParams(NewJaegerConfig().WithEndpoint("mock-jaeger-endpoint")) 24 | jaegerConfig, ok := tracingConfigInput.Params.(*JaegerConfig) 25 | assert.True(ok) 26 | assert.Equal("mock-jaeger-endpoint", *jaegerConfig.Endpoint) 27 | 28 | tracingConfigInput = NewTracingConfig() 29 | tracingConfigInput.WithJaegerConfig(NewJaegerConfig().WithEndpoint("mock-jaeger-endpoint")) 30 | jaegerConfig, ok = tracingConfigInput.Params.(*JaegerConfig) 31 | assert.True(ok) 32 | assert.Equal("mock-jaeger-endpoint", *jaegerConfig.Endpoint) 33 | assert.Equal(TracingTypeJaeger, *tracingConfigInput.Type) 34 | 35 | input := NewCreateServiceInput() 36 | assert.NotNil(input) 37 | 38 | input.WithServiceName("mock-service") 39 | assert.NotNil(input.ServiceName) 40 | assert.Equal("mock-service", *input.ServiceName) 41 | 42 | input.WithTracingConfig(tracingConfigInput) 43 | assert.NotNil(input.TracingConfig) 44 | assert.Equal(tracingConfigInput, input.TracingConfig) 45 | 46 | input.WithVPCConfig(NewVPCConfig(). 47 | WithVPCID("vpc-id"). 48 | WithVSwitchIDs([]string{"sw-1", "sw-2"}). 49 | WithSecurityGroupID("sg-id")) 50 | assert.NotNil(input.VPCConfig) 51 | assert.Equal("vpc-id", *input.VPCConfig.VPCID) 52 | assert.Equal([]string{"sw-1", "sw-2"}, input.VPCConfig.VSwitchIDs) 53 | assert.Equal("sg-id", *input.VPCConfig.SecurityGroupID) 54 | 55 | logStore := NewLogConfig().WithProject("mock-log-project").WithLogstore("mock-log-store") 56 | logStore.WithEnableRequestMetrics(true) 57 | input.WithLogConfig(logStore) 58 | assert.NotNil(logStore) 59 | assert.Equal(true, *logStore.EnableRequestMetrics) 60 | 61 | logStore.WithEnableInstanceMetrics(true) 62 | input.WithLogConfig(logStore) 63 | assert.NotNil(logStore) 64 | assert.Equal(true, *logStore.EnableInstanceMetrics) 65 | } 66 | 67 | func (s *ServiceStructsTestSuite) TestUpdateService() { 68 | assert := s.Require() 69 | 70 | input := NewUpdateServiceInput("mock-service-name") 71 | assert.NotNil(input) 72 | 73 | logConfig := NewLogConfig().WithProject("mock-log-project").WithLogstore("mock-log-store").WithEnableRequestMetrics(true).WithEnableInstanceMetrics(true) 74 | input.WithLogConfig(logConfig) 75 | assert.NotNil(logConfig) 76 | assert.Equal(true, *input.LogConfig.EnableRequestMetrics) 77 | assert.Equal(true, *input.LogConfig.EnableInstanceMetrics) 78 | 79 | } 80 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | STR=$(go version) 4 | 5 | golang1dot8='go1.8' 6 | golang1dot9='go1.9' 7 | golang1dot10='go1.10' 8 | golang1dot11='go1.11' 9 | 10 | function setup_golang_vendor() { 11 | # Use glide to install deps for go version < 1.11 12 | curl https://glide.sh/get | sh 13 | glide update 14 | glide install 15 | go test -v 16 | } 17 | 18 | function setup_golang_go_mod() { 19 | # Use go mod for go version >= 1.11 20 | export GO111MODULE=on 21 | go test -v 22 | } 23 | 24 | if [[ "$STR" =~ .*"$golang1dot8".* ]]; then 25 | echo "Setup golang 1.8" 26 | setup_golang_vendor 27 | fi 28 | 29 | if [[ "$STR" =~ .*"$golang1dot9".* ]]; then 30 | echo "Setup golang 1.9" 31 | setup_golang_vendor 32 | fi 33 | 34 | if [[ "$STR" =~ .*"$golang1dot10".* ]]; then 35 | echo "Setup golang 1.10" 36 | setup_golang_vendor 37 | fi 38 | 39 | if [[ "$STR" =~ .*"$golang1dot11".* ]]; then 40 | echo "Setup golang 1.11" 41 | setup_golang_go_mod 42 | fi 43 | 44 | -------------------------------------------------------------------------------- /sign_url_request.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/url" 7 | "time" 8 | ) 9 | 10 | // SignURLInput ... 11 | type SignURLInput struct { 12 | Method string 13 | Expires time.Time 14 | ServiceName string 15 | Qualifier string 16 | FunctionName string 17 | CustomEndpoint string 18 | EscapedPath string 19 | Header http.Header 20 | Queries url.Values 21 | } 22 | 23 | // NewSignURLInput : create sign url request 24 | func NewSignURLInput(method, serviceName, functionName string, expires time.Time) *SignURLInput { 25 | return &SignURLInput{ 26 | ServiceName: serviceName, 27 | FunctionName: functionName, 28 | Method: method, 29 | Expires: expires, 30 | } 31 | } 32 | 33 | func (s *SignURLInput) signURL(apiVersion, endpoint, akID, akSec, stsToken string) (string, error) { 34 | orinalEscapedPath := s.EscapedPath 35 | if orinalEscapedPath == "" { 36 | orinalEscapedPath = "/" 37 | } 38 | unescapedPath, err := url.PathUnescape(orinalEscapedPath) 39 | if err != nil { 40 | return "", err 41 | } 42 | 43 | var queries url.Values = map[string][]string{} 44 | for k, values := range s.Queries { 45 | for _, v := range values { 46 | queries.Add(k, v) 47 | } 48 | } 49 | queries.Set(AuthQueryKeyExpires, fmt.Sprintf("%d", s.Expires.Unix())) 50 | if stsToken != "" { 51 | queries.Set(AuthQueryKeySecurityToken, stsToken) 52 | } 53 | queries.Set(AuthQueryKeyAccessKeyID, akID) 54 | 55 | singleHeaders := map[string]string{} 56 | for k, v := range s.Header { 57 | if len(v) > 0 { 58 | singleHeaders[http.CanonicalHeaderKey(k)] = v[0] 59 | } 60 | } 61 | 62 | serviceWithQualifier := s.ServiceName 63 | if s.Qualifier != "" { 64 | serviceWithQualifier = s.ServiceName + "." + s.Qualifier 65 | } 66 | 67 | unescapedPathForSign := fmt.Sprintf("/%s/proxy/%s/%s%s", apiVersion, 68 | serviceWithQualifier, s.FunctionName, unescapedPath) 69 | 70 | escapedPath := fmt.Sprintf("/%s/proxy/%s/%s%s", apiVersion, 71 | serviceWithQualifier, s.FunctionName, orinalEscapedPath) 72 | 73 | if s.CustomEndpoint != "" { 74 | _, err := url.Parse(s.CustomEndpoint) 75 | if s.CustomEndpoint == endpoint || err != nil { 76 | return "", fmt.Errorf("invalid custom endpoint: %s", s.CustomEndpoint) 77 | } 78 | endpoint = s.CustomEndpoint 79 | escapedPath = orinalEscapedPath 80 | unescapedPathForSign = unescapedPath 81 | } 82 | 83 | fcResource := GetSignResourceWithQueries(unescapedPathForSign, queries) 84 | signature := GetSignature(akSec, s.Method, singleHeaders, fcResource) 85 | 86 | queries.Set(AuthQueryKeySignature, signature) 87 | 88 | return fmt.Sprintf("%s%s?%s", endpoint, escapedPath, queries.Encode()), nil 89 | } 90 | 91 | // WithQualifier ... 92 | func (s *SignURLInput) WithQualifier(qualifier string) *SignURLInput { 93 | s.Qualifier = qualifier 94 | return s 95 | } 96 | 97 | // WithCustomEndpoint ... 98 | func (s *SignURLInput) WithCustomEndpoint(customEndpoint string) *SignURLInput { 99 | s.CustomEndpoint = customEndpoint 100 | return s 101 | } 102 | 103 | // WithEscapedPath ... 104 | func (s *SignURLInput) WithEscapedPath(esapedPath string) *SignURLInput { 105 | s.EscapedPath = esapedPath 106 | return s 107 | } 108 | 109 | // WithHeader ... 110 | func (s *SignURLInput) WithHeader(header http.Header) *SignURLInput { 111 | s.Header = header 112 | return s 113 | } 114 | 115 | // WithQueries ... 116 | func (s *SignURLInput) WithQueries(queries url.Values) *SignURLInput { 117 | s.Queries = queries 118 | return s 119 | } 120 | -------------------------------------------------------------------------------- /sign_url_request_test.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | func TestSignURL(t *testing.T) { 9 | input := NewSignURLInput("GET", "service", "func", time.Unix(1583339600, 0)) 10 | url, err := input.signURL("2016-08-15", "http://localhost", "akid", "akSec", "stsToken") 11 | expectedURL := "http://localhost/2016-08-15/proxy/service/func/?x-fc-access-key-id=akid&x-fc-expires=1583339600&x-fc-security-token=stsToken&x-fc-signature=Yi0jCBQ6cTZc%2BtN8wtYUz9FbYNijx5jDiE3sVNW6XwA%3D" 12 | if url != expectedURL { 13 | t.Fatalf("%s expected but %s in actual due to %+v", expectedURL, url, err) 14 | } 15 | 16 | // make sure stsToken should be signed 17 | nURL, nErr := input.signURL("2016-08-15", "http://localhost", "akid", "akSec", "") 18 | nExpectedURL := "http://localhost/2016-08-15/proxy/service/func/?x-fc-access-key-id=akid&x-fc-expires=1583339600&x-fc-signature=6Rc4KxEAv3%2BlHpbNQWceIUqWVWq3ewxhadlJBRzZ0XQ%3D" 19 | if nURL != nExpectedURL { 20 | t.Fatalf("%s expected but %s in actual due to %+v", nExpectedURL, nURL, nErr) 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /signature.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "bytes" 5 | "crypto/hmac" 6 | "crypto/sha256" 7 | "encoding/base64" 8 | "fmt" 9 | "hash" 10 | "io" 11 | "sort" 12 | "strings" 13 | ) 14 | 15 | const ( 16 | // AuthQueryKeyExpires : keys in request queries 17 | AuthQueryKeyExpires = "x-fc-expires" 18 | 19 | // AuthQueryKeyAccessKeyID : keys in request queries 20 | AuthQueryKeyAccessKeyID = "x-fc-access-key-id" 21 | 22 | // AuthQueryKeySignature : keys in request queries 23 | AuthQueryKeySignature = "x-fc-signature" 24 | 25 | // AuthQueryKeySecurityToken : keys in requres queries 26 | AuthQueryKeySecurityToken = "x-fc-security-token" 27 | ) 28 | 29 | type headers struct { 30 | Keys []string 31 | Vals []string 32 | } 33 | 34 | // GetAuthStr get signature strings 35 | func GetAuthStr(accessKeyID string, accessKeySecret string, method string, header map[string]string, resource string) string { 36 | return "FC " + accessKeyID + ":" + GetSignature(accessKeySecret, method, header, resource) 37 | } 38 | 39 | func getSignQueries(queries map[string][]string) string { 40 | paramsList := []string{} 41 | for key, values := range queries { 42 | if len(values) == 0 { 43 | paramsList = append(paramsList, key) 44 | continue 45 | } 46 | for _, v := range values { 47 | paramsList = append(paramsList, fmt.Sprintf("%s=%s", key, v)) 48 | } 49 | } 50 | sort.Strings(paramsList) 51 | return strings.Join(paramsList, "\n") 52 | } 53 | 54 | // GetSignResourceWithQueries get signature resource with queries 55 | func GetSignResourceWithQueries(path string, queries map[string][]string) string { 56 | return path + "\n" + getSignQueries(queries) 57 | } 58 | 59 | // getExpiresFromURLQueries returns expires and true if AuthQueryKeyExpires in queries 60 | func getExpiresFromURLQueries(fcResource string) (string, bool) { 61 | originItems := strings.Split(fcResource, "\n") 62 | queriesUnescaped := map[string]string{} 63 | 64 | for _, item := range originItems[1:] { 65 | kvPair := strings.Split(item, "=") 66 | if len(kvPair) > 1 { 67 | queriesUnescaped[kvPair[0]] = kvPair[1] 68 | } 69 | } 70 | 71 | expires, ok := queriesUnescaped[AuthQueryKeyExpires] 72 | return expires, ok 73 | } 74 | 75 | // GetSignature calculate user's signature 76 | func GetSignature(key string, method string, req map[string]string, fcResource string) string { 77 | header := &headers{} 78 | lowerKeyHeaders := map[string]string{} 79 | for k, v := range req { 80 | lowerKey := strings.ToLower(k) 81 | if strings.HasPrefix(lowerKey, HTTPHeaderPrefix) { 82 | header.Keys = append(header.Keys, lowerKey) 83 | header.Vals = append(header.Vals, v) 84 | } 85 | lowerKeyHeaders[lowerKey] = v 86 | } 87 | sort.Sort(header) 88 | 89 | fcHeaders := "" 90 | for i := range header.Keys { 91 | fcHeaders += header.Keys[i] + ":" + header.Vals[i] + "\n" 92 | } 93 | 94 | date := req[HTTPHeaderDate] 95 | if expires, ok := getExpiresFromURLQueries(fcResource); ok { 96 | date = expires 97 | } 98 | 99 | signStr := method + "\n" + lowerKeyHeaders[strings.ToLower(HTTPHeaderContentMD5)] + "\n" + lowerKeyHeaders[strings.ToLower(HTTPHeaderContentType)] + "\n" + date + "\n" + fcHeaders + fcResource 100 | 101 | h := hmac.New(func() hash.Hash { return sha256.New() }, []byte(key)) 102 | io.WriteString(h, signStr) 103 | signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil)) 104 | 105 | return signedStr 106 | } 107 | 108 | func (h *headers) Len() int { 109 | return len(h.Vals) 110 | } 111 | 112 | func (h *headers) Less(i, j int) bool { 113 | return bytes.Compare([]byte(h.Keys[i]), []byte(h.Keys[j])) < 0 114 | } 115 | 116 | func (h *headers) Swap(i, j int) { 117 | h.Vals[i], h.Vals[j] = h.Vals[j], h.Vals[i] 118 | h.Keys[i], h.Keys[j] = h.Keys[j], h.Keys[i] 119 | } 120 | -------------------------------------------------------------------------------- /signature_test.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestGetSignResourceWithQueries(t *testing.T) { 8 | path := "/path/action with space" 9 | queries := map[string][]string{ 10 | "xyz": {}, 11 | "foo": {"bar"}, 12 | "key2": {"123"}, 13 | "key1": {"xyz", "abc"}, 14 | "key3/~x-y_z.a#b": {"value/~x-y_z.a#b"}, 15 | } 16 | resource := GetSignResourceWithQueries(path, queries) 17 | 18 | expectedResource := "/path/action with space\nfoo=bar\nkey1=abc\nkey1=xyz\nkey2=123\nkey3/~x-y_z.a#b=value/~x-y_z.a#b\nxyz" 19 | if resource != expectedResource { 20 | t.Fatalf("%s expected but %s in actual", expectedResource, resource) 21 | } 22 | 23 | } 24 | 25 | func TestGetSignature(t *testing.T) { 26 | path := "/2016-08-15/proxy/service.LATEST/func/abc 123" 27 | queries := map[string][]string{ 28 | "x": {"xyz", "456"}, 29 | "a": {"123 45"}, 30 | "x-fc-expires": {"1583221068"}, 31 | "x-fc-access-key-id": {"akID"}, 32 | "x-fc-security-token": {"stsToken"}, 33 | } 34 | 35 | headers := map[string]string{ 36 | "x-fc-trace-id": "trace-id", 37 | "content-type": "text/json", 38 | "content-md5": "ef5b43a0fe1d5b401b62c3ba33a7a3d6", 39 | } 40 | 41 | mockAkSec := "S9MWOBG0AOWHSO9HPASP216QOPHT5YR4NLH3A" 42 | fcResource := GetSignResourceWithQueries(path, queries) 43 | signature := GetSignature(mockAkSec, "GET", headers, fcResource) 44 | 45 | expectedSign := "QFdNhz0Dl+onUM/MvpX940WFH3H8OHayZHbby1c01aI=" 46 | expectedSignStr := "GET\nef5b43a0fe1d5b401b62c3ba33a7a3d6\ntext/json\n1583221068\nx-fc-trace-id:trace-id\n/2016-08-15/proxy/service.LATEST/func/abc 123\na=123 45\nx-fc-access-key-id=akID\nx-fc-expires=1583221068\nx-fc-security-token=stsToken\nx=456\nx=xyz" 47 | 48 | if signature != expectedSign { 49 | t.Fatalf("%s expected but %s in actual, signStr:%s", expectedSign, signature, expectedSignStr) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /stateful_async_invocation.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | "strconv" 9 | ) 10 | 11 | // StatefulAsyncInvocation represents the stateful async invocation records. 12 | type StatefulAsyncInvocation struct { 13 | FunctionName *string `json:"functionName"` 14 | ServiceName *string `json:"serviceName"` 15 | Qualifier *string `json:"qualifier"` 16 | InvocationID *string `json:"invocationId"` 17 | Status *string `json:"status"` 18 | // in ms 19 | StartedTime *int64 `json:"startedTime"` 20 | EndTime *int64 `json:"endTime"` 21 | DestinationStatus *string `json:"destinationStatus"` 22 | InvocationErrorMessage *string `json:"invocationErrorMessage"` 23 | InvocationPayload *string `json:"invocationPayload"` 24 | RequestID *string `json:"requestId"` 25 | AlreadyRetriedTimes *int64 `json:"alreadyRetriedTimes"` 26 | } 27 | 28 | type StatefulAsyncInvocationResponse struct { 29 | StatefulAsyncInvocation 30 | } 31 | 32 | // GetFunctionAsyncInvokeConfigInput defines function creation input 33 | type GetStatefulAsyncInvocationInput struct { 34 | ServiceName *string `json:"serviceName"` 35 | Qualifier *string `json:"qualifier"` 36 | FunctionName *string `json:"functionName"` 37 | InvocationID *string `json:"invocationId"` 38 | } 39 | 40 | func NewGetStatefulAsyncInvocationInput(serviceName, functionName, invocationID string) *GetStatefulAsyncInvocationInput { 41 | return &GetStatefulAsyncInvocationInput{ServiceName: &serviceName, FunctionName: &functionName, InvocationID: &invocationID} 42 | } 43 | 44 | func (i *GetStatefulAsyncInvocationInput) WithQualifier(qualifier string) *GetStatefulAsyncInvocationInput { 45 | i.Qualifier = &qualifier 46 | return i 47 | } 48 | 49 | func (i *GetStatefulAsyncInvocationInput) GetQueryParams() url.Values { 50 | out := url.Values{} 51 | return out 52 | } 53 | 54 | func (i *GetStatefulAsyncInvocationInput) GetPath() string { 55 | if !IsBlank(i.Qualifier) { 56 | return fmt.Sprintf(statefulAsyncInvocationWithQualifierPath, 57 | pathEscape(*i.ServiceName), pathEscape(*i.Qualifier), pathEscape(*i.FunctionName), pathEscape(*i.InvocationID)) 58 | } 59 | return fmt.Sprintf(statefulAsyncInvocationPath, pathEscape(*i.ServiceName), pathEscape(*i.FunctionName), pathEscape(*i.InvocationID)) 60 | } 61 | 62 | func (i *GetStatefulAsyncInvocationInput) GetHeaders() Header { 63 | header := make(Header) 64 | return header 65 | } 66 | 67 | func (i *GetStatefulAsyncInvocationInput) GetPayload() interface{} { 68 | return nil 69 | } 70 | 71 | func (i *GetStatefulAsyncInvocationInput) Validate() error { 72 | if IsBlank(i.ServiceName) { 73 | return fmt.Errorf("Service name is required but not provided") 74 | } 75 | if IsBlank(i.FunctionName) { 76 | return fmt.Errorf("Function name is required but not provided") 77 | } 78 | if IsBlank(i.InvocationID) { 79 | return fmt.Errorf("InvocationID is required but not provided") 80 | } 81 | return nil 82 | } 83 | 84 | // GetFunctionAsyncInvokeConfigOutput define get data response 85 | type GetStatefulAsyncInvocationOutput struct { 86 | Header http.Header 87 | StatefulAsyncInvocationResponse 88 | } 89 | 90 | func (o GetStatefulAsyncInvocationOutput) String() string { 91 | b, err := json.MarshalIndent(o, "", printIndent) 92 | if err != nil { 93 | return "" 94 | } 95 | return string(b) 96 | } 97 | 98 | func (o GetStatefulAsyncInvocationOutput) GetRequestID() string { 99 | return GetRequestID(o.Header) 100 | } 101 | 102 | // ListFunctionAsyncInvokeConfigsOutput defines ListFunctionAsyncInvocationsOutput result 103 | type ListStatefulAsyncInvocationsOutput struct { 104 | Header http.Header 105 | Invocations []*StatefulAsyncInvocation `json:"invocations"` 106 | NextToken *string `json:"nextToken"` 107 | } 108 | 109 | func (o ListStatefulAsyncInvocationsOutput) String() string { 110 | b, err := json.MarshalIndent(o, "", printIndent) 111 | if err != nil { 112 | return "" 113 | } 114 | return string(b) 115 | } 116 | 117 | func (o ListStatefulAsyncInvocationsOutput) GetRequestID() string { 118 | return GetRequestID(o.Header) 119 | } 120 | 121 | type ListStatefulAsyncInvocationsInput struct { 122 | ServiceName *string `json:"serviceName"` 123 | FunctionName *string `json:"functionName"` 124 | Qualifier *string `json:"qualifier"` 125 | NextToken *string `json:"nextToken"` 126 | Limit *int32 `json:"limit"` 127 | Status *string `json:"status"` 128 | StartedTimeBegin *int64 `json:"startedTimeBegin"` 129 | StartedTimeEnd *int64 `json:"startedTimeEnd"` 130 | SortOrderByTime *string `json:"sortOrderByTime"` 131 | InvocationIDPrefix *string `json:"invocationIdPrefix"` 132 | IncludePayload *bool `json:"includePayload"` 133 | } 134 | 135 | func NewListStatefulAsyncInvocationsInput(serviceName, functionName string) *ListStatefulAsyncInvocationsInput { 136 | return &ListStatefulAsyncInvocationsInput{ 137 | ServiceName: &serviceName, 138 | FunctionName: &functionName, 139 | } 140 | } 141 | 142 | func (i *ListStatefulAsyncInvocationsInput) WithQualifier(qualifier string) *ListStatefulAsyncInvocationsInput { 143 | i.Qualifier = &qualifier 144 | return i 145 | } 146 | 147 | func (i *ListStatefulAsyncInvocationsInput) WithNextToken(nextToken string) *ListStatefulAsyncInvocationsInput { 148 | i.NextToken = &nextToken 149 | return i 150 | } 151 | 152 | func (i *ListStatefulAsyncInvocationsInput) WithLimit(limit int32) *ListStatefulAsyncInvocationsInput { 153 | i.Limit = &limit 154 | return i 155 | } 156 | 157 | func (i *ListStatefulAsyncInvocationsInput) WithStatus(status string) *ListStatefulAsyncInvocationsInput { 158 | i.Status = &status 159 | return i 160 | } 161 | 162 | func (i *ListStatefulAsyncInvocationsInput) WithStartedTimeBegin(startedTimeBegin int64) *ListStatefulAsyncInvocationsInput { 163 | i.StartedTimeBegin = &startedTimeBegin 164 | return i 165 | } 166 | 167 | func (i *ListStatefulAsyncInvocationsInput) WithStartedTimeEnd(startedTimeEnd int64) *ListStatefulAsyncInvocationsInput { 168 | i.StartedTimeEnd = &startedTimeEnd 169 | return i 170 | } 171 | 172 | func (i *ListStatefulAsyncInvocationsInput) WithSortOrderByTime(sortOrder string) *ListStatefulAsyncInvocationsInput { 173 | i.SortOrderByTime = &sortOrder 174 | return i 175 | } 176 | 177 | func (i *ListStatefulAsyncInvocationsInput) WithInvocationIDPrefix(prefix string) *ListStatefulAsyncInvocationsInput { 178 | i.InvocationIDPrefix = &prefix 179 | return i 180 | } 181 | 182 | func (i *ListStatefulAsyncInvocationsInput) WithIncludePayload(includePayload bool) *ListStatefulAsyncInvocationsInput { 183 | i.IncludePayload = &includePayload 184 | return i 185 | } 186 | 187 | func (i *ListStatefulAsyncInvocationsInput) GetQueryParams() url.Values { 188 | out := url.Values{} 189 | 190 | if i.NextToken != nil { 191 | out.Set("nextToken", *i.NextToken) 192 | } 193 | 194 | if i.Limit != nil { 195 | out.Set("limit", strconv.FormatInt(int64(*i.Limit), 10)) 196 | } 197 | 198 | if i.Status != nil { 199 | out.Set("status", *i.Status) 200 | } 201 | 202 | if i.StartedTimeBegin != nil { 203 | out.Set("startedTimeBegin", strconv.FormatInt(int64(*i.StartedTimeBegin), 10)) 204 | } 205 | 206 | if i.StartedTimeEnd != nil { 207 | out.Set("startedTimeEnd", strconv.FormatInt(int64(*i.StartedTimeEnd), 10)) 208 | } 209 | 210 | if i.SortOrderByTime != nil { 211 | out.Set("sortOrderByTime", *i.SortOrderByTime) 212 | } 213 | 214 | if i.InvocationIDPrefix != nil { 215 | out.Set("invocationIdPrefix", *i.InvocationIDPrefix) 216 | } 217 | 218 | if i.IncludePayload != nil { 219 | out.Set("includePayload", strconv.FormatBool(*i.IncludePayload)) 220 | } 221 | 222 | return out 223 | } 224 | 225 | func (i *ListStatefulAsyncInvocationsInput) GetPath() string { 226 | if !IsBlank(i.Qualifier) { 227 | return fmt.Sprintf(listStatefulAsyncInvocationsWithQualifierPath, 228 | pathEscape(*i.ServiceName), pathEscape(*i.Qualifier), pathEscape(*i.FunctionName)) 229 | } 230 | return fmt.Sprintf(listStatefulAsyncInvocationsPath, pathEscape(*i.ServiceName), pathEscape(*i.FunctionName)) 231 | } 232 | 233 | func (i *ListStatefulAsyncInvocationsInput) GetHeaders() Header { 234 | return make(Header, 0) 235 | } 236 | 237 | func (i *ListStatefulAsyncInvocationsInput) GetPayload() interface{} { 238 | return nil 239 | } 240 | 241 | func (i *ListStatefulAsyncInvocationsInput) Validate() error { 242 | if IsBlank(i.ServiceName) { 243 | return fmt.Errorf("Service name is required but not provided") 244 | } 245 | if IsBlank(i.FunctionName) { 246 | return fmt.Errorf("Function name is required but not provided") 247 | } 248 | return nil 249 | } 250 | 251 | // StopStatefulAsyncInvocationInput defines function creation input 252 | type StopStatefulAsyncInvocationInput struct { 253 | ServiceName *string `json:"serviceName"` 254 | Qualifier *string `json:"qualifier"` 255 | FunctionName *string `json:"functionName"` 256 | InvocationID *string `json:"invocationId"` 257 | } 258 | 259 | func NewStopStatefulAsyncInvocationInput(serviceName, functionName, invocationID string) *StopStatefulAsyncInvocationInput { 260 | return &StopStatefulAsyncInvocationInput{ServiceName: &serviceName, FunctionName: &functionName, InvocationID: &invocationID} 261 | } 262 | 263 | func (i *StopStatefulAsyncInvocationInput) WithQualifier(qualifier string) *StopStatefulAsyncInvocationInput { 264 | i.Qualifier = &qualifier 265 | return i 266 | } 267 | 268 | func (i *StopStatefulAsyncInvocationInput) GetQueryParams() url.Values { 269 | out := url.Values{} 270 | return out 271 | } 272 | 273 | func (i *StopStatefulAsyncInvocationInput) GetPath() string { 274 | if !IsBlank(i.Qualifier) { 275 | return fmt.Sprintf(statefulAsyncInvocationWithQualifierPath, 276 | pathEscape(*i.ServiceName), pathEscape(*i.Qualifier), pathEscape(*i.FunctionName), pathEscape(*i.InvocationID)) 277 | } 278 | return fmt.Sprintf(statefulAsyncInvocationPath, pathEscape(*i.ServiceName), pathEscape(*i.FunctionName), pathEscape(*i.InvocationID)) 279 | } 280 | 281 | func (i *StopStatefulAsyncInvocationInput) GetHeaders() Header { 282 | header := make(Header) 283 | return header 284 | } 285 | 286 | func (i *StopStatefulAsyncInvocationInput) GetPayload() interface{} { 287 | return nil 288 | } 289 | 290 | func (i *StopStatefulAsyncInvocationInput) Validate() error { 291 | if IsBlank(i.ServiceName) { 292 | return fmt.Errorf("Service name is required but not provided") 293 | } 294 | if IsBlank(i.FunctionName) { 295 | return fmt.Errorf("Function name is required but not provided") 296 | } 297 | if IsBlank(i.InvocationID) { 298 | return fmt.Errorf("InvocationID is required but not provided") 299 | } 300 | return nil 301 | } 302 | 303 | // StopStatefulAsyncInvocationOutput ... 304 | type StopStatefulAsyncInvocationOutput struct { 305 | Header http.Header 306 | } 307 | 308 | func (o StopStatefulAsyncInvocationOutput) String() string { 309 | b, err := json.MarshalIndent(o, "", printIndent) 310 | if err != nil { 311 | return "" 312 | } 313 | return string(b) 314 | } 315 | 316 | func (o StopStatefulAsyncInvocationOutput) GetRequestID() string { 317 | return GetRequestID(o.Header) 318 | } 319 | -------------------------------------------------------------------------------- /tablestore_trigger.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | // TableStoreTriggerConfig .. 4 | type TableStoreTriggerConfig struct { 5 | } 6 | 7 | // NewTableStoreTriggerConfig .. 8 | func NewTableStoreTriggerConfig() *TableStoreTriggerConfig { 9 | return &TableStoreTriggerConfig{} 10 | } 11 | -------------------------------------------------------------------------------- /tag.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | ) 9 | 10 | const ( 11 | tagPath = "/tag" 12 | tagsPath = "/tags" 13 | ) 14 | 15 | // TagResourceInput defines input to tag a resource(service) 16 | type TagResourceInput struct { 17 | ResourceArn *string `json:"resourceArn"` 18 | Tags map[string]string `json:"tags"` 19 | } 20 | 21 | // NewTagResourceInput ... 22 | func NewTagResourceInput(resourceArn string, tags map[string]string) *TagResourceInput { 23 | return &TagResourceInput{ResourceArn: &resourceArn, Tags: tags} 24 | } 25 | 26 | func (s *TagResourceInput) WithResourceArn(resourceArn string) *TagResourceInput { 27 | s.ResourceArn = &resourceArn 28 | return s 29 | } 30 | 31 | func (s *TagResourceInput) WithTags(tags map[string]string) *TagResourceInput { 32 | s.Tags = tags 33 | return s 34 | } 35 | 36 | func (t *TagResourceInput) GetQueryParams() url.Values { 37 | out := url.Values{} 38 | return out 39 | } 40 | 41 | func (t *TagResourceInput) GetPath() string { 42 | return tagPath 43 | } 44 | 45 | func (t *TagResourceInput) GetHeaders() Header { 46 | return make(Header, 0) 47 | } 48 | 49 | func (t *TagResourceInput) GetPayload() interface{} { 50 | return t 51 | } 52 | 53 | func (t *TagResourceInput) Validate() error { 54 | if IsBlank(t.ResourceArn) { 55 | return fmt.Errorf("ResourceArn is required but not provided") 56 | } 57 | 58 | if t.Tags == nil || len(t.Tags) == 0 { 59 | return fmt.Errorf("At least 1 tag is required") 60 | } 61 | return nil 62 | } 63 | 64 | // TagResourceOut ... 65 | type TagResourceOut struct { 66 | Header http.Header 67 | } 68 | 69 | func (o TagResourceOut) String() string { 70 | b, err := json.MarshalIndent(o, "", printIndent) 71 | if err != nil { 72 | return "" 73 | } 74 | return string(b) 75 | } 76 | 77 | func (o TagResourceOut) GetRequestID() string { 78 | return GetRequestID(o.Header) 79 | } 80 | 81 | // GetResourceTagsInput ... 82 | type GetResourceTagsInput struct { 83 | ResourceArn *string `json:"resourceArn"` 84 | } 85 | 86 | // NewGetResourceTagsInput... 87 | func NewGetResourceTagsInput(resourceArn string) *GetResourceTagsInput { 88 | return &GetResourceTagsInput{ResourceArn: &resourceArn} 89 | } 90 | 91 | func (s *GetResourceTagsInput) WithResourceArn(resourceArn string) *GetResourceTagsInput { 92 | s.ResourceArn = &resourceArn 93 | return s 94 | } 95 | 96 | func (t *GetResourceTagsInput) GetQueryParams() url.Values { 97 | out := url.Values{} 98 | if t.ResourceArn != nil { 99 | out.Set("resourceArn", *t.ResourceArn) 100 | } 101 | return out 102 | } 103 | 104 | func (t *GetResourceTagsInput) GetPath() string { 105 | return tagPath 106 | } 107 | 108 | func (t *GetResourceTagsInput) GetHeaders() Header { 109 | return make(Header, 0) 110 | } 111 | 112 | func (t *GetResourceTagsInput) GetPayload() interface{} { 113 | return nil 114 | } 115 | 116 | func (t *GetResourceTagsInput) Validate() error { 117 | if IsBlank(t.ResourceArn) { 118 | return fmt.Errorf("ResourceArn is required but not provided") 119 | } 120 | return nil 121 | } 122 | 123 | // GetResourceTagsOut ... 124 | type GetResourceTagsOut struct { 125 | Header http.Header 126 | ResourceArn *string `json:"resourceArn"` 127 | Tags map[string]string `json:"tags"` 128 | } 129 | 130 | func (o GetResourceTagsOut) String() string { 131 | b, err := json.MarshalIndent(o, "", printIndent) 132 | if err != nil { 133 | return "" 134 | } 135 | return string(b) 136 | } 137 | 138 | func (o GetResourceTagsOut) GetRequestID() string { 139 | return GetRequestID(o.Header) 140 | } 141 | 142 | // UnTagResourceInput ... 143 | type UnTagResourceInput struct { 144 | ResourceArn *string `json:"resourceArn"` 145 | TagKeys []string `json:"tagKeys"` 146 | All *bool `json:"all"` 147 | } 148 | 149 | // NewUnTagResourceInput ... 150 | func NewUnTagResourceInput(resourceArn string) *UnTagResourceInput { 151 | return &UnTagResourceInput{ResourceArn: &resourceArn} 152 | } 153 | 154 | func (s *UnTagResourceInput) WithResourceArn(resourceArn string) *UnTagResourceInput { 155 | s.ResourceArn = &resourceArn 156 | return s 157 | } 158 | 159 | func (s *UnTagResourceInput) WithTagKeys(tagKeys []string) *UnTagResourceInput { 160 | s.TagKeys = tagKeys 161 | return s 162 | } 163 | 164 | func (s *UnTagResourceInput) WithAll(all bool) *UnTagResourceInput { 165 | s.All = &all 166 | return s 167 | } 168 | 169 | func (t *UnTagResourceInput) GetQueryParams() url.Values { 170 | out := url.Values{} 171 | return out 172 | } 173 | 174 | func (t *UnTagResourceInput) GetPath() string { 175 | return tagPath 176 | } 177 | 178 | func (t *UnTagResourceInput) GetHeaders() Header { 179 | return make(Header, 0) 180 | } 181 | 182 | func (t *UnTagResourceInput) GetPayload() interface{} { 183 | return t 184 | } 185 | 186 | func (t *UnTagResourceInput) Validate() error { 187 | if IsBlank(t.ResourceArn) { 188 | return fmt.Errorf("ResourceArn is required but not provided") 189 | } 190 | 191 | all := true 192 | if t.All == nil { 193 | all = false 194 | } else { 195 | all = *t.All 196 | } 197 | 198 | if !all && len(t.TagKeys) == 0 { 199 | return fmt.Errorf("At least 1 tag key is required if all=false") 200 | } 201 | 202 | if len(t.TagKeys) > 20 { 203 | return fmt.Errorf("At most 20 tag is required") 204 | } 205 | return nil 206 | } 207 | 208 | // UnTagResourceOut ... 209 | type UnTagResourceOut struct { 210 | Header http.Header 211 | } 212 | 213 | func (o UnTagResourceOut) String() string { 214 | b, err := json.MarshalIndent(o, "", printIndent) 215 | if err != nil { 216 | return "" 217 | } 218 | return string(b) 219 | } 220 | 221 | func (o UnTagResourceOut) GetRequestID() string { 222 | return GetRequestID(o.Header) 223 | } 224 | -------------------------------------------------------------------------------- /tag_test.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/suite" 8 | ) 9 | 10 | func TestTagStructs(t *testing.T) { 11 | suite.Run(t, new(TagStructsTestSuite)) 12 | } 13 | 14 | type TagStructsTestSuite struct { 15 | suite.Suite 16 | } 17 | 18 | func (s *TagStructsTestSuite) TestTagResource() { 19 | assert := s.Require() 20 | 21 | input := NewTagResourceInput("soureArn", map[string]string{}) 22 | assert.NotNil(input) 23 | assert.Equal("soureArn", *input.ResourceArn) 24 | assert.True(reflect.DeepEqual(map[string]string{}, input.Tags)) 25 | 26 | input.WithResourceArn("services/foo") 27 | assert.NotNil(input.ResourceArn) 28 | assert.Equal("services/foo", *input.ResourceArn) 29 | 30 | input.WithTags(map[string]string{"k": "v"}) 31 | assert.NotNil(input.Tags) 32 | assert.True(reflect.DeepEqual(map[string]string{ 33 | "k": "v", 34 | }, input.Tags)) 35 | } 36 | 37 | func (s *TagStructsTestSuite) TestUnTagResource() { 38 | assert := s.Require() 39 | 40 | input := NewUnTagResourceInput("soureArn") 41 | assert.NotNil(input) 42 | assert.Equal("soureArn", *input.ResourceArn) 43 | 44 | input.WithResourceArn("services/foo") 45 | assert.NotNil(input.ResourceArn) 46 | assert.Equal("services/foo", *input.ResourceArn) 47 | 48 | input.WithTagKeys([]string{"k2", "k2"}) 49 | assert.NotNil(input.TagKeys) 50 | assert.True(reflect.DeepEqual([]string{"k2", "k2"}, input.TagKeys)) 51 | 52 | input.WithAll(true) 53 | assert.Equal(true, *input.All) 54 | } 55 | 56 | func (s *TagStructsTestSuite) TestGetResourceTags() { 57 | assert := s.Require() 58 | 59 | input := NewGetResourceTagsInput("soureArn") 60 | assert.NotNil(input) 61 | assert.Equal("soureArn", *input.ResourceArn) 62 | 63 | input.WithResourceArn("services/foo") 64 | assert.NotNil(input.ResourceArn) 65 | assert.Equal("services/foo", *input.ResourceArn) 66 | } 67 | -------------------------------------------------------------------------------- /testCode/hello_world.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliyun/fc-go-sdk/3a1b2ede1e1e9ead26a9979f294588e8d39263a9/testCode/hello_world.zip -------------------------------------------------------------------------------- /testCode/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import logging 4 | HELLO_WORLD = b'Hello world!\n' 5 | 6 | # To enable the initializer feature (https://help.aliyun.com/document_detail/158208.html) 7 | # please implement the initializer function as below: 8 | # def initializer(context): 9 | # logger = logging.getLogger() 10 | # logger.info('initializing') 11 | 12 | 13 | def handler(environ, start_response): 14 | context = environ['fc.context'] 15 | request_uri = environ['fc.request_uri'] 16 | for k, v in environ.items(): 17 | if k.startswith('HTTP_'): 18 | # process custom request headers 19 | pass 20 | # do something here 21 | status = '200 OK' 22 | response_headers = [('Content-type', 'text/plain')] 23 | start_response(status, response_headers) 24 | return [HELLO_WORLD] -------------------------------------------------------------------------------- /time_trigger.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | // TimeTriggerConfig defines the time trigger config 4 | type TimeTriggerConfig struct { 5 | Payload *string `json:"payload"` 6 | CronExpression *string `json:"cronExpression"` 7 | Enable *bool `json:"enable"` 8 | } 9 | 10 | // NewTimeTriggerConfig creates an empty TimeTriggerConfig 11 | func NewTimeTriggerConfig() *TimeTriggerConfig { 12 | return &TimeTriggerConfig{} 13 | } 14 | 15 | func (ttc *TimeTriggerConfig) WithPayload(payload string) *TimeTriggerConfig { 16 | ttc.Payload = &payload 17 | return ttc 18 | } 19 | 20 | func (ttc *TimeTriggerConfig) WithCronExpression(cronExpression string) *TimeTriggerConfig { 21 | ttc.CronExpression = &cronExpression 22 | return ttc 23 | } 24 | 25 | func (ttc *TimeTriggerConfig) WithEnable(enable bool) *TimeTriggerConfig { 26 | ttc.Enable = &enable 27 | return ttc 28 | } 29 | -------------------------------------------------------------------------------- /types.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | type Header map[string]string 4 | 5 | type Query struct { 6 | Prefix *string 7 | StartKey *string 8 | NextToken *string 9 | Limit *int32 10 | Tags map[string]string 11 | } 12 | -------------------------------------------------------------------------------- /util.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "crypto/md5" 5 | "encoding/hex" 6 | "net/http" 7 | "net/url" 8 | ) 9 | 10 | //MD5 :Encoding MD5 11 | func MD5(b []byte) string { 12 | ctx := md5.New() 13 | ctx.Write(b) 14 | return hex.EncodeToString(ctx.Sum(nil)) 15 | } 16 | 17 | // HasPrefix check endpoint prefix 18 | func HasPrefix(s, prefix string) bool { 19 | return len(s) >= len(prefix) && s[0:len(prefix)] == prefix 20 | } 21 | 22 | // GetAccessPoint get correct endpoint and host 23 | func GetAccessPoint(endpointInput string) (endpoint, host string) { 24 | httpPrefix := "http://" 25 | httpsPrefix := "https://" 26 | if HasPrefix(endpointInput, httpPrefix) { 27 | host = endpointInput[len(httpPrefix):] 28 | return endpointInput, host 29 | } else if HasPrefix(endpointInput, httpsPrefix) { 30 | host = endpointInput[len(httpsPrefix):] 31 | return endpointInput, host 32 | } 33 | return httpPrefix + endpointInput, endpointInput 34 | } 35 | 36 | // IsBlank :check string pointer is nil or empty 37 | func IsBlank(s *string) bool { 38 | if s == nil { 39 | return true 40 | } 41 | if len(*s) == 0 { 42 | return true 43 | } 44 | return false 45 | } 46 | 47 | // GetRequestID from headers 48 | func GetRequestID(header http.Header) string { 49 | return header.Get(HTTPHeaderRequestID) 50 | } 51 | 52 | // GetErrorType get error type when call invocation 53 | func GetErrorType(header http.Header) string { 54 | return header.Get(HTTPHeaderFCErrorType) 55 | } 56 | 57 | // GetEtag get resource etag 58 | func GetEtag(header http.Header) string { 59 | return header.Get(HTTPHeaderEtag) 60 | } 61 | 62 | func pathEscape(s string) string { 63 | return url.PathEscape(s) 64 | } 65 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | "strconv" 9 | ) 10 | 11 | var ( 12 | ListDirectionBackward = "BACKWARD" 13 | ListDirectionForward = "FORWARD" 14 | ) 15 | 16 | type versionMetadata struct { 17 | VersionID *string `json:"versionId"` 18 | Description *string `json:"description"` 19 | CreatedTime *string `json:"createdTime"` 20 | LastModifiedTime *string `json:"lastModifiedTime"` 21 | } 22 | 23 | type ServiceVersionPublishObject struct { 24 | Description *string 25 | } 26 | 27 | type PublishServiceVersionInput struct { 28 | ServiceName *string 29 | ServiceVersionPublishObject 30 | IfMatch *string 31 | } 32 | 33 | func NewPublishServiceVersionInput(serviceName string) *PublishServiceVersionInput { 34 | return &PublishServiceVersionInput{ServiceName: &serviceName} 35 | } 36 | 37 | func (i *PublishServiceVersionInput) WithDescription(description string) *PublishServiceVersionInput { 38 | i.Description = &description 39 | return i 40 | } 41 | 42 | func (i *PublishServiceVersionInput) WithIfMatch(ifMatch string) *PublishServiceVersionInput { 43 | i.IfMatch = &ifMatch 44 | return i 45 | } 46 | 47 | func (i *PublishServiceVersionInput) GetQueryParams() url.Values { 48 | out := url.Values{} 49 | return out 50 | } 51 | 52 | func (i *PublishServiceVersionInput) GetPath() string { 53 | return fmt.Sprintf(versionsPath, pathEscape(*i.ServiceName)) 54 | } 55 | 56 | func (i *PublishServiceVersionInput) GetHeaders() Header { 57 | header := make(Header) 58 | if i.IfMatch != nil { 59 | header[ifMatch] = *i.IfMatch 60 | } 61 | return header 62 | } 63 | 64 | func (i *PublishServiceVersionInput) GetPayload() interface{} { 65 | return i.ServiceVersionPublishObject 66 | } 67 | 68 | func (i *PublishServiceVersionInput) Validate() error { 69 | if IsBlank(i.ServiceName) { 70 | return fmt.Errorf("Service name is required but not provided") 71 | } 72 | return nil 73 | } 74 | 75 | type PublishServiceVersionOutput struct { 76 | Header http.Header 77 | versionMetadata 78 | } 79 | 80 | func (o PublishServiceVersionOutput) String() string { 81 | b, err := json.MarshalIndent(o, "", printIndent) 82 | if err != nil { 83 | return "" 84 | } 85 | return string(b) 86 | } 87 | 88 | func (o PublishServiceVersionOutput) GetRequestID() string { 89 | return GetRequestID(o.Header) 90 | } 91 | 92 | func (o PublishServiceVersionOutput) GetEtag() string { 93 | return GetEtag(o.Header) 94 | } 95 | 96 | type ListServiceVersionsInput struct { 97 | ServiceName *string 98 | StartKey *string 99 | NextToken *string 100 | Limit *int32 101 | Direction *string 102 | } 103 | 104 | func NewListServiceVersionsInput(serviceName string) *ListServiceVersionsInput { 105 | return &ListServiceVersionsInput{ServiceName: &serviceName} 106 | } 107 | 108 | func (i *ListServiceVersionsInput) WithStartKey(startKey string) *ListServiceVersionsInput { 109 | i.StartKey = &startKey 110 | return i 111 | } 112 | 113 | func (i *ListServiceVersionsInput) WithNextToken(nextToken string) *ListServiceVersionsInput { 114 | i.NextToken = &nextToken 115 | return i 116 | } 117 | 118 | func (i *ListServiceVersionsInput) WithLimit(limit int32) *ListServiceVersionsInput { 119 | i.Limit = &limit 120 | return i 121 | } 122 | 123 | func (i *ListServiceVersionsInput) WithBackwardDirection() *ListServiceVersionsInput { 124 | i.Direction = &ListDirectionBackward 125 | return i 126 | } 127 | 128 | func (i *ListServiceVersionsInput) WithForwardDirection() *ListServiceVersionsInput { 129 | i.Direction = &ListDirectionForward 130 | return i 131 | } 132 | 133 | func (i *ListServiceVersionsInput) GetQueryParams() url.Values { 134 | out := url.Values{} 135 | 136 | if i.StartKey != nil { 137 | out.Set("startKey", *i.StartKey) 138 | } 139 | 140 | if i.NextToken != nil { 141 | out.Set("nextToken", *i.NextToken) 142 | } 143 | 144 | if i.Limit != nil { 145 | out.Set("limit", strconv.FormatInt(int64(*i.Limit), 10)) 146 | } 147 | 148 | if i.Direction != nil { 149 | out.Set("direction", *i.Direction) 150 | } 151 | 152 | return out 153 | } 154 | 155 | func (i *ListServiceVersionsInput) GetPath() string { 156 | return fmt.Sprintf(versionsPath, pathEscape(*i.ServiceName)) 157 | } 158 | 159 | func (i *ListServiceVersionsInput) GetHeaders() Header { 160 | return make(Header, 0) 161 | } 162 | 163 | func (i *ListServiceVersionsInput) GetPayload() interface{} { 164 | return nil 165 | } 166 | 167 | func (i *ListServiceVersionsInput) Validate() error { 168 | if IsBlank(i.ServiceName) { 169 | return fmt.Errorf("Service name is required but not provided") 170 | } 171 | return nil 172 | } 173 | 174 | type ListServiceVersionsOutput struct { 175 | Header http.Header 176 | Versions []*versionMetadata `json:"versions"` 177 | NextToken *string `json:"nextToken,omitempty"` 178 | Direction *string `json:"direction"` 179 | } 180 | 181 | func (o ListServiceVersionsOutput) String() string { 182 | b, err := json.MarshalIndent(o, "", printIndent) 183 | if err != nil { 184 | return "" 185 | } 186 | return string(b) 187 | } 188 | 189 | func (o ListServiceVersionsOutput) GetRequestID() string { 190 | return GetRequestID(o.Header) 191 | } 192 | 193 | type DeleteServiceVersionInput struct { 194 | ServiceName *string 195 | VersionID *string 196 | } 197 | 198 | func NewDeleteServiceVersionInput(serviceName string, versionID string) *DeleteServiceVersionInput { 199 | return &DeleteServiceVersionInput{ServiceName: &serviceName, VersionID: &versionID} 200 | } 201 | 202 | func (i *DeleteServiceVersionInput) GetQueryParams() url.Values { 203 | out := url.Values{} 204 | return out 205 | } 206 | 207 | func (i *DeleteServiceVersionInput) GetPath() string { 208 | return fmt.Sprintf(singleVersionPath, pathEscape(*i.ServiceName), pathEscape(*i.VersionID)) 209 | } 210 | 211 | func (i *DeleteServiceVersionInput) GetHeaders() Header { 212 | return make(Header, 0) 213 | } 214 | 215 | func (i *DeleteServiceVersionInput) GetPayload() interface{} { 216 | return nil 217 | } 218 | 219 | func (i *DeleteServiceVersionInput) Validate() error { 220 | if IsBlank(i.ServiceName) { 221 | return fmt.Errorf("Service name is required but not provided") 222 | } 223 | if IsBlank(i.VersionID) { 224 | return fmt.Errorf("Version ID is required but not provided") 225 | } 226 | return nil 227 | } 228 | 229 | type DeleteServiceVersionOutput struct { 230 | Header http.Header 231 | } 232 | 233 | func (o DeleteServiceVersionOutput) String() string { 234 | b, err := json.MarshalIndent(o, "", printIndent) 235 | if err != nil { 236 | return "" 237 | } 238 | return string(b) 239 | } 240 | 241 | func (o DeleteServiceVersionOutput) GetRequestID() string { 242 | return GetRequestID(o.Header) 243 | } 244 | 245 | -------------------------------------------------------------------------------- /zip.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "archive/zip" 5 | "io" 6 | "io/ioutil" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | ) 11 | 12 | // TempZipDir zips everything from source dir into a temporary zip file which doesn't include the source dir but its content. 13 | // Return the location of the temporary zip file. 14 | func TempZipDir(dir string) (string, error) { 15 | // Collect files to zip. 16 | fs, err := ioutil.ReadDir(dir) 17 | if err != nil { 18 | return "", err 19 | } 20 | files := []string{} 21 | for _, f := range fs { 22 | files = append(files, filepath.Join(dir, f.Name())) 23 | } 24 | return TmpZip(files) 25 | } 26 | 27 | // TmpZip everything from source file into a temporary zip file. 28 | // Return the location of the temporary zip file. 29 | func TmpZip(files []string) (string, error) { 30 | zipfile, err := ioutil.TempFile("", "fc_temp_file_") 31 | if err != nil { 32 | return "", err 33 | } 34 | 35 | archive := zip.NewWriter(zipfile) 36 | defer archive.Close() 37 | 38 | for _, source := range files { 39 | if err := compress(source, archive); err != nil { 40 | return "", err 41 | } 42 | } 43 | 44 | return zipfile.Name(), nil 45 | } 46 | 47 | // Zip everything from the source (either file/directory) recursively into target zip file. 48 | func Zip(files []string, target string) error { 49 | zipfile, err := os.Create(target) 50 | if err != nil { 51 | return err 52 | } 53 | defer zipfile.Close() 54 | 55 | archive := zip.NewWriter(zipfile) 56 | defer archive.Close() 57 | 58 | for _, f := range files { 59 | if err := compress(f, archive); err != nil { 60 | return err 61 | } 62 | } 63 | 64 | return nil 65 | } 66 | 67 | // Compress zips source file into archive file. 68 | func compress(source string, archive *zip.Writer) error { 69 | srcInfo, err := os.Stat(source) 70 | if err != nil { 71 | return err 72 | } 73 | 74 | return filepath.Walk(source, func(path string, info os.FileInfo, err error) error { 75 | if err != nil { 76 | return err 77 | } 78 | 79 | header, err := zip.FileInfoHeader(info) 80 | if err != nil { 81 | return err 82 | } 83 | 84 | if srcInfo.IsDir() { 85 | header.Name = filepath.Join(filepath.Base(source), strings.TrimPrefix(path, source)) 86 | } 87 | 88 | if info.IsDir() { 89 | header.Name += "/" 90 | } else { 91 | header.Method = zip.Deflate 92 | } 93 | 94 | writer, err := archive.CreateHeader(header) 95 | if err != nil { 96 | return err 97 | } 98 | 99 | if info.IsDir() { 100 | return nil 101 | } 102 | 103 | if info.Mode()&os.ModeSymlink != 0 { 104 | // handle symbol link file 105 | dest, err := os.Readlink(path) 106 | if err != nil { 107 | return err 108 | } 109 | _, err = writer.Write([]byte(dest)) 110 | return err 111 | } 112 | 113 | file, err := os.Open(path) 114 | if err != nil { 115 | return err 116 | } 117 | defer file.Close() 118 | _, err = io.Copy(writer, file) 119 | return err 120 | }) 121 | } 122 | 123 | // ZipDir zip up a directory and preserve symlinks and empty directories. 124 | func ZipDir(srcDir string, output io.Writer) error { 125 | zipWriter := zip.NewWriter(output) 126 | defer zipWriter.Close() 127 | 128 | // Convert the input dir path to absolute path if necessary. 129 | srcDir, err := filepath.Abs(srcDir) 130 | if err != nil { 131 | return err 132 | } 133 | 134 | return filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error { 135 | if err != nil { 136 | return err 137 | } 138 | header, err := zip.FileInfoHeader(info) 139 | if err != nil { 140 | return err 141 | } 142 | // handle the decode issue for windows : set default utf8. 143 | header.Flags |= 1 << 11 144 | relPath, err := filepath.Rel(srcDir, path) 145 | if err != nil { 146 | return err 147 | } 148 | // handle windows path issue: replace "\\" to "/" 149 | header.Name = filepath.ToSlash(relPath) 150 | if info.IsDir() { 151 | header.Name += "/" 152 | } else { 153 | header.Method = zip.Deflate 154 | } 155 | writer, err := zipWriter.CreateHeader(header) 156 | if err != nil { 157 | return err 158 | } 159 | if info.Mode()&os.ModeSymlink != 0 { 160 | dest, err := os.Readlink(path) 161 | if err != nil { 162 | return err 163 | } 164 | _, err = writer.Write([]byte(dest)) 165 | return err 166 | } 167 | if info.IsDir() { 168 | // dir need create one entry to avoid of setting default permission 169 | _, err = writer.Write([]byte("")) 170 | return err 171 | } 172 | 173 | file, err := os.Open(path) 174 | if err != nil { 175 | return err 176 | } 177 | defer file.Close() 178 | _, err = io.Copy(writer, file) 179 | return err 180 | }) 181 | } 182 | -------------------------------------------------------------------------------- /zip_test.go: -------------------------------------------------------------------------------- 1 | package fc 2 | 3 | import ( 4 | "testing" 5 | "os" 6 | "os/exec" 7 | "io/ioutil" 8 | "path/filepath" 9 | ) 10 | 11 | func TestZipEmptyDir(t *testing.T) { 12 | // Cleanup the last data to prevent from confliction. 13 | os.RemoveAll("/tmp/TestZipEmptyDir/") 14 | 15 | // Create directory with empty sub-directory. 16 | err := os.MkdirAll("/tmp/TestZipEmptyDir/src/empty", 0777) 17 | if err != nil { 18 | panic(err) 19 | } 20 | f, err := os.Create("/tmp/TestZipEmptyDir/src/t") 21 | if err != nil { 22 | panic(err) 23 | } 24 | f.Close() 25 | 26 | // Zip the directory. 27 | err = os.MkdirAll("/tmp/TestZipEmptyDir/dst", 0777) 28 | if err != nil { 29 | panic(err) 30 | } 31 | zip, err := os.Create("/tmp/TestZipEmptyDir/dst/empty.zip") 32 | defer zip.Close() 33 | err = ZipDir("/tmp/TestZipEmptyDir/src", zip) 34 | if err != nil { 35 | panic(err) 36 | } 37 | 38 | // Use system command to unzip the file. 39 | cmd := exec.Command("sh", "-c", "unzip /tmp/TestZipEmptyDir/dst/empty.zip") 40 | cmd.Dir = "/tmp/TestZipEmptyDir/dst/" 41 | _, err = cmd.CombinedOutput() 42 | if err != nil { 43 | t.Fatalf("%v", err) 44 | } 45 | 46 | f, err = os.Open("/tmp/TestZipEmptyDir/dst") 47 | entries, err := f.Readdir(-1) 48 | // 3 elems: zip file, empty dir and a file. 49 | if len(entries) != 3 { 50 | t.Fatalf("%v", entries) 51 | } 52 | f.Close() 53 | 54 | // Check the unzipped empty directory is valid. 55 | info, err := os.Stat("/tmp/TestZipEmptyDir/dst/empty") 56 | if err != nil { 57 | panic(err) 58 | } 59 | if !info.IsDir() { 60 | t.Fatalf("%v", info) 61 | } 62 | } 63 | 64 | func TestZipDirWithSymbolLinks(t *testing.T) { 65 | // Cleanup the last data to prevent from confliction. 66 | os.RemoveAll("./TestZipDirWithSymbolLinks/") 67 | 68 | // Create file and symbol links. 69 | err := os.MkdirAll("./TestZipDirWithSymbolLinks/src/", 0777) 70 | if err != nil { 71 | panic(err) 72 | } 73 | err = ioutil.WriteFile("./TestZipDirWithSymbolLinks/src/main.py", []byte("this is a file."), 0666) 74 | if err != nil { 75 | panic(err) 76 | } 77 | // Write link with absolute path. 78 | absPath, _ := filepath.Abs("./TestZipDirWithSymbolLinks/src/main.py") 79 | err = os.Symlink(absPath, "./TestZipDirWithSymbolLinks/src/symbol_link") 80 | if err != nil { 81 | panic(err) 82 | } 83 | 84 | // Zip the directory. 85 | err = os.MkdirAll("./TestZipDirWithSymbolLinks/dst", 0777) 86 | if err != nil { 87 | panic(err) 88 | } 89 | zip, err := os.Create("./TestZipDirWithSymbolLinks/dst/link.zip") 90 | defer zip.Close() 91 | err = ZipDir("./TestZipDirWithSymbolLinks/src", zip) 92 | if err != nil { 93 | panic(err) 94 | } 95 | 96 | // Use system command to unzip the file. 97 | cmd := exec.Command("sh", "-c", "unzip link.zip") 98 | cmd.Dir = "./TestZipDirWithSymbolLinks/dst/" 99 | out, err := cmd.CombinedOutput() 100 | if err != nil { 101 | t.Fatalf("%v: %s", err, out) 102 | } 103 | 104 | // Verify the file attributes. 105 | dir, err := os.Open("./TestZipDirWithSymbolLinks/dst") 106 | entries, err := dir.Readdir(-1) 107 | // 3 elems: zip file, file and its links. 108 | if len(entries) != 3 { 109 | t.Fatalf("%v", entries) 110 | } 111 | dir.Close() 112 | info, err := os.Lstat("./TestZipDirWithSymbolLinks/dst/symbol_link") 113 | if err != nil { 114 | panic(err) 115 | } 116 | if info.Mode() & os.ModeSymlink == 0 { 117 | t.Fatalf("%v", info) 118 | } 119 | 120 | // Verify the file and its symbol link. 121 | data, err := ioutil.ReadFile("./TestZipDirWithSymbolLinks/dst/main.py") 122 | if err != nil { 123 | panic(err) 124 | } 125 | if string(data) != "this is a file." { 126 | t.Fatalf("%s", string(data)) 127 | } 128 | linkData, err := ioutil.ReadFile("./TestZipDirWithSymbolLinks/dst/symbol_link") 129 | if err != nil { 130 | panic(err) 131 | } 132 | if string(linkData) != "this is a file." { 133 | t.Fatalf("%s", string(data)) 134 | } 135 | } 136 | --------------------------------------------------------------------------------