Commit 7abc3de6 authored by k8s-merge-robot's avatar k8s-merge-robot Committed by GitHub

Merge pull request #29694 from jsafrane/dynprov2-apionly

Automatic merge from submit-queue Add API for StorageClasses This is the API objects only required for dynamic provisioning picked apart from the controller logic. Entire feature is here: https://github.com/kubernetes/kubernetes/pull/29006
parents eca270bb f5bd7d47
...@@ -423,6 +423,12 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; } ...@@ -423,6 +423,12 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
<li> <li>
<p><a href="#_v1beta1_networkpolicylist">v1beta1.NetworkPolicyList</a></p> <p><a href="#_v1beta1_networkpolicylist">v1beta1.NetworkPolicyList</a></p>
</li> </li>
<li>
<p><a href="#_v1beta1_storageclass">v1beta1.StorageClass</a></p>
</li>
<li>
<p><a href="#_v1beta1_storageclasslist">v1beta1.StorageClassList</a></p>
</li>
</ul> </ul>
</div> </div>
</div> </div>
...@@ -1549,6 +1555,71 @@ Examples:<br> ...@@ -1549,6 +1555,71 @@ Examples:<br>
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_v1beta1_storageclass">v1beta1.StorageClass</h3>
<div class="paragraph">
<p>StorageClass describes the parameters for a class of storage for which PersistentVolumes can be dynamically provisioned.</p>
</div>
<div class="paragraph">
<p>StorageClasses are non-namespaced; the name of the storage class according to etcd is in ObjectMeta.Name.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">kind</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: <a href="http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds">http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">apiVersion</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: <a href="http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources">http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">metadata</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Standard object&#8217;s metadata. More info: <a href="http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata">http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_objectmeta">v1.ObjectMeta</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">provisioner</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Provisioner indicates the type of the provisioner.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">parameters</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Parameters holds the parameters for the provisioner that should create volumes of this storage class.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">object</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_execaction">v1.ExecAction</h3> <h3 id="_v1_execaction">v1.ExecAction</h3>
<div class="paragraph"> <div class="paragraph">
<p>ExecAction describes a "run in container" action.</p> <p>ExecAction describes a "run in container" action.</p>
...@@ -2123,6 +2194,61 @@ Populated by the system when a graceful deletion is requested. Read-only. More i ...@@ -2123,6 +2194,61 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
</div> </div>
</div> </div>
<div class="sect2"> <div class="sect2">
<h3 id="_v1beta1_storageclasslist">v1beta1.StorageClassList</h3>
<div class="paragraph">
<p>StorageClassList is a collection of storage classes.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
<col style="width:20%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Name</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Required</th>
<th class="tableblock halign-left valign-top">Schema</th>
<th class="tableblock halign-left valign-top">Default</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">kind</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: <a href="http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds">http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">apiVersion</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: <a href="http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources">http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">metadata</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Standard list metadata More info: <a href="http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata">http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_unversioned_listmeta">unversioned.ListMeta</a></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">items</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Items is the list of StorageClasses</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1beta1_storageclass">v1beta1.StorageClass</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_v1_flockervolumesource">v1.FlockerVolumeSource</h3> <h3 id="_v1_flockervolumesource">v1.FlockerVolumeSource</h3>
<div class="paragraph"> <div class="paragraph">
<p>Represents a Flocker volume mounted by the Flocker agent. Flocker volumes do not support ownership management or SELinux relabeling.</p> <p>Represents a Flocker volume mounted by the Flocker agent. Flocker volumes do not support ownership management or SELinux relabeling.</p>
...@@ -6365,7 +6491,7 @@ Both these may change in the future. Incoming requests are matched against the h ...@@ -6365,7 +6491,7 @@ Both these may change in the future. Incoming requests are matched against the h
</div> </div>
<div id="footer"> <div id="footer">
<div id="footer-text"> <div id="footer-text">
Last updated 2016-07-07 17:05:18 UTC Last updated 2016-07-28 17:22:13 UTC
</div> </div>
</div> </div>
</body> </body>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -2262,7 +2262,32 @@ __EOF__ ...@@ -2262,7 +2262,32 @@ __EOF__
# Post-condition: no PVCs # Post-condition: no PVCs
kube::test::get_object_assert pvc "{{range.items}}{{$id_field}}:{{end}}" '' kube::test::get_object_assert pvc "{{range.items}}{{$id_field}}:{{end}}" ''
############################
# Storage Classes #
############################
### Create and delete storage class
# Pre-condition: no storage classes currently exist
kube::test::get_object_assert storageclass "{{range.items}}{{$id_field}}:{{end}}" ''
# Command
kubectl create -f - "${kube_flags[@]}" << __EOF__
{
"kind": "StorageClass",
"apiVersion": "extensions/v1beta1",
"metadata": {
"name": "storage-class-name"
},
"provisioner": "kubernetes.io/fake-provisioner-type",
"parameters": {
"zone":"us-east-1b",
"type":"ssd"
}
}
__EOF__
kube::test::get_object_assert storageclass "{{range.items}}{{$id_field}}:{{end}}" 'storage-class-name:'
kubectl delete storageclass storage-class-name "${kube_flags[@]}"
# Post-condition: no storage classes
kube::test::get_object_assert storageclass "{{range.items}}{{$id_field}}:{{end}}" ''
######### #########
# Nodes # # Nodes #
......
...@@ -93,6 +93,7 @@ func newRESTMapper(externalVersions []unversioned.GroupVersion) meta.RESTMapper ...@@ -93,6 +93,7 @@ func newRESTMapper(externalVersions []unversioned.GroupVersion) meta.RESTMapper
rootScoped := sets.NewString( rootScoped := sets.NewString(
"PodSecurityPolicy", "PodSecurityPolicy",
"ThirdPartyResource", "ThirdPartyResource",
"StorageClass",
) )
ignoredKinds := sets.NewString() ignoredKinds := sets.NewString()
......
...@@ -75,5 +75,7 @@ func addKnownTypes(scheme *runtime.Scheme) { ...@@ -75,5 +75,7 @@ func addKnownTypes(scheme *runtime.Scheme) {
&PodSecurityPolicyList{}, &PodSecurityPolicyList{},
&NetworkPolicy{}, &NetworkPolicy{},
&NetworkPolicyList{}, &NetworkPolicyList{},
&StorageClass{},
&StorageClassList{},
) )
} }
...@@ -899,3 +899,41 @@ type NetworkPolicyList struct { ...@@ -899,3 +899,41 @@ type NetworkPolicyList struct {
Items []NetworkPolicy `json:"items"` Items []NetworkPolicy `json:"items"`
} }
// +genclient=true
// +nonNamespaced=true
// StorageClass describes a named "class" of storage offered in a cluster.
// Different classes might map to quality-of-service levels, or to backup policies,
// or to arbitrary policies determined by the cluster administrators. Kubernetes
// itself is unopinionated about what classes represent. This concept is sometimes
// called "profiles" in other storage systems.
// The name of a StorageClass object is significant, and is how users can request a particular class.
type StorageClass struct {
unversioned.TypeMeta `json:",inline"`
api.ObjectMeta `json:"metadata,omitempty"`
// provisioner is the driver expected to handle this StorageClass.
// This is an optionally-prefixed name, like a label key.
// For example: "kubernetes.io/gce-pd" or "kubernetes.io/aws-ebs".
// This value may not be empty.
Provisioner string `json:"provisioner"`
// parameters holds parameters for the provisioner.
// These values are opaque to the system and are passed directly
// to the provisioner. The only validation done on keys is that they are
// not empty. The maximum number of parameters is
// 512, with a cumulative max size of 256K
Parameters map[string]string `json:"parameters,omitempty"`
}
// StorageClassList is a collection of storage classes.
type StorageClassList struct {
unversioned.TypeMeta `json:",inline"`
// Standard list metadata
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
unversioned.ListMeta `json:"metadata,omitempty"`
// Items is the list of StorageClasses
Items []StorageClass `json:"items"`
}
...@@ -942,6 +942,34 @@ message ScaleStatus { ...@@ -942,6 +942,34 @@ message ScaleStatus {
optional string targetSelector = 3; optional string targetSelector = 3;
} }
// StorageClass describes the parameters for a class of storage for
// which PersistentVolumes can be dynamically provisioned.
//
// StorageClasses are non-namespaced; the name of the storage class
// according to etcd is in ObjectMeta.Name.
message StorageClass {
// Standard object's metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
optional k8s.io.kubernetes.pkg.api.v1.ObjectMeta metadata = 1;
// Provisioner indicates the type of the provisioner.
optional string provisioner = 2;
// Parameters holds the parameters for the provisioner that should
// create volumes of this storage class.
map<string, string> parameters = 3;
}
// StorageClassList is a collection of storage classes.
message StorageClassList {
// Standard list metadata
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
optional k8s.io.kubernetes.pkg.api.unversioned.ListMeta metadata = 1;
// Items is the list of StorageClasses
repeated StorageClass items = 2;
}
// SubresourceReference contains enough information to let you inspect or modify the referred subresource. // SubresourceReference contains enough information to let you inspect or modify the referred subresource.
message SubresourceReference { message SubresourceReference {
// Kind of the referent; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds // Kind of the referent; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds
......
...@@ -63,6 +63,8 @@ func addKnownTypes(scheme *runtime.Scheme) { ...@@ -63,6 +63,8 @@ func addKnownTypes(scheme *runtime.Scheme) {
&PodSecurityPolicyList{}, &PodSecurityPolicyList{},
&NetworkPolicy{}, &NetworkPolicy{},
&NetworkPolicyList{}, &NetworkPolicyList{},
&StorageClass{},
&StorageClassList{},
) )
// Add the watch version that applies // Add the watch version that applies
versionedwatch.AddToGroupVersion(scheme, SchemeGroupVersion) versionedwatch.AddToGroupVersion(scheme, SchemeGroupVersion)
......
...@@ -1196,3 +1196,36 @@ type NetworkPolicyList struct { ...@@ -1196,3 +1196,36 @@ type NetworkPolicyList struct {
// Items is a list of schema objects. // Items is a list of schema objects.
Items []NetworkPolicy `json:"items" protobuf:"bytes,2,rep,name=items"` Items []NetworkPolicy `json:"items" protobuf:"bytes,2,rep,name=items"`
} }
// +genclient=true
// +nonNamespaced=true
// StorageClass describes the parameters for a class of storage for
// which PersistentVolumes can be dynamically provisioned.
//
// StorageClasses are non-namespaced; the name of the storage class
// according to etcd is in ObjectMeta.Name.
type StorageClass struct {
unversioned.TypeMeta `json:",inline"`
// Standard object's metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
v1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Provisioner indicates the type of the provisioner.
Provisioner string `json:"provisioner" protobuf:"bytes,2,opt,name=provisioner"`
// Parameters holds the parameters for the provisioner that should
// create volumes of this storage class.
Parameters map[string]string `json:"parameters,omitempty" protobuf:"bytes,3,rep,name=parameters"`
}
// StorageClassList is a collection of storage classes.
type StorageClassList struct {
unversioned.TypeMeta `json:",inline"`
// Standard list metadata
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
unversioned.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Items is the list of StorageClasses
Items []StorageClass `json:"items" protobuf:"bytes,2,rep,name=items"`
}
...@@ -674,6 +674,27 @@ func (ScaleStatus) SwaggerDoc() map[string]string { ...@@ -674,6 +674,27 @@ func (ScaleStatus) SwaggerDoc() map[string]string {
return map_ScaleStatus return map_ScaleStatus
} }
var map_StorageClass = map[string]string{
"": "StorageClass describes the parameters for a class of storage for which PersistentVolumes can be dynamically provisioned.\n\nStorageClasses are non-namespaced; the name of the storage class according to etcd is in ObjectMeta.Name.",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"provisioner": "Provisioner indicates the type of the provisioner.",
"parameters": "Parameters holds the parameters for the provisioner that should create volumes of this storage class.",
}
func (StorageClass) SwaggerDoc() map[string]string {
return map_StorageClass
}
var map_StorageClassList = map[string]string{
"": "StorageClassList is a collection of storage classes.",
"metadata": "Standard list metadata More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"items": "Items is the list of StorageClasses",
}
func (StorageClassList) SwaggerDoc() map[string]string {
return map_StorageClassList
}
var map_SubresourceReference = map[string]string{ var map_SubresourceReference = map[string]string{
"": "SubresourceReference contains enough information to let you inspect or modify the referred subresource.", "": "SubresourceReference contains enough information to let you inspect or modify the referred subresource.",
"kind": "Kind of the referent; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds", "kind": "Kind of the referent; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
......
...@@ -156,6 +156,10 @@ func init() { ...@@ -156,6 +156,10 @@ func init() {
Convert_extensions_ScaleSpec_To_v1beta1_ScaleSpec, Convert_extensions_ScaleSpec_To_v1beta1_ScaleSpec,
Convert_v1beta1_ScaleStatus_To_extensions_ScaleStatus, Convert_v1beta1_ScaleStatus_To_extensions_ScaleStatus,
Convert_extensions_ScaleStatus_To_v1beta1_ScaleStatus, Convert_extensions_ScaleStatus_To_v1beta1_ScaleStatus,
Convert_v1beta1_StorageClass_To_extensions_StorageClass,
Convert_extensions_StorageClass_To_v1beta1_StorageClass,
Convert_v1beta1_StorageClassList_To_extensions_StorageClassList,
Convert_extensions_StorageClassList_To_v1beta1_StorageClassList,
Convert_v1beta1_SupplementalGroupsStrategyOptions_To_extensions_SupplementalGroupsStrategyOptions, Convert_v1beta1_SupplementalGroupsStrategyOptions_To_extensions_SupplementalGroupsStrategyOptions,
Convert_extensions_SupplementalGroupsStrategyOptions_To_v1beta1_SupplementalGroupsStrategyOptions, Convert_extensions_SupplementalGroupsStrategyOptions_To_v1beta1_SupplementalGroupsStrategyOptions,
Convert_v1beta1_ThirdPartyResource_To_extensions_ThirdPartyResource, Convert_v1beta1_ThirdPartyResource_To_extensions_ThirdPartyResource,
...@@ -2414,6 +2418,90 @@ func Convert_extensions_ScaleSpec_To_v1beta1_ScaleSpec(in *extensions.ScaleSpec, ...@@ -2414,6 +2418,90 @@ func Convert_extensions_ScaleSpec_To_v1beta1_ScaleSpec(in *extensions.ScaleSpec,
return autoConvert_extensions_ScaleSpec_To_v1beta1_ScaleSpec(in, out, s) return autoConvert_extensions_ScaleSpec_To_v1beta1_ScaleSpec(in, out, s)
} }
func autoConvert_v1beta1_StorageClass_To_extensions_StorageClass(in *StorageClass, out *extensions.StorageClass, s conversion.Scope) error {
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
return err
}
out.Provisioner = in.Provisioner
out.Parameters = in.Parameters
return nil
}
func Convert_v1beta1_StorageClass_To_extensions_StorageClass(in *StorageClass, out *extensions.StorageClass, s conversion.Scope) error {
return autoConvert_v1beta1_StorageClass_To_extensions_StorageClass(in, out, s)
}
func autoConvert_extensions_StorageClass_To_v1beta1_StorageClass(in *extensions.StorageClass, out *StorageClass, s conversion.Scope) error {
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
return err
}
out.Provisioner = in.Provisioner
out.Parameters = in.Parameters
return nil
}
func Convert_extensions_StorageClass_To_v1beta1_StorageClass(in *extensions.StorageClass, out *StorageClass, s conversion.Scope) error {
return autoConvert_extensions_StorageClass_To_v1beta1_StorageClass(in, out, s)
}
func autoConvert_v1beta1_StorageClassList_To_extensions_StorageClassList(in *StorageClassList, out *extensions.StorageClassList, s conversion.Scope) error {
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := api.Convert_unversioned_ListMeta_To_unversioned_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
return err
}
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]extensions.StorageClass, len(*in))
for i := range *in {
if err := Convert_v1beta1_StorageClass_To_extensions_StorageClass(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
func Convert_v1beta1_StorageClassList_To_extensions_StorageClassList(in *StorageClassList, out *extensions.StorageClassList, s conversion.Scope) error {
return autoConvert_v1beta1_StorageClassList_To_extensions_StorageClassList(in, out, s)
}
func autoConvert_extensions_StorageClassList_To_v1beta1_StorageClassList(in *extensions.StorageClassList, out *StorageClassList, s conversion.Scope) error {
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := api.Convert_unversioned_ListMeta_To_unversioned_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
return err
}
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]StorageClass, len(*in))
for i := range *in {
if err := Convert_extensions_StorageClass_To_v1beta1_StorageClass(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
func Convert_extensions_StorageClassList_To_v1beta1_StorageClassList(in *extensions.StorageClassList, out *StorageClassList, s conversion.Scope) error {
return autoConvert_extensions_StorageClassList_To_v1beta1_StorageClassList(in, out, s)
}
func autoConvert_v1beta1_SupplementalGroupsStrategyOptions_To_extensions_SupplementalGroupsStrategyOptions(in *SupplementalGroupsStrategyOptions, out *extensions.SupplementalGroupsStrategyOptions, s conversion.Scope) error { func autoConvert_v1beta1_SupplementalGroupsStrategyOptions_To_extensions_SupplementalGroupsStrategyOptions(in *SupplementalGroupsStrategyOptions, out *extensions.SupplementalGroupsStrategyOptions, s conversion.Scope) error {
out.Rule = extensions.SupplementalGroupsStrategyType(in.Rule) out.Rule = extensions.SupplementalGroupsStrategyType(in.Rule)
if in.Ranges != nil { if in.Ranges != nil {
......
...@@ -94,6 +94,8 @@ func init() { ...@@ -94,6 +94,8 @@ func init() {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_Scale, InType: reflect.TypeOf(func() *Scale { var x *Scale; return x }())}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_Scale, InType: reflect.TypeOf(func() *Scale { var x *Scale; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_ScaleSpec, InType: reflect.TypeOf(func() *ScaleSpec { var x *ScaleSpec; return x }())}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_ScaleSpec, InType: reflect.TypeOf(func() *ScaleSpec { var x *ScaleSpec; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_ScaleStatus, InType: reflect.TypeOf(func() *ScaleStatus { var x *ScaleStatus; return x }())}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_ScaleStatus, InType: reflect.TypeOf(func() *ScaleStatus { var x *ScaleStatus; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_StorageClass, InType: reflect.TypeOf(func() *StorageClass { var x *StorageClass; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_StorageClassList, InType: reflect.TypeOf(func() *StorageClassList { var x *StorageClassList; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_SubresourceReference, InType: reflect.TypeOf(func() *SubresourceReference { var x *SubresourceReference; return x }())}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_SubresourceReference, InType: reflect.TypeOf(func() *SubresourceReference { var x *SubresourceReference; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_SupplementalGroupsStrategyOptions, InType: reflect.TypeOf(func() *SupplementalGroupsStrategyOptions { var x *SupplementalGroupsStrategyOptions; return x }())}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_SupplementalGroupsStrategyOptions, InType: reflect.TypeOf(func() *SupplementalGroupsStrategyOptions { var x *SupplementalGroupsStrategyOptions; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_ThirdPartyResource, InType: reflect.TypeOf(func() *ThirdPartyResource { var x *ThirdPartyResource; return x }())}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1beta1_ThirdPartyResource, InType: reflect.TypeOf(func() *ThirdPartyResource { var x *ThirdPartyResource; return x }())},
...@@ -1333,6 +1335,49 @@ func DeepCopy_v1beta1_ScaleStatus(in interface{}, out interface{}, c *conversion ...@@ -1333,6 +1335,49 @@ func DeepCopy_v1beta1_ScaleStatus(in interface{}, out interface{}, c *conversion
} }
} }
func DeepCopy_v1beta1_StorageClass(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*StorageClass)
out := out.(*StorageClass)
out.TypeMeta = in.TypeMeta
if err := v1.DeepCopy_v1_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
return err
}
out.Provisioner = in.Provisioner
if in.Parameters != nil {
in, out := &in.Parameters, &out.Parameters
*out = make(map[string]string)
for key, val := range *in {
(*out)[key] = val
}
} else {
out.Parameters = nil
}
return nil
}
}
func DeepCopy_v1beta1_StorageClassList(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*StorageClassList)
out := out.(*StorageClassList)
out.TypeMeta = in.TypeMeta
out.ListMeta = in.ListMeta
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]StorageClass, len(*in))
for i := range *in {
if err := DeepCopy_v1beta1_StorageClass(&(*in)[i], &(*out)[i], c); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
}
func DeepCopy_v1beta1_SubresourceReference(in interface{}, out interface{}, c *conversion.Cloner) error { func DeepCopy_v1beta1_SubresourceReference(in interface{}, out interface{}, c *conversion.Cloner) error {
{ {
in := in.(*SubresourceReference) in := in.(*SubresourceReference)
......
...@@ -741,3 +741,65 @@ func ValidateNetworkPolicyUpdate(update, old *extensions.NetworkPolicy) field.Er ...@@ -741,3 +741,65 @@ func ValidateNetworkPolicyUpdate(update, old *extensions.NetworkPolicy) field.Er
} }
return allErrs return allErrs
} }
// ValidateStorageClass validates a StorageClass.
func ValidateStorageClass(storageClass *extensions.StorageClass) field.ErrorList {
allErrs := apivalidation.ValidateObjectMeta(&storageClass.ObjectMeta, false, apivalidation.NameIsDNSSubdomain, field.NewPath("metadata"))
allErrs = append(allErrs, validateProvisioner(storageClass.Provisioner, field.NewPath("provisioner"))...)
allErrs = append(allErrs, validateParameters(storageClass.Parameters, field.NewPath("parameters"))...)
return allErrs
}
// ValidateStorageClassUpdate tests if an update to StorageClass is valid.
func ValidateStorageClassUpdate(storageClass, oldStorageClass *extensions.StorageClass) field.ErrorList {
allErrs := apivalidation.ValidateObjectMetaUpdate(&storageClass.ObjectMeta, &oldStorageClass.ObjectMeta, field.NewPath("metadata"))
if !reflect.DeepEqual(oldStorageClass.Parameters, storageClass.Parameters) {
allErrs = append(allErrs, field.Forbidden(field.NewPath("parameters"), "updates to parameters are forbidden."))
}
if strings.Compare(storageClass.Provisioner, oldStorageClass.Provisioner) != 0 {
allErrs = append(allErrs, field.Forbidden(field.NewPath("provisioner"), "updates to provisioner are forbidden."))
}
return allErrs
}
// validateProvisioner tests if provisioner is a valid qualified name.
func validateProvisioner(provisioner string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(provisioner) == 0 {
allErrs = append(allErrs, field.Required(fldPath, provisioner))
}
if len(provisioner) > 0 {
for _, msg := range validation.IsQualifiedName(strings.ToLower(provisioner)) {
allErrs = append(allErrs, field.Invalid(fldPath, provisioner, msg))
}
}
return allErrs
}
const maxProvisionerParameterSize = 256 * (1 << 10) // 256 kB
const maxProvisionerParameterLen = 512
// validateParameters tests that keys are qualified names and that provisionerParameter are < 256kB.
func validateParameters(params map[string]string, fldPath *field.Path) field.ErrorList {
var totalSize int64
allErrs := field.ErrorList{}
if len(params) > maxProvisionerParameterLen {
allErrs = append(allErrs, field.TooLong(fldPath, "Provisioner Parameters exceeded max allowed", maxProvisionerParameterLen))
return allErrs
}
for k, v := range params {
if len(k) < 1 {
allErrs = append(allErrs, field.Invalid(fldPath, k, "field can not be empty."))
}
totalSize += (int64)(len(k)) + (int64)(len(v))
}
if totalSize > maxProvisionerParameterSize {
allErrs = append(allErrs, field.TooLong(fldPath, "", maxProvisionerParameterSize))
}
return allErrs
}
...@@ -1929,3 +1929,80 @@ func newBool(val bool) *bool { ...@@ -1929,3 +1929,80 @@ func newBool(val bool) *bool {
*p = val *p = val
return p return p
} }
func TestValidateStorageClass(t *testing.T) {
successCases := []extensions.StorageClass{
{
// empty parameters
ObjectMeta: api.ObjectMeta{Name: "foo"},
Provisioner: "kubernetes.io/foo-provisioner",
Parameters: map[string]string{},
},
{
// nil parameters
ObjectMeta: api.ObjectMeta{Name: "foo"},
Provisioner: "kubernetes.io/foo-provisioner",
},
{
// some parameters
ObjectMeta: api.ObjectMeta{Name: "foo"},
Provisioner: "kubernetes.io/foo-provisioner",
Parameters: map[string]string{
"kubernetes.io/foo-parameter": "free/form/string",
"foo-parameter": "free-form-string",
"foo-parameter2": "{\"embedded\": \"json\", \"with\": {\"structures\":\"inside\"}}",
},
},
}
// Success cases are expected to pass validation.
for k, v := range successCases {
if errs := ValidateStorageClass(&v); len(errs) != 0 {
t.Errorf("Expected success for %d, got %v", k, errs)
}
}
// generate a map longer than maxProvisionerParameterSize
longParameters := make(map[string]string)
totalSize := 0
for totalSize < maxProvisionerParameterSize {
k := fmt.Sprintf("param/%d", totalSize)
v := fmt.Sprintf("value-%d", totalSize)
longParameters[k] = v
totalSize = totalSize + len(k) + len(v)
}
errorCases := map[string]extensions.StorageClass{
"namespace is present": {
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
Provisioner: "kubernetes.io/foo-provisioner",
},
"invalid provisioner": {
ObjectMeta: api.ObjectMeta{Name: "foo"},
Provisioner: "kubernetes.io/invalid/provisioner",
},
"invalid empty parameter name": {
ObjectMeta: api.ObjectMeta{Name: "foo"},
Provisioner: "kubernetes.io/foo",
Parameters: map[string]string{
"": "value",
},
},
"provisioner: Required value": {
ObjectMeta: api.ObjectMeta{Name: "foo"},
Provisioner: "",
},
"too long parameters": {
ObjectMeta: api.ObjectMeta{Name: "foo"},
Provisioner: "kubernetes.io/foo",
Parameters: longParameters,
},
}
// Error cases are not expected to pass validation.
for testName, storageClass := range errorCases {
if errs := ValidateStorageClass(&storageClass); len(errs) == 0 {
t.Errorf("Expected failure for test: %s", testName)
}
}
}
...@@ -79,6 +79,8 @@ func init() { ...@@ -79,6 +79,8 @@ func init() {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_Scale, InType: reflect.TypeOf(func() *Scale { var x *Scale; return x }())}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_Scale, InType: reflect.TypeOf(func() *Scale { var x *Scale; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_ScaleSpec, InType: reflect.TypeOf(func() *ScaleSpec { var x *ScaleSpec; return x }())}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_ScaleSpec, InType: reflect.TypeOf(func() *ScaleSpec { var x *ScaleSpec; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_ScaleStatus, InType: reflect.TypeOf(func() *ScaleStatus { var x *ScaleStatus; return x }())}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_ScaleStatus, InType: reflect.TypeOf(func() *ScaleStatus { var x *ScaleStatus; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_StorageClass, InType: reflect.TypeOf(func() *StorageClass { var x *StorageClass; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_StorageClassList, InType: reflect.TypeOf(func() *StorageClassList { var x *StorageClassList; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_SupplementalGroupsStrategyOptions, InType: reflect.TypeOf(func() *SupplementalGroupsStrategyOptions { var x *SupplementalGroupsStrategyOptions; return x }())}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_SupplementalGroupsStrategyOptions, InType: reflect.TypeOf(func() *SupplementalGroupsStrategyOptions { var x *SupplementalGroupsStrategyOptions; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_ThirdPartyResource, InType: reflect.TypeOf(func() *ThirdPartyResource { var x *ThirdPartyResource; return x }())}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_ThirdPartyResource, InType: reflect.TypeOf(func() *ThirdPartyResource { var x *ThirdPartyResource; return x }())},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_ThirdPartyResourceData, InType: reflect.TypeOf(func() *ThirdPartyResourceData { var x *ThirdPartyResourceData; return x }())}, conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_extensions_ThirdPartyResourceData, InType: reflect.TypeOf(func() *ThirdPartyResourceData { var x *ThirdPartyResourceData; return x }())},
...@@ -974,6 +976,49 @@ func DeepCopy_extensions_ScaleStatus(in interface{}, out interface{}, c *convers ...@@ -974,6 +976,49 @@ func DeepCopy_extensions_ScaleStatus(in interface{}, out interface{}, c *convers
} }
} }
func DeepCopy_extensions_StorageClass(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*StorageClass)
out := out.(*StorageClass)
out.TypeMeta = in.TypeMeta
if err := api.DeepCopy_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, c); err != nil {
return err
}
out.Provisioner = in.Provisioner
if in.Parameters != nil {
in, out := &in.Parameters, &out.Parameters
*out = make(map[string]string)
for key, val := range *in {
(*out)[key] = val
}
} else {
out.Parameters = nil
}
return nil
}
}
func DeepCopy_extensions_StorageClassList(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*StorageClassList)
out := out.(*StorageClassList)
out.TypeMeta = in.TypeMeta
out.ListMeta = in.ListMeta
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]StorageClass, len(*in))
for i := range *in {
if err := DeepCopy_extensions_StorageClass(&(*in)[i], &(*out)[i], c); err != nil {
return err
}
}
} else {
out.Items = nil
}
return nil
}
}
func DeepCopy_extensions_SupplementalGroupsStrategyOptions(in interface{}, out interface{}, c *conversion.Cloner) error { func DeepCopy_extensions_SupplementalGroupsStrategyOptions(in interface{}, out interface{}, c *conversion.Cloner) error {
{ {
in := in.(*SupplementalGroupsStrategyOptions) in := in.(*SupplementalGroupsStrategyOptions)
......
...@@ -30,6 +30,7 @@ type ExtensionsInterface interface { ...@@ -30,6 +30,7 @@ type ExtensionsInterface interface {
PodSecurityPoliciesGetter PodSecurityPoliciesGetter
ReplicaSetsGetter ReplicaSetsGetter
ScalesGetter ScalesGetter
StorageClassesGetter
ThirdPartyResourcesGetter ThirdPartyResourcesGetter
} }
...@@ -62,6 +63,10 @@ func (c *ExtensionsClient) Scales(namespace string) ScaleInterface { ...@@ -62,6 +63,10 @@ func (c *ExtensionsClient) Scales(namespace string) ScaleInterface {
return newScales(c, namespace) return newScales(c, namespace)
} }
func (c *ExtensionsClient) StorageClasses() StorageClassInterface {
return newStorageClasses(c)
}
func (c *ExtensionsClient) ThirdPartyResources() ThirdPartyResourceInterface { func (c *ExtensionsClient) ThirdPartyResources() ThirdPartyResourceInterface {
return newThirdPartyResources(c) return newThirdPartyResources(c)
} }
......
...@@ -50,6 +50,10 @@ func (c *FakeExtensions) Scales(namespace string) unversioned.ScaleInterface { ...@@ -50,6 +50,10 @@ func (c *FakeExtensions) Scales(namespace string) unversioned.ScaleInterface {
return &FakeScales{c, namespace} return &FakeScales{c, namespace}
} }
func (c *FakeExtensions) StorageClasses() unversioned.StorageClassInterface {
return &FakeStorageClasses{c}
}
func (c *FakeExtensions) ThirdPartyResources() unversioned.ThirdPartyResourceInterface { func (c *FakeExtensions) ThirdPartyResources() unversioned.ThirdPartyResourceInterface {
return &FakeThirdPartyResources{c} return &FakeThirdPartyResources{c}
} }
......
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
api "k8s.io/kubernetes/pkg/api"
unversioned "k8s.io/kubernetes/pkg/api/unversioned"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeStorageClasses implements StorageClassInterface
type FakeStorageClasses struct {
Fake *FakeExtensions
}
var storageclassesResource = unversioned.GroupVersionResource{Group: "extensions", Version: "", Resource: "storageclasses"}
func (c *FakeStorageClasses) Create(storageClass *extensions.StorageClass) (result *extensions.StorageClass, err error) {
obj, err := c.Fake.
Invokes(core.NewRootCreateAction(storageclassesResource, storageClass), &extensions.StorageClass{})
if obj == nil {
return nil, err
}
return obj.(*extensions.StorageClass), err
}
func (c *FakeStorageClasses) Update(storageClass *extensions.StorageClass) (result *extensions.StorageClass, err error) {
obj, err := c.Fake.
Invokes(core.NewRootUpdateAction(storageclassesResource, storageClass), &extensions.StorageClass{})
if obj == nil {
return nil, err
}
return obj.(*extensions.StorageClass), err
}
func (c *FakeStorageClasses) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewRootDeleteAction(storageclassesResource, name), &extensions.StorageClass{})
return err
}
func (c *FakeStorageClasses) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewRootDeleteCollectionAction(storageclassesResource, listOptions)
_, err := c.Fake.Invokes(action, &extensions.StorageClassList{})
return err
}
func (c *FakeStorageClasses) Get(name string) (result *extensions.StorageClass, err error) {
obj, err := c.Fake.
Invokes(core.NewRootGetAction(storageclassesResource, name), &extensions.StorageClass{})
if obj == nil {
return nil, err
}
return obj.(*extensions.StorageClass), err
}
func (c *FakeStorageClasses) List(opts api.ListOptions) (result *extensions.StorageClassList, err error) {
obj, err := c.Fake.
Invokes(core.NewRootListAction(storageclassesResource, opts), &extensions.StorageClassList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &extensions.StorageClassList{}
for _, item := range obj.(*extensions.StorageClassList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested storageClasses.
func (c *FakeStorageClasses) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewRootWatchAction(storageclassesResource, opts))
}
// Patch applies the patch and returns the patched storageClass.
func (c *FakeStorageClasses) Patch(name string, pt api.PatchType, data []byte, subresources ...string) (result *extensions.StorageClass, err error) {
obj, err := c.Fake.
Invokes(core.NewRootPatchSubresourceAction(storageclassesResource, name, data, subresources...), &extensions.StorageClass{})
if obj == nil {
return nil, err
}
return obj.(*extensions.StorageClass), err
}
...@@ -29,3 +29,5 @@ type PodSecurityPolicyExpansion interface{} ...@@ -29,3 +29,5 @@ type PodSecurityPolicyExpansion interface{}
type ThirdPartyResourceExpansion interface{} type ThirdPartyResourceExpansion interface{}
type ReplicaSetExpansion interface{} type ReplicaSetExpansion interface{}
type StorageClassExpansion interface{}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned
import (
api "k8s.io/kubernetes/pkg/api"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
watch "k8s.io/kubernetes/pkg/watch"
)
// StorageClassesGetter has a method to return a StorageClassInterface.
// A group's client should implement this interface.
type StorageClassesGetter interface {
StorageClasses() StorageClassInterface
}
// StorageClassInterface has methods to work with StorageClass resources.
type StorageClassInterface interface {
Create(*extensions.StorageClass) (*extensions.StorageClass, error)
Update(*extensions.StorageClass) (*extensions.StorageClass, error)
Delete(name string, options *api.DeleteOptions) error
DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error
Get(name string) (*extensions.StorageClass, error)
List(opts api.ListOptions) (*extensions.StorageClassList, error)
Watch(opts api.ListOptions) (watch.Interface, error)
Patch(name string, pt api.PatchType, data []byte, subresources ...string) (result *extensions.StorageClass, err error)
StorageClassExpansion
}
// storageClasses implements StorageClassInterface
type storageClasses struct {
client *ExtensionsClient
}
// newStorageClasses returns a StorageClasses
func newStorageClasses(c *ExtensionsClient) *storageClasses {
return &storageClasses{
client: c,
}
}
// Create takes the representation of a storageClass and creates it. Returns the server's representation of the storageClass, and an error, if there is any.
func (c *storageClasses) Create(storageClass *extensions.StorageClass) (result *extensions.StorageClass, err error) {
result = &extensions.StorageClass{}
err = c.client.Post().
Resource("storageclasses").
Body(storageClass).
Do().
Into(result)
return
}
// Update takes the representation of a storageClass and updates it. Returns the server's representation of the storageClass, and an error, if there is any.
func (c *storageClasses) Update(storageClass *extensions.StorageClass) (result *extensions.StorageClass, err error) {
result = &extensions.StorageClass{}
err = c.client.Put().
Resource("storageclasses").
Name(storageClass.Name).
Body(storageClass).
Do().
Into(result)
return
}
// Delete takes name of the storageClass and deletes it. Returns an error if one occurs.
func (c *storageClasses) Delete(name string, options *api.DeleteOptions) error {
return c.client.Delete().
Resource("storageclasses").
Name(name).
Body(options).
Do().
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *storageClasses) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
return c.client.Delete().
Resource("storageclasses").
VersionedParams(&listOptions, api.ParameterCodec).
Body(options).
Do().
Error()
}
// Get takes name of the storageClass, and returns the corresponding storageClass object, and an error if there is any.
func (c *storageClasses) Get(name string) (result *extensions.StorageClass, err error) {
result = &extensions.StorageClass{}
err = c.client.Get().
Resource("storageclasses").
Name(name).
Do().
Into(result)
return
}
// List takes label and field selectors, and returns the list of StorageClasses that match those selectors.
func (c *storageClasses) List(opts api.ListOptions) (result *extensions.StorageClassList, err error) {
result = &extensions.StorageClassList{}
err = c.client.Get().
Resource("storageclasses").
VersionedParams(&opts, api.ParameterCodec).
Do().
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested storageClasses.
func (c *storageClasses) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.client.Get().
Prefix("watch").
Resource("storageclasses").
VersionedParams(&opts, api.ParameterCodec).
Watch()
}
// Patch applies the patch and returns the patched storageClass.
func (c *storageClasses) Patch(name string, pt api.PatchType, data []byte, subresources ...string) (result *extensions.StorageClass, err error) {
result = &extensions.StorageClass{}
err = c.client.Patch(pt).
Resource("storageclasses").
SubResource(subresources...).
Name(name).
Body(data).
Do().
Into(result)
return
}
...@@ -33,6 +33,7 @@ type ExtensionsInterface interface { ...@@ -33,6 +33,7 @@ type ExtensionsInterface interface {
PodSecurityPoliciesGetter PodSecurityPoliciesGetter
ReplicaSetsGetter ReplicaSetsGetter
ScalesGetter ScalesGetter
StorageClassesGetter
ThirdPartyResourcesGetter ThirdPartyResourcesGetter
} }
...@@ -73,6 +74,10 @@ func (c *ExtensionsClient) Scales(namespace string) ScaleInterface { ...@@ -73,6 +74,10 @@ func (c *ExtensionsClient) Scales(namespace string) ScaleInterface {
return newScales(c, namespace) return newScales(c, namespace)
} }
func (c *ExtensionsClient) StorageClasses() StorageClassInterface {
return newStorageClasses(c)
}
func (c *ExtensionsClient) ThirdPartyResources() ThirdPartyResourceInterface { func (c *ExtensionsClient) ThirdPartyResources() ThirdPartyResourceInterface {
return newThirdPartyResources(c) return newThirdPartyResources(c)
} }
......
...@@ -58,6 +58,10 @@ func (c *FakeExtensions) Scales(namespace string) v1beta1.ScaleInterface { ...@@ -58,6 +58,10 @@ func (c *FakeExtensions) Scales(namespace string) v1beta1.ScaleInterface {
return &FakeScales{c, namespace} return &FakeScales{c, namespace}
} }
func (c *FakeExtensions) StorageClasses() v1beta1.StorageClassInterface {
return &FakeStorageClasses{c}
}
func (c *FakeExtensions) ThirdPartyResources() v1beta1.ThirdPartyResourceInterface { func (c *FakeExtensions) ThirdPartyResources() v1beta1.ThirdPartyResourceInterface {
return &FakeThirdPartyResources{c} return &FakeThirdPartyResources{c}
} }
......
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
api "k8s.io/kubernetes/pkg/api"
unversioned "k8s.io/kubernetes/pkg/api/unversioned"
v1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeStorageClasses implements StorageClassInterface
type FakeStorageClasses struct {
Fake *FakeExtensions
}
var storageclassesResource = unversioned.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "storageclasses"}
func (c *FakeStorageClasses) Create(storageClass *v1beta1.StorageClass) (result *v1beta1.StorageClass, err error) {
obj, err := c.Fake.
Invokes(core.NewRootCreateAction(storageclassesResource, storageClass), &v1beta1.StorageClass{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.StorageClass), err
}
func (c *FakeStorageClasses) Update(storageClass *v1beta1.StorageClass) (result *v1beta1.StorageClass, err error) {
obj, err := c.Fake.
Invokes(core.NewRootUpdateAction(storageclassesResource, storageClass), &v1beta1.StorageClass{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.StorageClass), err
}
func (c *FakeStorageClasses) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewRootDeleteAction(storageclassesResource, name), &v1beta1.StorageClass{})
return err
}
func (c *FakeStorageClasses) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewRootDeleteCollectionAction(storageclassesResource, listOptions)
_, err := c.Fake.Invokes(action, &v1beta1.StorageClassList{})
return err
}
func (c *FakeStorageClasses) Get(name string) (result *v1beta1.StorageClass, err error) {
obj, err := c.Fake.
Invokes(core.NewRootGetAction(storageclassesResource, name), &v1beta1.StorageClass{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.StorageClass), err
}
func (c *FakeStorageClasses) List(opts api.ListOptions) (result *v1beta1.StorageClassList, err error) {
obj, err := c.Fake.
Invokes(core.NewRootListAction(storageclassesResource, opts), &v1beta1.StorageClassList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &v1beta1.StorageClassList{}
for _, item := range obj.(*v1beta1.StorageClassList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested storageClasses.
func (c *FakeStorageClasses) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewRootWatchAction(storageclassesResource, opts))
}
// Patch applies the patch and returns the patched storageClass.
func (c *FakeStorageClasses) Patch(name string, pt api.PatchType, data []byte, subresources ...string) (result *v1beta1.StorageClass, err error) {
obj, err := c.Fake.
Invokes(core.NewRootPatchSubresourceAction(storageclassesResource, name, data, subresources...), &v1beta1.StorageClass{})
if obj == nil {
return nil, err
}
return obj.(*v1beta1.StorageClass), err
}
...@@ -33,3 +33,5 @@ type ReplicaSetExpansion interface{} ...@@ -33,3 +33,5 @@ type ReplicaSetExpansion interface{}
type ScaleExpansion interface{} type ScaleExpansion interface{}
type ThirdPartyResourceExpansion interface{} type ThirdPartyResourceExpansion interface{}
type StorageClassExpansion interface{}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1
import (
api "k8s.io/kubernetes/pkg/api"
v1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
watch "k8s.io/kubernetes/pkg/watch"
)
// StorageClassesGetter has a method to return a StorageClassInterface.
// A group's client should implement this interface.
type StorageClassesGetter interface {
StorageClasses() StorageClassInterface
}
// StorageClassInterface has methods to work with StorageClass resources.
type StorageClassInterface interface {
Create(*v1beta1.StorageClass) (*v1beta1.StorageClass, error)
Update(*v1beta1.StorageClass) (*v1beta1.StorageClass, error)
Delete(name string, options *api.DeleteOptions) error
DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error
Get(name string) (*v1beta1.StorageClass, error)
List(opts api.ListOptions) (*v1beta1.StorageClassList, error)
Watch(opts api.ListOptions) (watch.Interface, error)
Patch(name string, pt api.PatchType, data []byte, subresources ...string) (result *v1beta1.StorageClass, err error)
StorageClassExpansion
}
// storageClasses implements StorageClassInterface
type storageClasses struct {
client *ExtensionsClient
}
// newStorageClasses returns a StorageClasses
func newStorageClasses(c *ExtensionsClient) *storageClasses {
return &storageClasses{
client: c,
}
}
// Create takes the representation of a storageClass and creates it. Returns the server's representation of the storageClass, and an error, if there is any.
func (c *storageClasses) Create(storageClass *v1beta1.StorageClass) (result *v1beta1.StorageClass, err error) {
result = &v1beta1.StorageClass{}
err = c.client.Post().
Resource("storageclasses").
Body(storageClass).
Do().
Into(result)
return
}
// Update takes the representation of a storageClass and updates it. Returns the server's representation of the storageClass, and an error, if there is any.
func (c *storageClasses) Update(storageClass *v1beta1.StorageClass) (result *v1beta1.StorageClass, err error) {
result = &v1beta1.StorageClass{}
err = c.client.Put().
Resource("storageclasses").
Name(storageClass.Name).
Body(storageClass).
Do().
Into(result)
return
}
// Delete takes name of the storageClass and deletes it. Returns an error if one occurs.
func (c *storageClasses) Delete(name string, options *api.DeleteOptions) error {
return c.client.Delete().
Resource("storageclasses").
Name(name).
Body(options).
Do().
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *storageClasses) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
return c.client.Delete().
Resource("storageclasses").
VersionedParams(&listOptions, api.ParameterCodec).
Body(options).
Do().
Error()
}
// Get takes name of the storageClass, and returns the corresponding storageClass object, and an error if there is any.
func (c *storageClasses) Get(name string) (result *v1beta1.StorageClass, err error) {
result = &v1beta1.StorageClass{}
err = c.client.Get().
Resource("storageclasses").
Name(name).
Do().
Into(result)
return
}
// List takes label and field selectors, and returns the list of StorageClasses that match those selectors.
func (c *storageClasses) List(opts api.ListOptions) (result *v1beta1.StorageClassList, err error) {
result = &v1beta1.StorageClassList{}
err = c.client.Get().
Resource("storageclasses").
VersionedParams(&opts, api.ParameterCodec).
Do().
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested storageClasses.
func (c *storageClasses) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.client.Get().
Prefix("watch").
Resource("storageclasses").
VersionedParams(&opts, api.ParameterCodec).
Watch()
}
// Patch applies the patch and returns the patched storageClass.
func (c *storageClasses) Patch(name string, pt api.PatchType, data []byte, subresources ...string) (result *v1beta1.StorageClass, err error) {
result = &v1beta1.StorageClass{}
err = c.client.Patch(pt).
Resource("storageclasses").
SubResource(subresources...).
Name(name).
Body(data).
Do().
Into(result)
return
}
...@@ -37,6 +37,7 @@ type ExtensionsInterface interface { ...@@ -37,6 +37,7 @@ type ExtensionsInterface interface {
ThirdPartyResourceNamespacer ThirdPartyResourceNamespacer
ReplicaSetsNamespacer ReplicaSetsNamespacer
PodSecurityPoliciesInterface PodSecurityPoliciesInterface
StorageClassesInterface
} }
// ExtensionsClient is used to interact with experimental Kubernetes features. // ExtensionsClient is used to interact with experimental Kubernetes features.
...@@ -82,6 +83,10 @@ func (c *ExtensionsClient) ReplicaSets(namespace string) ReplicaSetInterface { ...@@ -82,6 +83,10 @@ func (c *ExtensionsClient) ReplicaSets(namespace string) ReplicaSetInterface {
return newReplicaSets(c, namespace) return newReplicaSets(c, namespace)
} }
func (c *ExtensionsClient) StorageClasses() StorageClassInterface {
return newStorageClasses(c)
}
// NewExtensions creates a new ExtensionsClient for the given config. This client // NewExtensions creates a new ExtensionsClient for the given config. This client
// provides access to experimental Kubernetes features. // provides access to experimental Kubernetes features.
// Features of Extensions group are not supported and may be changed or removed in // Features of Extensions group are not supported and may be changed or removed in
......
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/watch"
)
type StorageClassesInterface interface {
StorageClasses() StorageClassInterface
}
// StorageClassInterface has methods to work with StorageClass resources.
type StorageClassInterface interface {
List(opts api.ListOptions) (*extensions.StorageClassList, error)
Get(name string) (*extensions.StorageClass, error)
Create(storageClass *extensions.StorageClass) (*extensions.StorageClass, error)
Update(storageClass *extensions.StorageClass) (*extensions.StorageClass, error)
Delete(name string) error
Watch(opts api.ListOptions) (watch.Interface, error)
}
// storageClasses implements StorageClassInterface
type storageClasses struct {
client *ExtensionsClient
}
func newStorageClasses(c *ExtensionsClient) *storageClasses {
return &storageClasses{c}
}
func (c *storageClasses) List(opts api.ListOptions) (result *extensions.StorageClassList, err error) {
result = &extensions.StorageClassList{}
err = c.client.Get().
Resource("storageclasses").
VersionedParams(&opts, api.ParameterCodec).
Do().
Into(result)
return result, err
}
func (c *storageClasses) Get(name string) (result *extensions.StorageClass, err error) {
result = &extensions.StorageClass{}
err = c.client.Get().Resource("storageClasses").Name(name).Do().Into(result)
return
}
func (c *storageClasses) Create(storageClass *extensions.StorageClass) (result *extensions.StorageClass, err error) {
result = &extensions.StorageClass{}
err = c.client.Post().Resource("storageClasses").Body(storageClass).Do().Into(result)
return
}
func (c *storageClasses) Update(storageClass *extensions.StorageClass) (result *extensions.StorageClass, err error) {
result = &extensions.StorageClass{}
err = c.client.Put().Resource("storageClasses").Name(storageClass.Name).Body(storageClass).Do().Into(result)
return
}
func (c *storageClasses) Delete(name string) error {
return c.client.Delete().Resource("storageClasses").Name(name).Do().Error()
}
func (c *storageClasses) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.client.Get().
Prefix("watch").
Resource("storageClasses").
VersionedParams(&opts, api.ParameterCodec).
Watch()
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned_test
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/unversioned/testclient/simple"
)
func getStorageClassResourceName() string {
return "storageclasses"
}
func TestListStorageClasses(t *testing.T) {
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: testapi.Extensions.ResourcePath(getStorageClassResourceName(), "", ""),
},
Response: simple.Response{StatusCode: 200,
Body: &extensions.StorageClassList{
Items: []extensions.StorageClass{
{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Provisioner: "aaa",
},
},
},
},
}
receivedSCList, err := c.Setup(t).Extensions().StorageClasses().List(api.ListOptions{})
c.Validate(t, receivedSCList, err)
}
func TestGetStorageClass(t *testing.T) {
c := &simple.Client{
Request: simple.Request{Method: "GET", Path: testapi.Extensions.ResourcePath(getStorageClassResourceName(), "", "foo"), Query: simple.BuildQueryValues(nil)},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.StorageClass{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Provisioner: "aaa",
},
},
}
receivedSC, err := c.Setup(t).Extensions().StorageClasses().Get("foo")
c.Validate(t, receivedSC, err)
}
func TestGetStorageClassWithNoName(t *testing.T) {
c := &simple.Client{Error: true}
receivedSC, err := c.Setup(t).Extensions().StorageClasses().Get("")
if (err != nil) && (err.Error() != simple.NameRequiredError) {
t.Errorf("Expected error: %v, but got %v", simple.NameRequiredError, err)
}
c.Validate(t, receivedSC, err)
}
func TestUpdateStorageClass(t *testing.T) {
requestSC := &extensions.StorageClass{
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
Provisioner: "aaa",
}
c := &simple.Client{
Request: simple.Request{Method: "PUT", Path: testapi.Extensions.ResourcePath(getStorageClassResourceName(), "", "foo"), Query: simple.BuildQueryValues(nil)},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.StorageClass{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Provisioner: "aaa",
},
},
}
receivedSC, err := c.Setup(t).Extensions().StorageClasses().Update(requestSC)
c.Validate(t, receivedSC, err)
}
func TestDeleteStorageClass(t *testing.T) {
c := &simple.Client{
Request: simple.Request{Method: "DELETE", Path: testapi.Extensions.ResourcePath(getStorageClassResourceName(), "", "foo"), Query: simple.BuildQueryValues(nil)},
Response: simple.Response{StatusCode: 200},
}
err := c.Setup(t).Extensions().StorageClasses().Delete("foo")
c.Validate(t, nil, err)
}
func TestCreateStorageClass(t *testing.T) {
requestSC := &extensions.StorageClass{
ObjectMeta: api.ObjectMeta{Name: "foo"},
Provisioner: "aaa",
}
c := &simple.Client{
Request: simple.Request{Method: "POST", Path: testapi.Extensions.ResourcePath(getStorageClassResourceName(), "", ""), Body: requestSC, Query: simple.BuildQueryValues(nil)},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.StorageClass{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Provisioner: "aaa",
},
},
}
receivedSC, err := c.Setup(t).Extensions().StorageClasses().Create(requestSC)
c.Validate(t, receivedSC, err)
}
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testclient
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions"
kclientlib "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/watch"
)
// FakeStorageClasses implements StorageClassInterface. Meant to be embedded into a struct to get a default
// implementation. This makes faking out just the method you want to test easier.
type FakeStorageClasses struct {
Fake *FakeExperimental
}
// Ensure statically that FakeStorageClasses implements StorageClassInterface.
var _ kclientlib.StorageClassInterface = &FakeStorageClasses{}
func (c *FakeStorageClasses) Get(name string) (*extensions.StorageClass, error) {
obj, err := c.Fake.Invokes(NewGetAction("storageclasses", "", name), &extensions.StorageClass{})
if obj == nil {
return nil, err
}
return obj.(*extensions.StorageClass), err
}
func (c *FakeStorageClasses) List(opts api.ListOptions) (*extensions.StorageClassList, error) {
obj, err := c.Fake.Invokes(NewListAction("storageclasses", "", opts), &extensions.StorageClassList{})
if obj == nil {
return nil, err
}
return obj.(*extensions.StorageClassList), err
}
func (c *FakeStorageClasses) Create(np *extensions.StorageClass) (*extensions.StorageClass, error) {
obj, err := c.Fake.Invokes(NewCreateAction("storageclasses", "", np), &extensions.StorageClass{})
if obj == nil {
return nil, err
}
return obj.(*extensions.StorageClass), err
}
func (c *FakeStorageClasses) Update(np *extensions.StorageClass) (*extensions.StorageClass, error) {
obj, err := c.Fake.Invokes(NewUpdateAction("storageclasses", "", np), &extensions.StorageClass{})
if obj == nil {
return nil, err
}
return obj.(*extensions.StorageClass), err
}
func (c *FakeStorageClasses) Delete(name string) error {
_, err := c.Fake.Invokes(NewDeleteAction("storageclasses", "", name), &extensions.StorageClass{})
return err
}
func (c *FakeStorageClasses) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.InvokesWatch(NewWatchAction("storageclasses", "", opts))
}
...@@ -411,6 +411,10 @@ func (c *FakeExperimental) NetworkPolicies(namespace string) client.NetworkPolic ...@@ -411,6 +411,10 @@ func (c *FakeExperimental) NetworkPolicies(namespace string) client.NetworkPolic
return &FakeNetworkPolicies{Fake: c, Namespace: namespace} return &FakeNetworkPolicies{Fake: c, Namespace: namespace}
} }
func (c *FakeExperimental) StorageClasses() client.StorageClassInterface {
return &FakeStorageClasses{Fake: c}
}
func NewSimpleFakeRbac(objects ...runtime.Object) *FakeRbac { func NewSimpleFakeRbac(objects ...runtime.Object) *FakeRbac {
return &FakeRbac{Fake: NewSimpleFake(objects...)} return &FakeRbac{Fake: NewSimpleFake(objects...)}
} }
......
...@@ -100,6 +100,7 @@ import ( ...@@ -100,6 +100,7 @@ import (
serviceetcd "k8s.io/kubernetes/pkg/registry/service/etcd" serviceetcd "k8s.io/kubernetes/pkg/registry/service/etcd"
ipallocator "k8s.io/kubernetes/pkg/registry/service/ipallocator" ipallocator "k8s.io/kubernetes/pkg/registry/service/ipallocator"
serviceaccountetcd "k8s.io/kubernetes/pkg/registry/serviceaccount/etcd" serviceaccountetcd "k8s.io/kubernetes/pkg/registry/serviceaccount/etcd"
storageclassetcd "k8s.io/kubernetes/pkg/registry/storageclass/etcd"
thirdpartyresourceetcd "k8s.io/kubernetes/pkg/registry/thirdpartyresource/etcd" thirdpartyresourceetcd "k8s.io/kubernetes/pkg/registry/thirdpartyresource/etcd"
"k8s.io/kubernetes/pkg/registry/thirdpartyresourcedata" "k8s.io/kubernetes/pkg/registry/thirdpartyresourcedata"
thirdpartyresourcedataetcd "k8s.io/kubernetes/pkg/registry/thirdpartyresourcedata/etcd" thirdpartyresourcedataetcd "k8s.io/kubernetes/pkg/registry/thirdpartyresourcedata/etcd"
...@@ -807,6 +808,10 @@ func (m *Master) getExtensionResources(c *Config) map[string]rest.Storage { ...@@ -807,6 +808,10 @@ func (m *Master) getExtensionResources(c *Config) map[string]rest.Storage {
if c.APIResourceConfigSource.ResourceEnabled(version.WithResource("networkpolicies")) { if c.APIResourceConfigSource.ResourceEnabled(version.WithResource("networkpolicies")) {
storage["networkpolicies"] = networkPolicyStorage storage["networkpolicies"] = networkPolicyStorage
} }
storageClassStorage := storageclassetcd.NewREST(restOptions("storageclasses"))
if c.APIResourceConfigSource.ResourceEnabled(version.WithResource("storageclasses")) {
storage["storageclasses"] = storageClassStorage
}
return storage return storage
} }
...@@ -1057,6 +1062,7 @@ func DefaultAPIResourceConfigSource() *genericapiserver.ResourceConfig { ...@@ -1057,6 +1062,7 @@ func DefaultAPIResourceConfigSource() *genericapiserver.ResourceConfig {
extensionsapiv1beta1.SchemeGroupVersion.WithResource("networkpolicies"), extensionsapiv1beta1.SchemeGroupVersion.WithResource("networkpolicies"),
extensionsapiv1beta1.SchemeGroupVersion.WithResource("replicasets"), extensionsapiv1beta1.SchemeGroupVersion.WithResource("replicasets"),
extensionsapiv1beta1.SchemeGroupVersion.WithResource("thirdpartyresources"), extensionsapiv1beta1.SchemeGroupVersion.WithResource("thirdpartyresources"),
extensionsapiv1beta1.SchemeGroupVersion.WithResource("storageclasses"),
) )
return ret return ret
......
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package storageClass provides Registry interface and its REST
// implementation for storing storageclass api objects.
package storageclass
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package etcd
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/registry/generic/registry"
"k8s.io/kubernetes/pkg/registry/storageclass"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
)
type REST struct {
*registry.Store
}
// NewREST returns a RESTStorage object that will work against persistent volumes.
func NewREST(opts generic.RESTOptions) *REST {
prefix := "/storageclasses"
newListFunc := func() runtime.Object { return &extensions.StorageClassList{} }
storageInterface := opts.Decorator(
opts.Storage,
100,
&extensions.StorageClass{},
prefix,
storageclass.Strategy,
newListFunc,
storage.NoTriggerPublisher,
)
store := &registry.Store{
NewFunc: func() runtime.Object { return &extensions.StorageClass{} },
NewListFunc: newListFunc,
KeyRootFunc: func(ctx api.Context) string {
return prefix
},
KeyFunc: func(ctx api.Context, name string) (string, error) {
return registry.NoNamespaceKeyFunc(ctx, prefix, name)
},
ObjectNameFunc: func(obj runtime.Object) (string, error) {
return obj.(*extensions.StorageClass).Name, nil
},
PredicateFunc: storageclass.MatchStorageClasses,
QualifiedResource: api.Resource("storageclasses"),
DeleteCollectionWorkers: opts.DeleteCollectionWorkers,
CreateStrategy: storageclass.Strategy,
UpdateStrategy: storageclass.Strategy,
DeleteStrategy: storageclass.Strategy,
ReturnDeletedObject: true,
Storage: storageInterface,
}
return &REST{store}
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package etcd
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime"
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
)
func newStorage(t *testing.T) (*REST, *etcdtesting.EtcdTestServer) {
etcdStorage, server := registrytest.NewEtcdStorage(t, extensions.GroupName)
restOptions := generic.RESTOptions{Storage: etcdStorage, Decorator: generic.UndecoratedStorage, DeleteCollectionWorkers: 1}
storageClassStorage := NewREST(restOptions)
return storageClassStorage, server
}
func validNewStorageClass(name string) *extensions.StorageClass {
return &extensions.StorageClass{
ObjectMeta: api.ObjectMeta{
Name: name,
},
Provisioner: "kubernetes.io/aws-ebs",
Parameters: map[string]string{
"foo": "bar",
},
}
}
func validChangedStorageClass() *extensions.StorageClass {
return validNewStorageClass("foo")
}
func TestCreate(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Store).ClusterScope()
storageClass := validNewStorageClass("foo")
storageClass.ObjectMeta = api.ObjectMeta{GenerateName: "foo"}
test.TestCreate(
// valid
storageClass,
// invalid
&extensions.StorageClass{
ObjectMeta: api.ObjectMeta{Name: "*BadName!"},
},
)
}
func TestUpdate(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Store).ClusterScope()
test.TestUpdate(
// valid
validNewStorageClass("foo"),
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*extensions.StorageClass)
object.Parameters = map[string]string{"foo": "bar"}
return object
},
//invalid update
func(obj runtime.Object) runtime.Object {
object := obj.(*extensions.StorageClass)
object.Parameters = map[string]string{"faz": "bar"}
return object
},
)
}
func TestDelete(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Store).ClusterScope().ReturnDeletedObject()
test.TestDelete(validNewStorageClass("foo"))
}
func TestGet(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Store).ClusterScope()
test.TestGet(validNewStorageClass("foo"))
}
func TestList(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Store).ClusterScope()
test.TestList(validNewStorageClass("foo"))
}
func TestWatch(t *testing.T) {
storage, server := newStorage(t)
defer server.Terminate(t)
test := registrytest.New(t, storage.Store).ClusterScope()
test.TestWatch(
validNewStorageClass("foo"),
// matching labels
[]labels.Set{},
// not matching labels
[]labels.Set{
{"foo": "bar"},
},
// matching fields
[]fields.Set{
{"metadata.name": "foo"},
},
// not matching fields
[]fields.Set{
{"metadata.name": "bar"},
},
)
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package storageclass
import (
"fmt"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/extensions/validation"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/validation/field"
)
// storageClassStrategy implements behavior for StorageClass objects
type storageClassStrategy struct {
runtime.ObjectTyper
api.NameGenerator
}
// Strategy is the default logic that applies when creating and updating
// StorageClass objects via the REST API.
var Strategy = storageClassStrategy{api.Scheme, api.SimpleNameGenerator}
func (storageClassStrategy) NamespaceScoped() bool {
return false
}
// ResetBeforeCreate clears the Status field which is not allowed to be set by end users on creation.
func (storageClassStrategy) PrepareForCreate(obj runtime.Object) {
_ = obj.(*extensions.StorageClass)
}
func (storageClassStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList {
storageClass := obj.(*extensions.StorageClass)
return validation.ValidateStorageClass(storageClass)
}
// Canonicalize normalizes the object after validation.
func (storageClassStrategy) Canonicalize(obj runtime.Object) {
}
func (storageClassStrategy) AllowCreateOnUpdate() bool {
return false
}
// PrepareForUpdate sets the Status fields which is not allowed to be set by an end user updating a PV
func (storageClassStrategy) PrepareForUpdate(obj, old runtime.Object) {
_ = obj.(*extensions.StorageClass)
_ = old.(*extensions.StorageClass)
}
func (storageClassStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList {
errorList := validation.ValidateStorageClass(obj.(*extensions.StorageClass))
return append(errorList, validation.ValidateStorageClassUpdate(obj.(*extensions.StorageClass), old.(*extensions.StorageClass))...)
}
func (storageClassStrategy) AllowUnconditionalUpdate() bool {
return true
}
// MatchStorageClass returns a generic matcher for a given label and field selector.
func MatchStorageClasses(label labels.Selector, field fields.Selector) generic.Matcher {
return &generic.SelectionPredicate{
Label: label,
Field: field,
GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
cls, ok := obj.(*extensions.StorageClass)
if !ok {
return nil, nil, fmt.Errorf("given object is not of type StorageClass")
}
return labels.Set(cls.ObjectMeta.Labels), StorageClassToSelectableFields(cls), nil
},
}
}
// StorageClassToSelectableFields returns a label set that represents the object
func StorageClassToSelectableFields(storageClass *extensions.StorageClass) fields.Set {
return generic.ObjectMetaFieldsSet(storageClass.ObjectMeta, false)
}
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package storageclass
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions"
)
func TestStorageClassStrategy(t *testing.T) {
ctx := api.NewDefaultContext()
if Strategy.NamespaceScoped() {
t.Errorf("StorageClass must not be namespace scoped")
}
if Strategy.AllowCreateOnUpdate() {
t.Errorf("StorageClass should not allow create on update")
}
storageClass := &extensions.StorageClass{
ObjectMeta: api.ObjectMeta{
Name: "valid-class",
},
Provisioner: "kubernetes.io/aws-ebs",
Parameters: map[string]string{
"foo": "bar",
},
}
Strategy.PrepareForCreate(storageClass)
errs := Strategy.Validate(ctx, storageClass)
if len(errs) != 0 {
t.Errorf("unexpected error validating %v", errs)
}
newStorageClass := &extensions.StorageClass{
ObjectMeta: api.ObjectMeta{
Name: "valid-class-2",
ResourceVersion: "4",
},
Provisioner: "kubernetes.io/aws-ebs",
Parameters: map[string]string{
"foo": "bar",
},
}
Strategy.PrepareForUpdate(newStorageClass, storageClass)
errs = Strategy.ValidateUpdate(ctx, newStorageClass, storageClass)
if len(errs) == 0 {
t.Errorf("Expected a validation error")
}
}
// +build integration,!no-etcd
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package storageclasses
// This file contains tests for the storage classes API resource.
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/restclient"
client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/test/integration/framework"
)
const provisionerPluginName = "kubernetes.io/mock-provisioner"
// TestStorageClasses tests apiserver-side behavior of creation of storage class objects and their use by pvcs.
func TestStorageClasses(t *testing.T) {
_, s := framework.RunAMaster(nil)
defer s.Close()
client := client.NewOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}})
ns := framework.CreateTestingNamespace("storageclass", s, t)
defer framework.DeleteTestingNamespace(ns, s, t)
DoTestStorageClasses(t, client, ns)
}
// DoTestStorageClasses tests storage classes for one api version.
func DoTestStorageClasses(t *testing.T, client *client.Client, ns *api.Namespace) {
// Make a storage class object.
s := extensions.StorageClass{
TypeMeta: unversioned.TypeMeta{
Kind: "StorageClass",
},
ObjectMeta: api.ObjectMeta{
Name: "gold",
},
Provisioner: provisionerPluginName,
}
if _, err := client.Extensions().StorageClasses().Create(&s); err != nil {
t.Errorf("unable to create test storage class: %v", err)
}
defer deleteStorageClassOrErrorf(t, client, s.Namespace, s.Name)
// Template for pvcs that specify a storage class
pvc := &api.PersistentVolumeClaim{
ObjectMeta: api.ObjectMeta{
Name: "XXX",
Namespace: ns.Name,
Annotations: map[string]string{
"volume.beta.kubernetes.io/storage-class": "gold",
},
},
Spec: api.PersistentVolumeClaimSpec{
Resources: api.ResourceRequirements{Requests: api.ResourceList{api.ResourceName(api.ResourceStorage): resource.MustParse("1G")}},
AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
},
}
pvc.ObjectMeta.Name = "uses-storageclass"
if _, err := client.PersistentVolumeClaims(ns.Name).Create(pvc); err != nil {
t.Errorf("Failed to create pvc: %v", err)
}
defer deletePersistentVolumeClaimOrErrorf(t, client, ns.Name, pvc.Name)
}
func deleteStorageClassOrErrorf(t *testing.T, c *client.Client, ns, name string) {
if err := c.Extensions().StorageClasses().Delete(name); err != nil {
t.Errorf("unable to delete storage class %v: %v", name, err)
}
}
func deletePersistentVolumeClaimOrErrorf(t *testing.T, c *client.Client, ns, name string) {
if err := c.PersistentVolumeClaims(ns).Delete(name); err != nil {
t.Errorf("unable to delete persistent volume claim %v: %v", name, err)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment