Skip to content
This repository was archived by the owner on Mar 22, 2018. It is now read-only.

Commit 10b2e2e

Browse files
committed
Merge branch 'master' into util-freebsd
2 parents fc99c7a + 1c34b0a commit 10b2e2e

8 files changed

Lines changed: 332 additions & 22 deletions

File tree

pkg/cloudprovider/providers/openstack/BUILD

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package(default_visibility = ["//visibility:public"])
22

3-
licenses(["notice"])
4-
53
load(
64
"@io_bazel_rules_go//go:def.bzl",
75
"go_library",
@@ -20,7 +18,6 @@ go_library(
2018
"openstack_routes.go",
2119
"openstack_volumes.go",
2220
],
23-
tags = ["automanaged"],
2421
deps = [
2522
"//pkg/api/v1/helper:go_default_library",
2623
"//pkg/api/v1/service:go_default_library",
@@ -73,7 +70,6 @@ go_test(
7370
"openstack_test.go",
7471
],
7572
library = ":go_default_library",
76-
tags = ["automanaged"],
7773
deps = [
7874
"//pkg/cloudprovider:go_default_library",
7975
"//vendor/github.com/gophercloud/gophercloud:go_default_library",

pkg/cloudprovider/providers/openstack/openstack.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,11 @@ func (os *OpenStack) ScrubDNS(nameServers, searches []string) ([]string, []strin
458458
return nameServers, searches
459459
}
460460

461+
// HasClusterID returns true if the cluster has a clusterID
462+
func (os *OpenStack) HasClusterID() bool {
463+
return true
464+
}
465+
461466
func (os *OpenStack) LoadBalancer() (cloudprovider.LoadBalancer, bool) {
462467
glog.V(4).Info("openstack.LoadBalancer() called")
463468

pkg/cloudprovider/providers/openstack/openstack_client.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func (os *OpenStack) NewNetworkV2() (*gophercloud.ServiceClient, error) {
2828
Region: os.region,
2929
})
3030
if err != nil {
31-
glog.Warningf("Failed to find network v2 endpoint: %v", err)
31+
glog.Warningf("Failed to find network v2 endpoint for region %s: %v", os.region, err)
3232
return nil, err
3333
}
3434
return network, nil
@@ -39,7 +39,7 @@ func (os *OpenStack) NewComputeV2() (*gophercloud.ServiceClient, error) {
3939
Region: os.region,
4040
})
4141
if err != nil {
42-
glog.Warningf("Failed to find compute v2 endpoint: %v", err)
42+
glog.Warningf("Failed to find compute v2 endpoint for region %s: %v", os.region, err)
4343
return nil, err
4444
}
4545
return compute, nil
@@ -50,7 +50,7 @@ func (os *OpenStack) NewBlockStorageV1() (*gophercloud.ServiceClient, error) {
5050
Region: os.region,
5151
})
5252
if err != nil {
53-
glog.Errorf("Unable to initialize cinder v1 client for region: %s", os.region)
53+
glog.Errorf("Unable to initialize cinder v1 client for region %s: %v", os.region, err)
5454
return nil, err
5555
}
5656
return storage, nil
@@ -61,7 +61,7 @@ func (os *OpenStack) NewBlockStorageV2() (*gophercloud.ServiceClient, error) {
6161
Region: os.region,
6262
})
6363
if err != nil {
64-
glog.Errorf("Unable to initialize cinder v2 client for region: %s", os.region)
64+
glog.Errorf("Unable to initialize cinder v2 client for region %s: %v", os.region, err)
6565
return nil, err
6666
}
6767
return storage, nil

