Skip to content

Commit 1727120

Browse files
batikanuSebastian Florek
authored andcommitted
Implement persistent volume backend (#1091)
1 parent d2d9a9c commit 1727120

File tree

8 files changed

+365
-0
lines changed

8 files changed

+365
-0
lines changed

src/app/backend/handler/apihandler.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/kubernetes/dashboard/src/app/backend/resource/node"
3535
"github.com/kubernetes/dashboard/src/app/backend/resource/petset"
3636
"github.com/kubernetes/dashboard/src/app/backend/resource/pod"
37+
"github.com/kubernetes/dashboard/src/app/backend/resource/persistentvolume"
3738
"github.com/kubernetes/dashboard/src/app/backend/resource/replicaset"
3839
"github.com/kubernetes/dashboard/src/app/backend/resource/replicationcontroller"
3940
"github.com/kubernetes/dashboard/src/app/backend/resource/secret"
@@ -366,6 +367,15 @@ func CreateHTTPAPIHandler(client *clientK8s.Client, heapsterClient client.Heapst
366367
apiV1Ws.Route(
367368
apiV1Ws.PUT("/{kind}/namespace/{namespace}/name/{name}").
368369
To(apiHandler.handlePutResource))
370+
371+
apiV1Ws.Route(
372+
apiV1Ws.GET("/persistentvolume").
373+
To(apiHandler.handleGetPersistentVolumeList).
374+
Writes(persistentvolume.PersistentVolumeList{}))
375+
apiV1Ws.Route(
376+
apiV1Ws.GET("/persistentvolume/{persistentvolume}").
377+
To(apiHandler.handleGetPersistentVolumeDetail).
378+
Writes(persistentvolume.PersistentVolumeDetail{}))
369379
return wsContainer
370380
}
371381

@@ -946,6 +956,26 @@ func (apiHandler *APIHandler) handleGetConfigMapDetail(request *restful.Request,
946956
response.WriteHeaderAndEntity(http.StatusCreated, result)
947957
}
948958

959+
func (apiHandler *APIHandler) handleGetPersistentVolumeList(request *restful.Request, response *restful.Response) {
960+
pagination := parsePaginationPathParameter(request)
961+
result, err := persistentvolume.GetPersistentVolumeList(apiHandler.client, pagination)
962+
if err != nil {
963+
handleInternalError(response, err)
964+
return
965+
}
966+
response.WriteHeaderAndEntity(http.StatusOK, result)
967+
}
968+
969+
func (apiHandler *APIHandler) handleGetPersistentVolumeDetail(request *restful.Request, response *restful.Response) {
970+
name := request.PathParameter("persistentvolume")
971+
result, err := persistentvolume.GetPersistentVolumeDetail(apiHandler.client, name)
972+
if err != nil {
973+
handleInternalError(response, err)
974+
return
975+
}
976+
response.WriteHeaderAndEntity(http.StatusCreated, result)
977+
}
978+
949979
// Handles log API call.
950980
func (apiHandler *APIHandler) handleLogs(request *restful.Request, response *restful.Response) {
951981
namespace := request.PathParameter("namespace")

src/app/backend/resource/common/resourcechannels.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ type ResourceChannels struct {
7373

7474
// List and error channels to PodMetrics.
7575
PodMetrics PodMetricsChannel
76+
77+
// List and error channels to PersistentVolumes
78+
PersistentVolumeList PersistentVolumeListChannel
7679
}
7780

7881
// ServiceListChannel is a list and error channels to Services.
@@ -453,6 +456,31 @@ func GetConfigMapListChannel(client client.ConfigMapsNamespacer, nsQuery *Namesp
453456
return channel
454457
}
455458

459+
// PersistentVolumeListChannel is a list and error channels to PersistentVolumes.
460+
type PersistentVolumeListChannel struct {
461+
List chan *api.PersistentVolumeList
462+
Error chan error
463+
}
464+
465+
// GetPersistentVolumeListChannel returns a pair of channels to a PersistentVolume list and errors that
466+
// both must be read numReads times.
467+
func GetPersistentVolumeListChannel(client client.PersistentVolumesInterface, numReads int) PersistentVolumeListChannel {
468+
channel := PersistentVolumeListChannel{
469+
List: make(chan *api.PersistentVolumeList, numReads),
470+
Error: make(chan error, numReads),
471+
}
472+
473+
go func() {
474+
list, err := client.PersistentVolumes().List(listEverything)
475+
for i := 0; i < numReads; i++ {
476+
channel.List <- list
477+
channel.Error <- err
478+
}
479+
}()
480+
481+
return channel
482+
}
483+
456484
// PodMetricsChannel is a list and error channels to MetricsByPod.
457485
type PodMetricsChannel struct {
458486
MetricsByPod chan *MetricsByPod

src/app/backend/resource/common/types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ const (
108108
ResourceKindNode = "node"
109109
ResourceKindSecret = "secret"
110110
ResourceKindConfigMap = "configmap"
111+
ResourceKindPersistentVolume = "persistentvolume"
111112
)
112113

113114
// ClientType represents type of client that is used to perform generic operations on resources.
@@ -146,6 +147,7 @@ var kindToAPIMapping = map[string]struct {
146147
ResourceKindNode: {"nodes", ClientTypeDefault},
147148
ResourceKindSecret: {"secrets", ClientTypeDefault},
148149
ResourceKindConfigMap: {"configmaps", ClientTypeDefault},
150+
ResourceKindPersistentVolume: {"persistentvolumes", ClientTypeDefault},
149151
}
150152

151153
// IsSelectorMatching returns true when an object with the given
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package persistentvolume
16+
17+
import (
18+
"k8s.io/kubernetes/pkg/api"
19+
"github.com/kubernetes/dashboard/src/app/backend/resource/common"
20+
)
21+
22+
func paginate(persistentVolumes []api.PersistentVolume, pQuery *common.PaginationQuery) []api.PersistentVolume {
23+
startIndex, endIndex := pQuery.GetPaginationSettings(len(persistentVolumes))
24+
25+
// Return all items if provided settings do not meet requirements
26+
if !pQuery.CanPaginate(len(persistentVolumes), startIndex) {
27+
return persistentVolumes
28+
}
29+
30+
return persistentVolumes[startIndex:endIndex]
31+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package persistentvolume
16+
17+
import (
18+
"log"
19+
20+
"github.com/kubernetes/dashboard/src/app/backend/resource/common"
21+
"k8s.io/kubernetes/pkg/api"
22+
client "k8s.io/kubernetes/pkg/client/unversioned"
23+
)
24+
25+
// PersistentVolumeDetail provides the presentation layer view of Kubernetes Persistent Volume resource.
26+
type PersistentVolumeDetail struct {
27+
ObjectMeta common.ObjectMeta `json:"objectMeta"`
28+
TypeMeta common.TypeMeta `json:"typeMeta"`
29+
30+
Status api.PersistentVolumePhase `json:"status"`
31+
Claim string `json:"claim"`
32+
ReclaimPolicy api.PersistentVolumeReclaimPolicy `json:"reclaimPolicy"`
33+
AccessModes []api.PersistentVolumeAccessMode `json:"accessModes"`
34+
Capacity api.ResourceList `json:"capacity"`
35+
Message string `json:"message"`
36+
PersistentVolumeSource api.PersistentVolumeSource `json:"persistentVolumeSource"`
37+
}
38+
39+
// GetPersistentVolumeDetail returns detailed information about a persistent volume
40+
func GetPersistentVolumeDetail(client *client.Client, name string) (*PersistentVolumeDetail, error) {
41+
log.Printf("Getting details of %s persistent volume", name)
42+
43+
rawPersistentVolume, err := client.PersistentVolumes().Get(name)
44+
45+
if err != nil {
46+
return nil, err
47+
}
48+
49+
return getPersistentVolumeDetail(rawPersistentVolume), nil
50+
}
51+
52+
func getPersistentVolumeDetail(persistentVolume *api.PersistentVolume) *PersistentVolumeDetail {
53+
54+
var claim string
55+
if persistentVolume.Spec.ClaimRef != nil {
56+
claim = persistentVolume.Spec.ClaimRef.Name
57+
}
58+
return &PersistentVolumeDetail{
59+
ObjectMeta: common.NewObjectMeta(persistentVolume.ObjectMeta),
60+
TypeMeta: common.NewTypeMeta(common.ResourceKindPersistentVolume),
61+
Status: persistentVolume.Status.Phase,
62+
Claim: claim,
63+
ReclaimPolicy: persistentVolume.Spec.PersistentVolumeReclaimPolicy,
64+
AccessModes: persistentVolume.Spec.AccessModes,
65+
Capacity: persistentVolume.Spec.Capacity,
66+
Message: persistentVolume.Status.Message,
67+
PersistentVolumeSource: persistentVolume.Spec.PersistentVolumeSource,
68+
}
69+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package persistentvolume
16+
17+
import (
18+
"log"
19+
20+
"github.com/kubernetes/dashboard/src/app/backend/resource/common"
21+
"k8s.io/kubernetes/pkg/api"
22+
client "k8s.io/kubernetes/pkg/client/unversioned"
23+
)
24+
25+
// PersistentVolumeList contains a list of Persistent Volumes in the cluster.
26+
type PersistentVolumeList struct {
27+
ListMeta common.ListMeta `json:"listMeta"`
28+
29+
// Unordered list of Config Maps
30+
Items []PersistentVolume `json:"items"`
31+
}
32+
33+
// PersistentVolume provides the simplified presentation layer view of Kubernetes Persistent Volume resource.
34+
type PersistentVolume struct {
35+
ObjectMeta common.ObjectMeta `json:"objectMeta"`
36+
TypeMeta common.TypeMeta `json:"typeMeta"`
37+
38+
// No additional info in the list object.
39+
}
40+
41+
// GetPersistentVolumeList returns a list of all Persistent Volumes in the cluster.
42+
func GetPersistentVolumeList(client *client.Client, pQuery *common.PaginationQuery) (*PersistentVolumeList, error) {
43+
log.Printf("Getting list persistent volumes")
44+
channels := &common.ResourceChannels{
45+
PersistentVolumeList: common.GetPersistentVolumeListChannel(client, 1),
46+
}
47+
48+
return GetPersistentVolumeListFromChannels(channels, pQuery)
49+
}
50+
51+
// GetPersistentVolumeListFromChannels returns a list of all Persistent Volumes in the cluster
52+
// reading required resource list once from the channels.
53+
func GetPersistentVolumeListFromChannels(channels *common.ResourceChannels, pQuery *common.PaginationQuery) (
54+
*PersistentVolumeList, error) {
55+
56+
persistentVolumes := <-channels.PersistentVolumeList.List
57+
if err := <-channels.PersistentVolumeList.Error; err != nil {
58+
return nil, err
59+
}
60+
61+
result := getPersistentVolumeList(persistentVolumes.Items, pQuery)
62+
63+
return result, nil
64+
}
65+
66+
func getPersistentVolumeList(persistentVolumes []api.PersistentVolume, pQuery *common.PaginationQuery) *PersistentVolumeList {
67+
result := &PersistentVolumeList{
68+
Items: make([]PersistentVolume, 0),
69+
ListMeta: common.ListMeta{TotalItems: len(persistentVolumes)},
70+
}
71+
persistentVolumes = paginate(persistentVolumes, pQuery)
72+
73+
for _, item := range persistentVolumes {
74+
result.Items = append(result.Items,
75+
PersistentVolume{
76+
ObjectMeta: common.NewObjectMeta(item.ObjectMeta),
77+
TypeMeta: common.NewTypeMeta(common.ResourceKindPersistentVolume),
78+
})
79+
}
80+
81+
return result
82+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package persistentvolume
16+
17+
import (
18+
"reflect"
19+
"testing"
20+
21+
"github.com/kubernetes/dashboard/src/app/backend/resource/common"
22+
"k8s.io/kubernetes/pkg/api"
23+
)
24+
25+
func TestGetPersistentVolumeList(t *testing.T) {
26+
cases := []struct {
27+
persistentVolumes []api.PersistentVolume
28+
expected *PersistentVolumeList
29+
}{
30+
{nil, &PersistentVolumeList{Items: []PersistentVolume{}}},
31+
{
32+
[]api.PersistentVolume{
33+
{ObjectMeta: api.ObjectMeta{Name: "foo"}},
34+
},
35+
&PersistentVolumeList{
36+
ListMeta: common.ListMeta{TotalItems: 1},
37+
Items: []PersistentVolume{{
38+
TypeMeta: common.TypeMeta{Kind: "persistentvolume"},
39+
ObjectMeta: common.ObjectMeta{Name: "foo"},
40+
}},
41+
},
42+
},
43+
}
44+
for _, c := range cases {
45+
actual := getPersistentVolumeList(c.persistentVolumes, common.NoPagination)
46+
if !reflect.DeepEqual(actual, c.expected) {
47+
t.Errorf("getPersistentVolumeList(%#v) == \n%#v\nexpected \n%#v\n",
48+
c.persistentVolumes, actual, c.expected)
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)