Skip to content
This repository has been archived by the owner on Jul 26, 2021. It is now read-only.

Commit

Permalink
Merge pull request #116 from xanzy/svh/f-http-client
Browse files Browse the repository at this point in the history
Introduce optional client configuration options
  • Loading branch information
svanharmelen authored Jun 7, 2019
2 parents 42f262b + ca5ab20 commit 47f3e6c
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 10 deletions.
40 changes: 35 additions & 5 deletions cloudstack/cloudstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ func IsID(id string) bool {
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

Expand Down Expand Up @@ -142,7 +145,7 @@ type CloudStackClient struct {
}

// 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{
Expand All @@ -169,6 +172,11 @@ func newClient(apiurl string, apikey string, secret string, async bool, verifyss
options: []OptionFunc{},
timeout: 300,
}

for _, fn := range options {
fn(cs)
}

cs.APIDiscovery = NewAPIDiscoveryService(cs)
cs.Account = NewAccountService(cs)
cs.Address = NewAddressService(cs)
Expand Down Expand Up @@ -238,23 +246,24 @@ func newClient(apiurl string, apikey string, secret string, async bool, verifyss
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
}

// For sync API calls this client behaves exactly the same as a standard client call, but for async API calls
// 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
}

Expand Down Expand Up @@ -419,6 +428,15 @@ func getRawValue(b json.RawMessage) (json.RawMessage, error) {
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)
Expand Down Expand Up @@ -447,6 +465,18 @@ func WithDomain(domain string) OptionFunc {
}
}

// 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)
Expand Down
40 changes: 35 additions & 5 deletions generate/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@ func (as *allServices) GeneralCode() ([]byte, error) {
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("")
Expand Down Expand Up @@ -271,7 +274,7 @@ func (as *allServices) GeneralCode() ([]byte, error) {
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{")
Expand All @@ -298,26 +301,32 @@ func (as *allServices) GeneralCode() ([]byte, error) {
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("")
pn("// For sync API calls this client behaves exactly the same as a standard client call, but for async API calls")
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("")
Expand Down Expand Up @@ -482,6 +491,15 @@ func (as *allServices) GeneralCode() ([]byte, error) {
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)")
Expand Down Expand Up @@ -510,6 +528,18 @@ func (as *allServices) GeneralCode() ([]byte, error) {
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)")
Expand Down

0 comments on commit 47f3e6c

Please sign in to comment.