@@ -15,7 +15,10 @@ limitations under the License.
15
15
package gcecloudprovider
16
16
17
17
import (
18
+ "context"
18
19
"fmt"
20
+ "golang.org/x/oauth2/google"
21
+ "gopkg.in/gcfg.v1"
19
22
"net/http"
20
23
"os"
21
24
"runtime"
@@ -24,9 +27,8 @@ import (
24
27
"cloud.google.com/go/compute/metadata"
25
28
"github.com/golang/glog"
26
29
"golang.org/x/oauth2"
27
- "golang.org/x/oauth2/google"
28
30
beta "google.golang.org/api/compute/v0.beta"
29
- compute "google.golang.org/api/compute/v1"
31
+ "google.golang.org/api/compute/v1"
30
32
"google.golang.org/api/googleapi"
31
33
"k8s.io/apimachinery/pkg/util/wait"
32
34
)
@@ -57,20 +59,44 @@ type CloudProvider struct {
57
59
58
60
var _ GCECompute = & CloudProvider {}
59
61
60
- func CreateCloudProvider (vendorVersion string ) (* CloudProvider , error ) {
61
- svc , err := createCloudService (vendorVersion )
62
+ type ConfigFile struct {
63
+ Global ConfigGlobal `gcfg:"global"`
64
+ }
65
+
66
+ type ConfigGlobal struct {
67
+ TokenURL string `gcfg:"token-url"`
68
+ TokenBody string `gcfg:"token-body"`
69
+ ProjectId string `gcfg:"project-id"`
70
+ }
71
+
72
+ func CreateCloudProvider (vendorVersion string , configPath string ) (* CloudProvider , error ) {
73
+ configFile , err := readConfig (configPath )
74
+ if err != nil {
75
+ return nil , err
76
+ }
77
+ // At this point configFile could still be nil.
78
+ // Any following code that uses configFile should handle nil pointer gracefully.
79
+
80
+ glog .V (1 ).Infof ("Using GCE provider config %+v" , configFile )
81
+
82
+ tokenSource , err := generateTokenSource (configFile )
83
+ if err != nil {
84
+ return nil , err
85
+ }
86
+
87
+ svc , err := createCloudService (vendorVersion , tokenSource )
62
88
if err != nil {
63
89
return nil , err
64
90
}
65
91
66
- betasvc , err := createBetaCloudService (vendorVersion )
92
+ betasvc , err := createBetaCloudService (vendorVersion , tokenSource )
67
93
if err != nil {
68
94
return nil , err
69
95
}
70
96
71
- project , zone , err := getProjectAndZoneFromMetadata ( )
97
+ project , zone , err := getProjectAndZone ( configFile )
72
98
if err != nil {
73
- return nil , fmt .Errorf ("Failed getting Project and Zone from Metadata server : %v" , err )
99
+ return nil , fmt .Errorf ("Failed getting Project and Zone: %v" , err )
74
100
}
75
101
76
102
return & CloudProvider {
@@ -83,8 +109,55 @@ func CreateCloudProvider(vendorVersion string) (*CloudProvider, error) {
83
109
84
110
}
85
111
86
- func createBetaCloudService (vendorVersion string ) (* beta.Service , error ) {
87
- client , err := newDefaultOauthClient ()
112
+ func generateTokenSource (configFile * ConfigFile ) (oauth2.TokenSource , error ) {
113
+
114
+ if configFile != nil && configFile .Global .TokenURL != "" && configFile .Global .TokenURL != "nil" {
115
+ // configFile.Global.TokenURL is defined
116
+ // Use AltTokenSource
117
+
118
+ tokenSource := NewAltTokenSource (configFile .Global .TokenURL , configFile .Global .TokenBody )
119
+ glog .V (4 ).Infof ("Using AltTokenSource %#v" , tokenSource )
120
+ return tokenSource , nil
121
+ }
122
+
123
+ // Use DefaultTokenSource
124
+
125
+ tokenSource , err := google .DefaultTokenSource (
126
+ context .Background (),
127
+ compute .CloudPlatformScope ,
128
+ compute .ComputeScope )
129
+
130
+ // DefaultTokenSource relies on GOOGLE_APPLICATION_CREDENTIALS env var being set.
131
+ if gac , ok := os .LookupEnv ("GOOGLE_APPLICATION_CREDENTIALS" ); ok {
132
+ glog .V (4 ).Infof ("GOOGLE_APPLICATION_CREDENTIALS env var set %v" , gac )
133
+ } else {
134
+ glog .Warningf ("GOOGLE_APPLICATION_CREDENTIALS env var not set" )
135
+ }
136
+ glog .V (4 ).Infof ("Using DefaultTokenSource %#v" , tokenSource )
137
+
138
+ return tokenSource , err
139
+ }
140
+
141
+ func readConfig (configPath string ) (* ConfigFile , error ) {
142
+ if configPath == "" {
143
+ return nil , nil
144
+ }
145
+
146
+ reader , err := os .Open (configPath )
147
+ if err != nil {
148
+ return nil , fmt .Errorf ("couldn't open cloud provider configuration at %s: %v" , configPath , err )
149
+ }
150
+ defer reader .Close ()
151
+
152
+ cfg := & ConfigFile {}
153
+ if err := gcfg .FatalOnly (gcfg .ReadInto (cfg , reader )); err != nil {
154
+ return nil , fmt .Errorf ("couldn't read cloud provider configuration at %s: %v" , configPath , err )
155
+ }
156
+ return cfg , nil
157
+ }
158
+
159
+ func createBetaCloudService (vendorVersion string , tokenSource oauth2.TokenSource ) (* beta.Service , error ) {
160
+ client , err := newOauthClient (tokenSource )
88
161
if err != nil {
89
162
return nil , err
90
163
}
@@ -96,13 +169,13 @@ func createBetaCloudService(vendorVersion string) (*beta.Service, error) {
96
169
return service , nil
97
170
}
98
171
99
- func createCloudService (vendorVersion string ) (* compute.Service , error ) {
100
- svc , err := createCloudServiceWithDefaultServiceAccount (vendorVersion )
172
+ func createCloudService (vendorVersion string , tokenSource oauth2. TokenSource ) (* compute.Service , error ) {
173
+ svc , err := createCloudServiceWithDefaultServiceAccount (vendorVersion , tokenSource )
101
174
return svc , err
102
175
}
103
176
104
- func createCloudServiceWithDefaultServiceAccount (vendorVersion string ) (* compute.Service , error ) {
105
- client , err := newDefaultOauthClient ( )
177
+ func createCloudServiceWithDefaultServiceAccount (vendorVersion string , tokenSource oauth2. TokenSource ) (* compute.Service , error ) {
178
+ client , err := newOauthClient ( tokenSource )
106
179
if err != nil {
107
180
return nil , err
108
181
}
@@ -114,22 +187,7 @@ func createCloudServiceWithDefaultServiceAccount(vendorVersion string) (*compute
114
187
return service , nil
115
188
}
116
189
117
- func newDefaultOauthClient () (* http.Client , error ) {
118
- // No compute token source, fallback on default
119
- tokenSource , err := google .DefaultTokenSource (
120
- oauth2 .NoContext ,
121
- compute .CloudPlatformScope ,
122
- compute .ComputeScope )
123
- if gac , ok := os .LookupEnv ("GOOGLE_APPLICATION_CREDENTIALS" ); ok {
124
- glog .V (4 ).Infof ("GOOGLE_APPLICATION_CREDENTIALS env var set %v" , gac )
125
- } else {
126
- glog .Warningf ("GOOGLE_APPLICATION_CREDENTIALS env var not set" )
127
- }
128
- glog .V (4 ).Infof ("Using DefaultTokenSource %#v" , tokenSource )
129
- if err != nil {
130
- return nil , err
131
- }
132
-
190
+ func newOauthClient (tokenSource oauth2.TokenSource ) (* http.Client , error ) {
133
191
if err := wait .PollImmediate (5 * time .Second , 30 * time .Second , func () (bool , error ) {
134
192
if _ , err := tokenSource .Token (); err != nil {
135
193
glog .Errorf ("error fetching initial token: %v" , err )
@@ -140,18 +198,32 @@ func newDefaultOauthClient() (*http.Client, error) {
140
198
return nil , err
141
199
}
142
200
143
- return oauth2 .NewClient (oauth2 . NoContext , tokenSource ), nil
201
+ return oauth2 .NewClient (context . Background () , tokenSource ), nil
144
202
}
145
203
146
- func getProjectAndZoneFromMetadata () (string , string , error ) {
204
+ func getProjectAndZone (config * ConfigFile ) (string , string , error ) {
205
+ var err error
206
+
147
207
zone , err := metadata .Zone ()
148
208
if err != nil {
149
209
return "" , "" , err
150
210
}
151
- projectID , err := metadata .ProjectID ()
152
- if err != nil {
153
- return "" , "" , err
211
+
212
+ var projectID string
213
+ if config == nil || config .Global .ProjectId == "" {
214
+ // Project ID is not available from the local GCE cloud provider config file.
215
+ // This could happen if the driver is not running in the master VM.
216
+ // Defaulting to project ID from the Metadata server.
217
+ projectID , err = metadata .ProjectID ()
218
+ if err != nil {
219
+ return "" , "" , err
220
+ }
221
+ glog .V (4 ).Infof ("Using GCP project ID from the Metadata server: %q" , projectID )
222
+ } else {
223
+ projectID = config .Global .ProjectId
224
+ glog .V (4 ).Infof ("Using GCP project ID from the local GCE cloud provider config file: %q" , projectID )
154
225
}
226
+
155
227
return projectID , zone , nil
156
228
}
157
229
0 commit comments