Merge pull request #116 from xanzy/svh/f-http-client
Introduce optional client configuration options
diff --git a/cloudstack/cloudstack.go b/cloudstack/cloudstack.go
index e3dcb4e..98f2014 100644
--- a/cloudstack/cloudstack.go
+++ b/cloudstack/cloudstack.go
@@ -46,6 +46,9 @@
return idRegex.MatchString(id)
}
+// ClientOption can be passed to new client functions to set custom options
+type ClientOption func(*CloudStackClient)
+
// OptionFunc can be passed to the courtesy helper functions to set additional parameters
type OptionFunc func(*CloudStackClient, interface{}) error
@@ -142,7 +145,7 @@
}
// Creates a new client for communicating with CloudStack
-func newClient(apiurl string, apikey string, secret string, async bool, verifyssl bool) *CloudStackClient {
+func newClient(apiurl string, apikey string, secret string, async bool, verifyssl bool, options ...ClientOption) *CloudStackClient {
jar, _ := cookiejar.New(nil)
cs := &CloudStackClient{
client: &http.Client{
@@ -169,6 +172,11 @@
options: []OptionFunc{},
timeout: 300,
}
+
+ for _, fn := range options {
+ fn(cs)
+ }
+
cs.APIDiscovery = NewAPIDiscoveryService(cs)
cs.Account = NewAccountService(cs)
cs.Address = NewAddressService(cs)
@@ -238,14 +246,15 @@
cs.VirtualMachine = NewVirtualMachineService(cs)
cs.Volume = NewVolumeService(cs)
cs.Zone = NewZoneService(cs)
+
return cs
}
// Default non-async client. So for async calls you need to implement and check the async job result yourself. When using
// HTTPS with a self-signed certificate to connect to your CloudStack API, you would probably want to set 'verifyssl' to
// false so the call ignores the SSL errors/warnings.
-func NewClient(apiurl string, apikey string, secret string, verifyssl bool) *CloudStackClient {
- cs := newClient(apiurl, apikey, secret, false, verifyssl)
+func NewClient(apiurl string, apikey string, secret string, verifyssl bool, options ...ClientOption) *CloudStackClient {
+ cs := newClient(apiurl, apikey, secret, false, verifyssl, options...)
return cs
}
@@ -253,8 +262,8 @@
// this client will wait until the async job is finished or until the configured AsyncTimeout is reached. When the async
// job finishes successfully it will return actual object received from the API and nil, but when the timout is
// reached it will return the initial object containing the async job ID for the running job and a warning.
-func NewAsyncClient(apiurl string, apikey string, secret string, verifyssl bool) *CloudStackClient {
- cs := newClient(apiurl, apikey, secret, true, verifyssl)
+func NewAsyncClient(apiurl string, apikey string, secret string, verifyssl bool, options ...ClientOption) *CloudStackClient {
+ cs := newClient(apiurl, apikey, secret, true, verifyssl, options...)
return cs
}
@@ -419,6 +428,15 @@
return nil, fmt.Errorf("Unable to extract the raw value from:\n\n%s\n\n", string(b))
}
+// WithAsyncTimeout takes a custom timeout to be used by the CloudStackClient
+func WithAsyncTimeout(timeout int64) ClientOption {
+ return func(cs *CloudStackClient) {
+ if timeout != 0 {
+ cs.timeout = timeout
+ }
+ }
+}
+
// DomainIDSetter is an interface that every type that can set a domain ID must implement
type DomainIDSetter interface {
SetDomainid(string)
@@ -447,6 +465,18 @@
}
}
+// WithHTTPClient takes a custom HTTP client to be used by the CloudStackClient
+func WithHTTPClient(client *http.Client) ClientOption {
+ return func(cs *CloudStackClient) {
+ if client != nil {
+ if client.Jar == nil {
+ client.Jar = cs.client.Jar
+ }
+ cs.client = client
+ }
+ }
+}
+
// ProjectIDSetter is an interface that every type that can set a project ID must implement
type ProjectIDSetter interface {
SetProjectid(string)
diff --git a/generate/generate.go b/generate/generate.go
index 36894d3..edbe6af 100644
--- a/generate/generate.go
+++ b/generate/generate.go
@@ -241,6 +241,9 @@
pn(" return idRegex.MatchString(id)")
pn("}")
pn("")
+ pn("// ClientOption can be passed to new client functions to set custom options")
+ pn("type ClientOption func(*CloudStackClient)")
+ pn("")
pn("// OptionFunc can be passed to the courtesy helper functions to set additional parameters")
pn("type OptionFunc func(*CloudStackClient, interface{}) error")
pn("")
@@ -271,7 +274,7 @@
pn("}")
pn("")
pn("// Creates a new client for communicating with CloudStack")
- pn("func newClient(apiurl string, apikey string, secret string, async bool, verifyssl bool) *CloudStackClient {")
+ pn("func newClient(apiurl string, apikey string, secret string, async bool, verifyssl bool, options ...ClientOption) *CloudStackClient {")
pn(" jar, _ := cookiejar.New(nil)")
pn(" cs := &CloudStackClient{")
pn(" client: &http.Client{")
@@ -298,17 +301,23 @@
pn(" options: []OptionFunc{},")
pn(" timeout: 300,")
pn(" }")
+ pn("")
+ pn(" for _, fn := range options {")
+ pn(" fn(cs)")
+ pn(" }")
+ pn("")
for _, s := range as.services {
pn(" cs.%s = New%s(cs)", strings.TrimSuffix(s.name, "Service"), s.name)
}
+ pn("")
pn(" return cs")
pn("}")
pn("")
pn("// Default non-async client. So for async calls you need to implement and check the async job result yourself. When using")
pn("// HTTPS with a self-signed certificate to connect to your CloudStack API, you would probably want to set 'verifyssl' to")
pn("// false so the call ignores the SSL errors/warnings.")
- pn("func NewClient(apiurl string, apikey string, secret string, verifyssl bool) *CloudStackClient {")
- pn(" cs := newClient(apiurl, apikey, secret, false, verifyssl)")
+ pn("func NewClient(apiurl string, apikey string, secret string, verifyssl bool, options ...ClientOption) *CloudStackClient {")
+ pn(" cs := newClient(apiurl, apikey, secret, false, verifyssl, options...)")
pn(" return cs")
pn("}")
pn("")
@@ -316,8 +325,8 @@
pn("// this client will wait until the async job is finished or until the configured AsyncTimeout is reached. When the async")
pn("// job finishes successfully it will return actual object received from the API and nil, but when the timout is")
pn("// reached it will return the initial object containing the async job ID for the running job and a warning.")
- pn("func NewAsyncClient(apiurl string, apikey string, secret string, verifyssl bool) *CloudStackClient {")
- pn(" cs := newClient(apiurl, apikey, secret, true, verifyssl)")
+ pn("func NewAsyncClient(apiurl string, apikey string, secret string, verifyssl bool, options ...ClientOption) *CloudStackClient {")
+ pn(" cs := newClient(apiurl, apikey, secret, true, verifyssl, options...)")
pn(" return cs")
pn("}")
pn("")
@@ -482,6 +491,15 @@
pn(" return nil, fmt.Errorf(\"Unable to extract the raw value from:\\n\\n%%s\\n\\n\", string(b))")
pn("}")
pn("")
+ pn("// WithAsyncTimeout takes a custom timeout to be used by the CloudStackClient")
+ pn("func WithAsyncTimeout(timeout int64) ClientOption {")
+ pn(" return func(cs *CloudStackClient) {")
+ pn(" if timeout != 0 {")
+ pn(" cs.timeout = timeout")
+ pn(" }")
+ pn(" }")
+ pn("}")
+ pn("")
pn("// DomainIDSetter is an interface that every type that can set a domain ID must implement")
pn("type DomainIDSetter interface {")
pn(" SetDomainid(string)")
@@ -510,6 +528,18 @@
pn(" }")
pn("}")
pn("")
+ pn("// WithHTTPClient takes a custom HTTP client to be used by the CloudStackClient")
+ pn("func WithHTTPClient(client *http.Client) ClientOption {")
+ pn(" return func(cs *CloudStackClient) {")
+ pn(" if client != nil {")
+ pn(" if client.Jar == nil {")
+ pn(" client.Jar = cs.client.Jar")
+ pn(" }")
+ pn(" cs.client = client")
+ pn(" }")
+ pn(" }")
+ pn("}")
+ pn("")
pn("// ProjectIDSetter is an interface that every type that can set a project ID must implement")
pn("type ProjectIDSetter interface {")
pn(" SetProjectid(string)")