pkg/cloudprovider/providers/openstack/openstack_volumes.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,7 @@ func (os *OpenStack) AttachDisk(instanceID, volumeID string) (string, error) {
215215
if err != nil {
216216
return "", err
217217
}
218-
if volume.Status != VolumeAvailableStatus {
219-
errmsg := fmt.Sprintf("volume %s status is %s, not %s, can not be attached to instance %s.", volume.Name, volume.Status, VolumeAvailableStatus, instanceID)
220-
glog.Errorf(errmsg)
221-
return "", errors.New(errmsg)
222-
}
218+
223219
cClient, err := os.NewComputeV2()
224220
if err != nil {
225221
return "", err
@@ -230,11 +226,9 @@ func (os *OpenStack) AttachDisk(instanceID, volumeID string) (string, error) {
230226
glog.V(4).Infof("Disk %s is already attached to instance %s", volumeID, instanceID)
231227
return volume.ID, nil
232228
}
233-
glog.V(2).Infof("Disk %s is attached to a different instance (%s), detaching", volumeID, volume.AttachedServerId)
234-
err = os.DetachDisk(volume.AttachedServerId, volumeID)
235-
if err != nil {
236-
return "", err
237-
}
229+
errmsg := fmt.Sprintf("Disk %s is attached to a different instance (%s)", volumeID, volume.AttachedServerId)
230+
glog.V(2).Infof(errmsg)
231+
return "", errors.New(errmsg)
238232
}
239233

240234
startTime := time.Now()
@@ -258,6 +252,12 @@ func (os *OpenStack) DetachDisk(instanceID, volumeID string) error {
258252
if err != nil {
259253
return err
260254
}
255+
if volume.Status == VolumeAvailableStatus {
256+
// "available" is fine since that means the volume is detached from instance already.
257+
glog.V(2).Infof("volume: %s has been detached from compute: %s ", volume.ID, instanceID)
258+
return nil
259+
}
260+
261261
if volume.Status != VolumeInUseStatus {
262262
errmsg := fmt.Sprintf("can not detach volume %s, its status is %s.", volume.Name, volume.Status)
263263
glog.Errorf(errmsg)

pkg/volume/cinder/BUILD

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package(default_visibility = ["//visibility:public"])
22

3-
licenses(["notice"])
4-
53
load(
64
"@io_bazel_rules_go//go:def.bzl",
75
"go_library",
@@ -16,7 +14,6 @@ go_library(
1614
"cinder_util.go",
1715
"doc.go",
1816
],
19-
tags = ["automanaged"],
2017
deps = [
2118
"//pkg/cloudprovider:go_default_library",
2219
"//pkg/cloudprovider/providers/openstack:go_default_library",
@@ -47,7 +44,6 @@ go_test(
4744
"cinder_test.go",
4845
],
4946
library = ":go_default_library",
50-
tags = ["automanaged"],
5147
deps = [
5248
"//pkg/cloudprovider:go_default_library",
5349
"//pkg/util/mount:go_default_library",
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package(default_visibility = ["//visibility:public"])
2+
3+
load(
4+
"@io_bazel_rules_go//go:def.bzl",
5+
"go_library",
6+
"go_test",
7+
)
8+
9+
go_test(
10+
name = "go_default_test",
11+
srcs = ["openstack_test.go"],
12+
library = ":go_default_library",
13+
)
14+
15+
go_library(
16+
name = "go_default_library",
17+
srcs = ["openstack.go"],
18+
deps = [
19+
"//vendor/github.com/golang/glog:go_default_library",
20+
"//vendor/github.com/gophercloud/gophercloud/openstack:go_default_library",
21+
"//vendor/k8s.io/client-go/rest:go_default_library",
22+
],
23+
)
24+
25+
filegroup(
26+
name = "package-srcs",
27+
srcs = glob(["**"]),
28+
tags = ["automanaged"],
29+
visibility = ["//visibility:private"],
30+
)
31+
32+
filegroup(
33+
name = "all-srcs",
34+
srcs = [":package-srcs"],
35+
tags = ["automanaged"],
36+
)
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
Copyright 2017 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package openstack
18+
19+
import (
20+
"fmt"
21+
"net/http"
22+
"sync"
23+
"time"
24+
25+
"github.com/golang/glog"
26+
"github.com/gophercloud/gophercloud/openstack"
27+
28+
restclient "k8s.io/client-go/rest"
29+
)
30+
31+
func init() {
32+
if err := restclient.RegisterAuthProviderPlugin("openstack", newOpenstackAuthProvider); err != nil {
33+
glog.Fatalf("Failed to register openstack auth plugin: %s", err)
34+
}
35+
}
36+
37+
// DefaultTTLDuration is the time before a token gets expired.
38+
const DefaultTTLDuration = 10 * time.Minute
39+
40+
// openstackAuthProvider is an authprovider for openstack. this provider reads
41+
// the environment variables to determine the client identity, and generates a
42+
// token which will be inserted into the request header later.
43+
type openstackAuthProvider struct {
44+
ttl time.Duration
45+
46+
tokenGetter TokenGetter
47+
}
48+
49+
// TokenGetter returns a bearer token that can be inserted into request.
50+
type TokenGetter interface {
51+
Token() (string, error)
52+
}
53+
54+
type tokenGetter struct{}
55+
56+
// Token creates a token by authenticate with keystone.
57+
func (*tokenGetter) Token() (string, error) {
58+
options, err := openstack.AuthOptionsFromEnv()
59+
if err != nil {
60+
return "", fmt.Errorf("failed to read openstack env vars: %s", err)
61+
}
62+
client, err := openstack.AuthenticatedClient(options)
63+
if err != nil {
64+
return "", fmt.Errorf("authentication failed: %s", err)
65+
}
66+
return client.TokenID, nil
67+
}
68+
69+
// cachedGetter caches a token until it gets expired, after the expiration, it will
70+
// generate another token and cache it.
71+
type cachedGetter struct {
72+
mutex sync.Mutex
73+
tokenGetter TokenGetter
74+
75+
token string
76+
born time.Time
77+
ttl time.Duration
78+
}
79+
80+
// Token returns the current available token, create a new one if expired.
81+
func (c *cachedGetter) Token() (string, error) {
82+
c.mutex.Lock()
83+
defer c.mutex.Unlock()
84+
85+
var err error
86+
// no token or exceeds the TTL
87+
if c.token == "" || time.Now().Sub(c.born) > c.ttl {
88+
c.token, err = c.tokenGetter.Token()
89+
if err != nil {
90+
return "", fmt.Errorf("failed to get token: %s", err)
91+
}
92+
c.born = time.Now()
93+
}
94+
return c.token, nil
95+
}
96+
97+
// tokenRoundTripper implements the RoundTripper interface: adding the bearer token
98+
// into the request header.
99+
type tokenRoundTripper struct {
100+
http.RoundTripper
101+
102+
tokenGetter TokenGetter
103+
}
104+
105+
// RoundTrip adds the bearer token into the request.
106+
func (t *tokenRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
107+
// if the authorization header already present, use it.
108+
if req.Header.Get("Authorization") != "" {
109+
return t.RoundTripper.RoundTrip(req)
110+
}
111+
112+
token, err := t.tokenGetter.Token()
113+
if err == nil {
114+
req.Header.Set("Authorization", "Bearer "+token)
115+
} else {
116+
glog.V(4).Infof("failed to get token: %s", err)
117+
}
118+
119+
return t.RoundTripper.RoundTrip(req)
120+
}
121+
122+
// newOpenstackAuthProvider creates an auth provider which works with openstack
123+
// environment.
124+
func newOpenstackAuthProvider(clusterAddress string, config map[string]string, persister restclient.AuthProviderConfigPersister) (restclient.AuthProvider, error) {
125+
var ttlDuration time.Duration
126+
var err error
127+
128+
ttl, found := config["ttl"]
129+
if !found {
130+
ttlDuration = DefaultTTLDuration
131+
// persist to config
132+
config["ttl"] = ttlDuration.String()
133+
if err = persister.Persist(config); err != nil {
134+
return nil, fmt.Errorf("failed to persist config: %s", err)
135+
}
136+
} else {
137+
ttlDuration, err = time.ParseDuration(ttl)
138+
if err != nil {
139+
return nil, fmt.Errorf("failed to parse ttl config: %s", err)
140+
}
141+
}
142+
143+
// TODO: read/persist client configuration(OS_XXX env vars) in config
144+
145+
return &openstackAuthProvider{
146+
ttl: ttlDuration,
147+
tokenGetter: &tokenGetter{},
148+
}, nil
149+
}
150+
151+
func (oap *openstackAuthProvider) WrapTransport(rt http.RoundTripper) http.RoundTripper {
152+
return &tokenRoundTripper{
153+
RoundTripper: rt,
154+
tokenGetter: &cachedGetter{
155+
tokenGetter: oap.tokenGetter,
156+
ttl: oap.ttl,
157+
},
158+
}
159+
}
160+
161+
func (oap *openstackAuthProvider) Login() error { return nil }

0 commit comments

Comments
 (0)