@@ -35,37 +35,38 @@ type Client interface {
35
35
ZoneIFace
36
36
IsoNetworkIface
37
37
UserCredIFace
38
+ NewClientFromSpec (Config ) (Client , error )
38
39
}
39
40
40
41
type client struct {
41
42
cs * cloudstack.CloudStackClient
42
43
csAsync * cloudstack.CloudStackClient
44
+ config Config
43
45
}
44
46
45
47
// cloud-config ini structure.
46
- type config struct {
48
+ type Config struct {
47
49
APIURL string `ini:"api-url"`
48
50
APIKey string `ini:"api-key"`
49
51
SecretKey string `ini:"secret-key"`
50
52
VerifySSL bool `ini:"verify-ssl"`
51
53
}
52
54
53
55
func NewClient (ccPath string ) (Client , error ) {
54
- c := & client {}
55
- cfg := & config {VerifySSL : true }
56
+ c := & client {config : Config {VerifySSL : true }}
56
57
if rawCfg , err := ini .Load (ccPath ); err != nil {
57
58
return nil , errors .Wrapf (err , "reading config at path %s:" , ccPath )
58
59
} else if g := rawCfg .Section ("Global" ); len (g .Keys ()) == 0 {
59
60
return nil , errors .New ("section Global not found" )
60
- } else if err = rawCfg .Section ("Global" ).StrictMapTo (cfg ); err != nil {
61
+ } else if err = rawCfg .Section ("Global" ).StrictMapTo (& c . config ); err != nil {
61
62
return nil , errors .Wrapf (err , "parsing [Global] section from config at path %s:" , ccPath )
62
63
}
63
64
64
65
// The client returned from NewAsyncClient works in a synchronous way. On the other hand,
65
66
// a client returned from NewClient works in an asynchronous way. Dive into the constructor definition
66
67
// comments for more details
67
- c .cs = cloudstack .NewAsyncClient (cfg . APIURL , cfg . APIKey , cfg . SecretKey , cfg .VerifySSL )
68
- c .csAsync = cloudstack .NewClient (cfg . APIURL , cfg . APIKey , cfg . SecretKey , cfg .VerifySSL )
68
+ c .cs = cloudstack .NewAsyncClient (c . config . APIURL , c . config . APIKey , c . config . SecretKey , c . config .VerifySSL )
69
+ c .csAsync = cloudstack .NewClient (c . config . APIURL , c . config . APIKey , c . config . SecretKey , c . config .VerifySSL )
69
70
70
71
_ , err := c .cs .APIDiscovery .ListApis (c .cs .APIDiscovery .NewListApisParams ())
71
72
if err != nil && strings .Contains (strings .ToLower (err .Error ()), "i/o timeout" ) {
@@ -74,6 +75,29 @@ func NewClient(ccPath string) (Client, error) {
74
75
return c , errors .Wrap (err , "checking CloudStack API Client connectivity:" )
75
76
}
76
77
78
+ // NewClientFromSpec generates a new client from an existing client.
79
+ // Unless the passed config contains a new API URL the original one will be used.
80
+ // VerifySSL will be set to true if either the old or new configs is true.
81
+ func (origC * client ) NewClientFromSpec (cfg Config ) (Client , error ) {
82
+ newC := & client {config : cfg }
83
+ newC .config .VerifySSL = cfg .VerifySSL || origC .config .VerifySSL // Prefer the most secure setting given.
84
+ if newC .config .APIURL == "" {
85
+ newC .config .APIURL = origC .config .APIURL
86
+ }
87
+
88
+ // The client returned from NewAsyncClient works in a synchronous way. On the other hand,
89
+ // a client returned from NewClient works in an asynchronous way. Dive into the constructor definition
90
+ // comments for more details
91
+ newC .cs = cloudstack .NewAsyncClient (newC .config .APIURL , newC .config .APIKey , newC .config .SecretKey , newC .config .VerifySSL )
92
+ newC .csAsync = cloudstack .NewClient (newC .config .APIURL , newC .config .APIKey , newC .config .SecretKey , newC .config .VerifySSL )
93
+
94
+ _ , err := newC .cs .APIDiscovery .ListApis (newC .cs .APIDiscovery .NewListApisParams ())
95
+ if err != nil && strings .Contains (strings .ToLower (err .Error ()), "i/o timeout" ) {
96
+ return newC , errors .Wrap (err , "timeout while checking CloudStack API Client connectivity" )
97
+ }
98
+ return newC , errors .Wrap (err , "checking CloudStack API Client connectivity:" )
99
+ }
100
+
77
101
func NewClientFromCSAPIClient (cs * cloudstack.CloudStackClient ) Client {
78
102
c := & client {cs : cs , csAsync : cs }
79
103
return c
0 commit comments