mirror of
https://github.com/open-cluster-management-io/ocm.git
synced 2026-08-23 22:26:49 +00:00
Merge pull request #7 from skeeey/master
implement the hub controller to reconcile SpokeCluster
This commit is contained in:
@@ -7,8 +7,11 @@ include $(addprefix ./vendor/github.com/openshift/build-machinery-go/make/, \
|
||||
golang.mk \
|
||||
targets/openshift/deps.mk \
|
||||
targets/openshift/images.mk \
|
||||
targets/openshift/bindata.mk \
|
||||
)
|
||||
|
||||
$(call add-bindata,spokecluster,./pkg/hub/spokecluster/manifests/...,bindata,bindata,./pkg/hub/spokecluster/bindata/bindata.go)
|
||||
|
||||
clean:
|
||||
$(RM) ./registration
|
||||
.PHONY: clean
|
||||
|
||||
@@ -5,5 +5,6 @@
|
||||
package dependencymagnet
|
||||
|
||||
import (
|
||||
_ "github.com/jteeuwen/go-bindata/go-bindata"
|
||||
_ "github.com/openshift/build-machinery-go"
|
||||
)
|
||||
|
||||
@@ -3,6 +3,8 @@ module github.com/open-cluster-management/registration
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/jteeuwen/go-bindata v3.0.8-0.20151023091102-a0ff2567cfb7+incompatible
|
||||
github.com/open-cluster-management/api v0.0.0-20200407195507-bec5ad33c0fe
|
||||
github.com/openshift/build-machinery-go v0.0.0-20200211121458-5e3d6e570160
|
||||
github.com/openshift/library-go v0.0.0-20200401114229-ffab8c6e83a9
|
||||
github.com/spf13/cobra v0.0.5
|
||||
|
||||
@@ -91,12 +91,14 @@ github.com/fsouza/go-dockerclient v0.0.0-20171004212419-da3951ba2e9e/go.mod h1:K
|
||||
github.com/getsentry/raven-go v0.0.0-20190513200303-c977f96e1095 h1:F2m41rgyxoveZKD+Z6xwyAbtdNeVvhpi9BpQLvt5oRU=
|
||||
github.com/getsentry/raven-go v0.0.0-20190513200303-c977f96e1095/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
|
||||
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
||||
@@ -220,6 +222,7 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
|
||||
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jteeuwen/go-bindata v3.0.8-0.20151023091102-a0ff2567cfb7+incompatible h1:KTM14h3AKWWcPf5IWS/pcFTZosRmoqdIYzqi0mMG7es=
|
||||
github.com/jteeuwen/go-bindata v3.0.8-0.20151023091102-a0ff2567cfb7+incompatible/go.mod h1:JVvhzYOiGBnFSYRyV00iY8q7/0PThjIYav1p9h5dmKs=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
@@ -270,6 +273,8 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/open-cluster-management/api v0.0.0-20200407195507-bec5ad33c0fe h1:utjVkRygzHU7o+BO89pfuyXa//eH+7RAzMfOvwuzxKQ=
|
||||
github.com/open-cluster-management/api v0.0.0-20200407195507-bec5ad33c0fe/go.mod h1:RgKeB8PJ7upe2QXy/MpCejU/xm2G6/i0Y+/itWuPugs=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v0.0.0-20191031171055-b133feaeeb2e/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
@@ -404,6 +409,8 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -437,6 +444,8 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -452,6 +461,7 @@ golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgw
|
||||
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200115044656-831fdb1e1868/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
@@ -498,6 +508,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.18.0 h1:lwYk8Vt7rsVTwjRU6pzEsa9YNhThbmbocQlKvNBB4EQ=
|
||||
k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8=
|
||||
k8s.io/apiextensions-apiserver v0.18.0 h1:HN4/P8vpGZFvB5SOMuPPH2Wt9Y/ryX+KRvIyAkchu1Q=
|
||||
k8s.io/apiextensions-apiserver v0.18.0/go.mod h1:18Cwn1Xws4xnWQNC00FLq1E350b9lUF+aOdIWDOZxgo=
|
||||
k8s.io/apimachinery v0.18.0 h1:fuPfYpk3cs1Okp/515pAf0dNhL66+8zk8RLbSX+EgAE=
|
||||
k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA=
|
||||
@@ -514,11 +525,14 @@ k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUc
|
||||
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/kube-aggregator v0.18.0 h1:J+wa9FDQ3SbgyA8wQBNg2m2FMSm+mMQfs2A58500hs0=
|
||||
k8s.io/kube-aggregator v0.18.0/go.mod h1:ateewQ5QbjMZF/dihEFXwaEwoA4v/mayRvzfmvb6eqI=
|
||||
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c h1:/KUFqjjqAcY4Us6luF5RDNZ16KJtb49HfR3ZHB9qYXM=
|
||||
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU=
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/utils v0.0.0-20200327001022-6496210b90e8 h1:6JFbaLjRyBz8K2Jvt+pcT+N3vvwMZfg8MfVENwe9aag=
|
||||
k8s.io/utils v0.0.0-20200327001022-6496210b90e8/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7 h1:uuHDyjllyzRyCIvvn0OBjiRB0SgBZGqHNYAmjR7fO50=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
spokeclusterclientset "github.com/open-cluster-management/api/client/cluster/clientset/versioned"
|
||||
spokeclusterv1 "github.com/open-cluster-management/api/cluster/v1"
|
||||
"k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/util/retry"
|
||||
)
|
||||
|
||||
func IsConditionTrue(condition *spokeclusterv1.StatusCondition) bool {
|
||||
if condition == nil {
|
||||
return false
|
||||
}
|
||||
return condition.Status == metav1.ConditionTrue
|
||||
}
|
||||
|
||||
func FindSpokeClusterCondition(conditions []spokeclusterv1.StatusCondition, conditionType string) *spokeclusterv1.StatusCondition {
|
||||
for i := range conditions {
|
||||
if conditions[i].Type == conditionType {
|
||||
return &conditions[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetSpokeClusterCondition(conditions *[]spokeclusterv1.StatusCondition, newCondition spokeclusterv1.StatusCondition) {
|
||||
if conditions == nil {
|
||||
conditions = &[]spokeclusterv1.StatusCondition{}
|
||||
}
|
||||
existingCondition := FindSpokeClusterCondition(*conditions, newCondition.Type)
|
||||
if existingCondition == nil {
|
||||
newCondition.LastTransitionTime = metav1.NewTime(time.Now())
|
||||
*conditions = append(*conditions, newCondition)
|
||||
return
|
||||
}
|
||||
|
||||
if existingCondition.Status != newCondition.Status {
|
||||
existingCondition.Status = newCondition.Status
|
||||
existingCondition.LastTransitionTime = metav1.NewTime(time.Now())
|
||||
}
|
||||
|
||||
existingCondition.Reason = newCondition.Reason
|
||||
existingCondition.Message = newCondition.Message
|
||||
}
|
||||
|
||||
type UpdateSpokeClusterStatusFunc func(status *spokeclusterv1.SpokeClusterStatus) error
|
||||
|
||||
func UpdateSpokeClusterStatus(
|
||||
ctx context.Context,
|
||||
client spokeclusterclientset.Interface,
|
||||
spokeClusterName string,
|
||||
updateFuncs ...UpdateSpokeClusterStatusFunc) (*spokeclusterv1.SpokeClusterStatus, bool, error) {
|
||||
updated := false
|
||||
var updatedSpokeClusterStatus *spokeclusterv1.SpokeClusterStatus
|
||||
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
||||
spokeCluster, err := client.ClusterV1().SpokeClusters().Get(ctx, spokeClusterName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldStatus := &spokeCluster.Status
|
||||
|
||||
newStatus := oldStatus.DeepCopy()
|
||||
for _, update := range updateFuncs {
|
||||
if err := update(newStatus); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if equality.Semantic.DeepEqual(oldStatus, newStatus) {
|
||||
// We return the newStatus which is a deep copy of oldStatus but with all update funcs applied.
|
||||
updatedSpokeClusterStatus = newStatus
|
||||
return nil
|
||||
}
|
||||
|
||||
spokeCluster.Status = *newStatus
|
||||
updatedSpokeCluster, err := client.ClusterV1().SpokeClusters().UpdateStatus(ctx, spokeCluster, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedSpokeClusterStatus = &updatedSpokeCluster.Status
|
||||
updated = err == nil
|
||||
return err
|
||||
})
|
||||
|
||||
return updatedSpokeClusterStatus, updated, err
|
||||
}
|
||||
|
||||
func UpdateSpokeClusterConditionFn(cond spokeclusterv1.StatusCondition) UpdateSpokeClusterStatusFunc {
|
||||
return func(oldStatus *spokeclusterv1.SpokeClusterStatus) error {
|
||||
SetSpokeClusterCondition(&oldStatus.Conditions, cond)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
clusterfake "github.com/open-cluster-management/api/client/cluster/clientset/versioned/fake"
|
||||
spokeclusterv1 "github.com/open-cluster-management/api/cluster/v1"
|
||||
"k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
)
|
||||
|
||||
func TestUpdateStatusCondition(t *testing.T) {
|
||||
nowish := metav1.Now()
|
||||
beforeish := metav1.Time{Time: nowish.Add(-10 * time.Second)}
|
||||
afterish := metav1.Time{Time: nowish.Add(10 * time.Second)}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
startingConditions []spokeclusterv1.StatusCondition
|
||||
newCondition spokeclusterv1.StatusCondition
|
||||
expextedUpdated bool
|
||||
expectedConditions []spokeclusterv1.StatusCondition
|
||||
}{
|
||||
{
|
||||
name: "add to empty",
|
||||
startingConditions: []spokeclusterv1.StatusCondition{},
|
||||
newCondition: newCondition("test", "True", "my-reason", "my-message", nil),
|
||||
expextedUpdated: true,
|
||||
expectedConditions: []spokeclusterv1.StatusCondition{newCondition("test", "True", "my-reason", "my-message", nil)},
|
||||
},
|
||||
{
|
||||
name: "add to non-conflicting",
|
||||
startingConditions: []spokeclusterv1.StatusCondition{
|
||||
newCondition("two", "True", "my-reason", "my-message", nil),
|
||||
},
|
||||
newCondition: newCondition("one", "True", "my-reason", "my-message", nil),
|
||||
expextedUpdated: true,
|
||||
expectedConditions: []spokeclusterv1.StatusCondition{
|
||||
newCondition("two", "True", "my-reason", "my-message", nil),
|
||||
newCondition("one", "True", "my-reason", "my-message", nil),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change existing status",
|
||||
startingConditions: []spokeclusterv1.StatusCondition{
|
||||
newCondition("two", "True", "my-reason", "my-message", nil),
|
||||
newCondition("one", "True", "my-reason", "my-message", nil),
|
||||
},
|
||||
newCondition: newCondition("one", "False", "my-different-reason", "my-othermessage", nil),
|
||||
expextedUpdated: true,
|
||||
expectedConditions: []spokeclusterv1.StatusCondition{
|
||||
newCondition("two", "True", "my-reason", "my-message", nil),
|
||||
newCondition("one", "False", "my-different-reason", "my-othermessage", nil),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "leave existing transition time",
|
||||
startingConditions: []spokeclusterv1.StatusCondition{
|
||||
newCondition("two", "True", "my-reason", "my-message", nil),
|
||||
newCondition("one", "True", "my-reason", "my-message", &beforeish),
|
||||
},
|
||||
newCondition: newCondition("one", "True", "my-reason", "my-message", &afterish),
|
||||
expextedUpdated: false,
|
||||
expectedConditions: []spokeclusterv1.StatusCondition{
|
||||
newCondition("two", "True", "my-reason", "my-message", nil),
|
||||
newCondition("one", "True", "my-reason", "my-message", &beforeish),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
fakeClusterClient := clusterfake.NewSimpleClientset(&spokeclusterv1.SpokeCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "testspokecluster"},
|
||||
Status: spokeclusterv1.SpokeClusterStatus{
|
||||
Conditions: c.startingConditions,
|
||||
},
|
||||
})
|
||||
|
||||
status, updated, err := UpdateSpokeClusterStatus(
|
||||
context.TODO(),
|
||||
fakeClusterClient,
|
||||
"testspokecluster",
|
||||
UpdateSpokeClusterConditionFn(c.newCondition),
|
||||
)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected err: %v", err)
|
||||
}
|
||||
if updated != c.expextedUpdated {
|
||||
t.Errorf("expected %t, but %t", c.expextedUpdated, updated)
|
||||
}
|
||||
for i := range c.expectedConditions {
|
||||
expected := c.expectedConditions[i]
|
||||
actual := status.Conditions[i]
|
||||
if expected.LastTransitionTime == (metav1.Time{}) {
|
||||
actual.LastTransitionTime = metav1.Time{}
|
||||
}
|
||||
if !equality.Semantic.DeepEqual(expected, actual) {
|
||||
t.Errorf(diff.ObjectDiff(expected, actual))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newCondition(name, status, reason, message string, lastTransition *metav1.Time) spokeclusterv1.StatusCondition {
|
||||
ret := spokeclusterv1.StatusCondition{
|
||||
Type: name,
|
||||
Status: metav1.ConditionStatus(status),
|
||||
Reason: reason,
|
||||
Message: message,
|
||||
}
|
||||
if lastTransition != nil {
|
||||
ret.LastTransitionTime = *lastTransition
|
||||
}
|
||||
return ret
|
||||
}
|
||||
+23
-1
@@ -2,15 +2,37 @@ package hub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/openshift/library-go/pkg/controller/controllercmd"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
clusterv1client "github.com/open-cluster-management/api/client/cluster/clientset/versioned"
|
||||
clusterv1informers "github.com/open-cluster-management/api/client/cluster/informers/externalversions"
|
||||
"github.com/open-cluster-management/registration/pkg/hub/spokecluster"
|
||||
)
|
||||
|
||||
// RunControllerManager starts the controllers on hub to manage spoke cluster registraiton.
|
||||
func RunControllerManager(ctx context.Context, controllerContext *controllercmd.ControllerContext) error {
|
||||
spokeClusterController := spokecluster.NewController(controllerContext.EventRecorder)
|
||||
kubeClient, err := kubernetes.NewForConfig(controllerContext.KubeConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clusterClient, err := clusterv1client.NewForConfig(controllerContext.KubeConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clusterInformers := clusterv1informers.NewSharedInformerFactory(clusterClient, 10*time.Minute)
|
||||
|
||||
spokeClusterController := spokecluster.NewSpokeClusterController(
|
||||
kubeClient,
|
||||
clusterClient,
|
||||
clusterInformers.Cluster().V1().SpokeClusters().Informer(),
|
||||
controllerContext.EventRecorder,
|
||||
)
|
||||
|
||||
go clusterInformers.Start(ctx.Done())
|
||||
|
||||
go spokeClusterController.Run(ctx, 1)
|
||||
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
// Code generated by go-bindata.
|
||||
// sources:
|
||||
// pkg/hub/spokecluster/manifests/spokecluster-clusterrole.yaml
|
||||
// pkg/hub/spokecluster/manifests/spokecluster-clusterrolebinding.yaml
|
||||
// pkg/hub/spokecluster/manifests/spokecluster-namespace.yaml
|
||||
// pkg/hub/spokecluster/manifests/spokecluster-role.yaml
|
||||
// pkg/hub/spokecluster/manifests/spokecluster-rolebinding.yaml
|
||||
// DO NOT EDIT!
|
||||
|
||||
package bindata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type asset struct {
|
||||
bytes []byte
|
||||
info os.FileInfo
|
||||
}
|
||||
|
||||
type bindataFileInfo struct {
|
||||
name string
|
||||
size int64
|
||||
mode os.FileMode
|
||||
modTime time.Time
|
||||
}
|
||||
|
||||
func (fi bindataFileInfo) Name() string {
|
||||
return fi.name
|
||||
}
|
||||
func (fi bindataFileInfo) Size() int64 {
|
||||
return fi.size
|
||||
}
|
||||
func (fi bindataFileInfo) Mode() os.FileMode {
|
||||
return fi.mode
|
||||
}
|
||||
func (fi bindataFileInfo) ModTime() time.Time {
|
||||
return fi.modTime
|
||||
}
|
||||
func (fi bindataFileInfo) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
func (fi bindataFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _pkgHubSpokeclusterManifestsSpokeclusterClusterroleYaml = []byte(`apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: system:open-cluster-management:spokecluster:{{ .SpokeClusterName }}
|
||||
rules:
|
||||
# Allow spoke agent to rotate its certificate
|
||||
- apiGroups: ["certificates.k8s.io"]
|
||||
resources: ["certificatesigningrequests/spokeclusteragent"]
|
||||
verbs: ["create"]
|
||||
# Allow spoke agent to get/list/watch its owner spoke cluster
|
||||
- apiGroups: ["cluster.open-cluster-management.io"]
|
||||
resources: ["spokeclusters"]
|
||||
resourceNames: ["{{ .SpokeClusterName }}"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
# Allow spoke agent to update the status of its owner spoke cluster
|
||||
- apiGroups: ["cluster.open-cluster-management.io"]
|
||||
resources: ["spokeclusters/status"]
|
||||
resourceNames: ["{{ .SpokeClusterName }}"]
|
||||
verbs: ["patch", "update"]
|
||||
`)
|
||||
|
||||
func pkgHubSpokeclusterManifestsSpokeclusterClusterroleYamlBytes() ([]byte, error) {
|
||||
return _pkgHubSpokeclusterManifestsSpokeclusterClusterroleYaml, nil
|
||||
}
|
||||
|
||||
func pkgHubSpokeclusterManifestsSpokeclusterClusterroleYaml() (*asset, error) {
|
||||
bytes, err := pkgHubSpokeclusterManifestsSpokeclusterClusterroleYamlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "pkg/hub/spokecluster/manifests/spokecluster-clusterrole.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _pkgHubSpokeclusterManifestsSpokeclusterClusterrolebindingYaml = []byte(`apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: system:open-cluster-management:spokecluster:{{ .SpokeClusterName }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: system:open-cluster-management:spokecluster:{{ .SpokeClusterName }}
|
||||
subjects:
|
||||
- kind: Group
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
name: system:open-cluster-management:spokecluster:{{ .SpokeClusterName }}`)
|
||||
|
||||
func pkgHubSpokeclusterManifestsSpokeclusterClusterrolebindingYamlBytes() ([]byte, error) {
|
||||
return _pkgHubSpokeclusterManifestsSpokeclusterClusterrolebindingYaml, nil
|
||||
}
|
||||
|
||||
func pkgHubSpokeclusterManifestsSpokeclusterClusterrolebindingYaml() (*asset, error) {
|
||||
bytes, err := pkgHubSpokeclusterManifestsSpokeclusterClusterrolebindingYamlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "pkg/hub/spokecluster/manifests/spokecluster-clusterrolebinding.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _pkgHubSpokeclusterManifestsSpokeclusterNamespaceYaml = []byte(`apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: {{ .SpokeClusterName }}`)
|
||||
|
||||
func pkgHubSpokeclusterManifestsSpokeclusterNamespaceYamlBytes() ([]byte, error) {
|
||||
return _pkgHubSpokeclusterManifestsSpokeclusterNamespaceYaml, nil
|
||||
}
|
||||
|
||||
func pkgHubSpokeclusterManifestsSpokeclusterNamespaceYaml() (*asset, error) {
|
||||
bytes, err := pkgHubSpokeclusterManifestsSpokeclusterNamespaceYamlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "pkg/hub/spokecluster/manifests/spokecluster-namespace.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _pkgHubSpokeclusterManifestsSpokeclusterRoleYaml = []byte(`apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ .SpokeClusterName }}
|
||||
namespace: {{ .SpokeClusterName }}
|
||||
# TODO add rules later
|
||||
# rules: []
|
||||
`)
|
||||
|
||||
func pkgHubSpokeclusterManifestsSpokeclusterRoleYamlBytes() ([]byte, error) {
|
||||
return _pkgHubSpokeclusterManifestsSpokeclusterRoleYaml, nil
|
||||
}
|
||||
|
||||
func pkgHubSpokeclusterManifestsSpokeclusterRoleYaml() (*asset, error) {
|
||||
bytes, err := pkgHubSpokeclusterManifestsSpokeclusterRoleYamlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "pkg/hub/spokecluster/manifests/spokecluster-role.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _pkgHubSpokeclusterManifestsSpokeclusterRolebindingYaml = []byte(`apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ .SpokeClusterName }}
|
||||
namespace: {{ .SpokeClusterName }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: {{ .SpokeClusterName }}
|
||||
subjects:
|
||||
# Bind the role with spoke agent user group, the role will be as a common role for all spoke agents
|
||||
# TODO: we will consider bind a specific role for each spoke agent by spoke agent name
|
||||
- kind: Group
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
name: system:open-cluster-management:{{ .SpokeClusterName }}
|
||||
`)
|
||||
|
||||
func pkgHubSpokeclusterManifestsSpokeclusterRolebindingYamlBytes() ([]byte, error) {
|
||||
return _pkgHubSpokeclusterManifestsSpokeclusterRolebindingYaml, nil
|
||||
}
|
||||
|
||||
func pkgHubSpokeclusterManifestsSpokeclusterRolebindingYaml() (*asset, error) {
|
||||
bytes, err := pkgHubSpokeclusterManifestsSpokeclusterRolebindingYamlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "pkg/hub/spokecluster/manifests/spokecluster-rolebinding.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Asset loads and returns the asset for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func Asset(name string) ([]byte, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.bytes, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
|
||||
// MustAsset is like Asset but panics when Asset would return an error.
|
||||
// It simplifies safe initialization of global variables.
|
||||
func MustAsset(name string) []byte {
|
||||
a, err := Asset(name)
|
||||
if err != nil {
|
||||
panic("asset: Asset(" + name + "): " + err.Error())
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// AssetInfo loads and returns the asset info for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func AssetInfo(name string) (os.FileInfo, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.info, nil
|
||||
}
|
||||
return nil, fmt.Errorf("AssetInfo %s not found", name)
|
||||
}
|
||||
|
||||
// AssetNames returns the names of the assets.
|
||||
func AssetNames() []string {
|
||||
names := make([]string, 0, len(_bindata))
|
||||
for name := range _bindata {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() (*asset, error){
|
||||
"pkg/hub/spokecluster/manifests/spokecluster-clusterrole.yaml": pkgHubSpokeclusterManifestsSpokeclusterClusterroleYaml,
|
||||
"pkg/hub/spokecluster/manifests/spokecluster-clusterrolebinding.yaml": pkgHubSpokeclusterManifestsSpokeclusterClusterrolebindingYaml,
|
||||
"pkg/hub/spokecluster/manifests/spokecluster-namespace.yaml": pkgHubSpokeclusterManifestsSpokeclusterNamespaceYaml,
|
||||
"pkg/hub/spokecluster/manifests/spokecluster-role.yaml": pkgHubSpokeclusterManifestsSpokeclusterRoleYaml,
|
||||
"pkg/hub/spokecluster/manifests/spokecluster-rolebinding.yaml": pkgHubSpokeclusterManifestsSpokeclusterRolebindingYaml,
|
||||
}
|
||||
|
||||
// AssetDir returns the file names below a certain
|
||||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
// AssetDir("") will return []string{"data"}.
|
||||
func AssetDir(name string) ([]string, error) {
|
||||
node := _bintree
|
||||
if len(name) != 0 {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
pathList := strings.Split(cannonicalName, "/")
|
||||
for _, p := range pathList {
|
||||
node = node.Children[p]
|
||||
if node == nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.Func != nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
rv := make([]string, 0, len(node.Children))
|
||||
for childName := range node.Children {
|
||||
rv = append(rv, childName)
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
type bintree struct {
|
||||
Func func() (*asset, error)
|
||||
Children map[string]*bintree
|
||||
}
|
||||
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"pkg": {nil, map[string]*bintree{
|
||||
"hub": {nil, map[string]*bintree{
|
||||
"spokecluster": {nil, map[string]*bintree{
|
||||
"manifests": {nil, map[string]*bintree{
|
||||
"spokecluster-clusterrole.yaml": {pkgHubSpokeclusterManifestsSpokeclusterClusterroleYaml, map[string]*bintree{}},
|
||||
"spokecluster-clusterrolebinding.yaml": {pkgHubSpokeclusterManifestsSpokeclusterClusterrolebindingYaml, map[string]*bintree{}},
|
||||
"spokecluster-namespace.yaml": {pkgHubSpokeclusterManifestsSpokeclusterNamespaceYaml, map[string]*bintree{}},
|
||||
"spokecluster-role.yaml": {pkgHubSpokeclusterManifestsSpokeclusterRoleYaml, map[string]*bintree{}},
|
||||
"spokecluster-rolebinding.yaml": {pkgHubSpokeclusterManifestsSpokeclusterRolebindingYaml, map[string]*bintree{}},
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory
|
||||
func RestoreAsset(dir, name string) error {
|
||||
data, err := Asset(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := AssetInfo(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RestoreAssets restores an asset under the given directory recursively
|
||||
func RestoreAssets(dir, name string) error {
|
||||
children, err := AssetDir(name)
|
||||
// File
|
||||
if err != nil {
|
||||
return RestoreAsset(dir, name)
|
||||
}
|
||||
// Dir
|
||||
for _, child := range children {
|
||||
err = RestoreAssets(dir, filepath.Join(name, child))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func _filePath(dir, name string) string {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
|
||||
}
|
||||
@@ -2,27 +2,217 @@ package spokecluster
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
clientset "github.com/open-cluster-management/api/client/cluster/clientset/versioned"
|
||||
v1 "github.com/open-cluster-management/api/cluster/v1"
|
||||
"github.com/open-cluster-management/registration/pkg/helpers"
|
||||
"github.com/open-cluster-management/registration/pkg/hub/spokecluster/bindata"
|
||||
"github.com/openshift/library-go/pkg/assets"
|
||||
"github.com/openshift/library-go/pkg/controller/factory"
|
||||
"github.com/openshift/library-go/pkg/operator/events"
|
||||
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
|
||||
operatorhelpers "github.com/openshift/library-go/pkg/operator/v1helpers"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// Controller manages the SpokeCluster resources
|
||||
type Controller struct {
|
||||
// TODO add client and other configurations
|
||||
const (
|
||||
manifestDir = "pkg/hub/spokecluster"
|
||||
clusterRolePrefix = "system:open-cluster-management:spokecluster"
|
||||
spokeClusterFinalizer = "cluster.open-cluster-management.io/api-resource-cleanup"
|
||||
)
|
||||
|
||||
type spokeClusterController struct {
|
||||
kubeClient kubernetes.Interface
|
||||
clusterClient clientset.Interface
|
||||
eventRecorder events.Recorder
|
||||
}
|
||||
|
||||
// NewController creates a new spoke cluster registration controller
|
||||
func NewController(recorder events.Recorder) factory.Controller {
|
||||
c := &Controller{}
|
||||
// NewSpokeClusterController creates a new spoke cluster controller
|
||||
func NewSpokeClusterController(
|
||||
kubeClient kubernetes.Interface,
|
||||
clusterClient clientset.Interface,
|
||||
clusterInformer factory.Informer,
|
||||
recorder events.Recorder) factory.Controller {
|
||||
c := &spokeClusterController{
|
||||
kubeClient: kubeClient,
|
||||
clusterClient: clusterClient,
|
||||
eventRecorder: recorder.WithComponentSuffix("spoke-cluster-controller"),
|
||||
}
|
||||
return factory.New().
|
||||
WithInformersQueueKeyFunc(func(obj runtime.Object) string {
|
||||
accessor, _ := meta.Accessor(obj)
|
||||
return accessor.GetName()
|
||||
}, clusterInformer).
|
||||
WithSync(c.sync).
|
||||
ResyncEvery(time.Minute).
|
||||
ToController("SpokeClusterController", recorder)
|
||||
}
|
||||
|
||||
func (c Controller) sync(ctx context.Context, syncCtx factory.SyncContext) error {
|
||||
// TODO add main reconcile loop
|
||||
func (c *spokeClusterController) sync(ctx context.Context, syncCtx factory.SyncContext) error {
|
||||
spokeClusterName := syncCtx.QueueKey()
|
||||
klog.V(4).Infof("Reconciling SpokeCluster %s", spokeClusterName)
|
||||
spokeCluster, err := c.clusterClient.ClusterV1().SpokeClusters().Get(ctx, spokeClusterName, metav1.GetOptions{})
|
||||
if errors.IsNotFound(err) {
|
||||
// Spoke cluster not found, could have been deleted, do nothing.
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if spokeCluster.DeletionTimestamp.IsZero() {
|
||||
hasFinalizer := false
|
||||
for i := range spokeCluster.Finalizers {
|
||||
if spokeCluster.Finalizers[i] == spokeClusterFinalizer {
|
||||
hasFinalizer = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasFinalizer {
|
||||
spokeCluster.Finalizers = append(spokeCluster.Finalizers, spokeClusterFinalizer)
|
||||
_, err := c.clusterClient.ClusterV1().SpokeClusters().Update(ctx, spokeCluster, metav1.UpdateOptions{})
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Spoke cluster is deleting, we remove its related resources
|
||||
if !spokeCluster.DeletionTimestamp.IsZero() {
|
||||
if err := c.removeSpokeClusterResources(ctx, spokeClusterName); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.removeSpokeClusterFinalizer(ctx, spokeCluster)
|
||||
}
|
||||
|
||||
if !spokeCluster.Spec.HubAcceptsClient {
|
||||
acceptedCondition := helpers.FindSpokeClusterCondition(spokeCluster.Status.Conditions, v1.SpokeClusterConditionHubAccepted)
|
||||
// Current spoke cluster is not accepted, do nothing.
|
||||
if !helpers.IsConditionTrue(acceptedCondition) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Hub cluster-admin denies the current spoke cluster, we remove its related resources and update its condition.
|
||||
c.eventRecorder.Eventf("SpokeClusterDenied", "spoke cluster %s is denied by hub cluster admin", spokeClusterName)
|
||||
|
||||
if err := c.removeSpokeClusterResources(ctx, spokeClusterName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, _, err := helpers.UpdateSpokeClusterStatus(
|
||||
ctx,
|
||||
c.clusterClient,
|
||||
spokeClusterName,
|
||||
helpers.UpdateSpokeClusterConditionFn(v1.StatusCondition{
|
||||
Type: v1.SpokeClusterConditionHubAccepted,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: "HubClusterAdminDenied",
|
||||
Message: "Denied by hub cluster admin",
|
||||
}),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// Hub cluster-admin accepts the spoke cluster, we apply
|
||||
// 1. clusterrole and clusterrolebinding for this spoke cluster.
|
||||
// 2. namespace for this spoke cluster.
|
||||
// 3. role and rolebinding for this spoke cluster on its namespace.
|
||||
resourceResults := resourceapply.ApplyDirectly(
|
||||
resourceapply.NewKubeClientHolder(c.kubeClient),
|
||||
syncCtx.Recorder(),
|
||||
func(name string) ([]byte, error) {
|
||||
config := struct {
|
||||
SpokeClusterName string
|
||||
}{
|
||||
SpokeClusterName: spokeClusterName,
|
||||
}
|
||||
return assets.MustCreateAssetFromTemplate(name, bindata.MustAsset(filepath.Join(manifestDir, name)), config).Data, nil
|
||||
},
|
||||
"manifests/spokecluster-clusterrole.yaml",
|
||||
"manifests/spokecluster-clusterrolebinding.yaml",
|
||||
"manifests/spokecluster-namespace.yaml",
|
||||
"manifests/spokecluster-role.yaml",
|
||||
"manifests/spokecluster-rolebinding.yaml",
|
||||
)
|
||||
errs := []error{}
|
||||
for _, result := range resourceResults {
|
||||
if result.Error != nil {
|
||||
errs = append(errs, fmt.Errorf("%q (%T): %v", result.File, result.Type, result.Error))
|
||||
}
|
||||
}
|
||||
|
||||
// We add the accepted condition to spoke cluster
|
||||
acceptedCondition := v1.StatusCondition{
|
||||
Type: v1.SpokeClusterConditionHubAccepted,
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: "HubClusterAdminAccepted",
|
||||
Message: "Accepted by hub cluster admin",
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
applyErrors := operatorhelpers.NewMultiLineAggregate(errs)
|
||||
acceptedCondition.Reason = "Error"
|
||||
acceptedCondition.Message = applyErrors.Error()
|
||||
}
|
||||
|
||||
_, updated, updatedErr := helpers.UpdateSpokeClusterStatus(
|
||||
ctx,
|
||||
c.clusterClient,
|
||||
spokeClusterName,
|
||||
helpers.UpdateSpokeClusterConditionFn(acceptedCondition),
|
||||
)
|
||||
if updatedErr != nil {
|
||||
errs = append(errs, updatedErr)
|
||||
}
|
||||
if updated {
|
||||
c.eventRecorder.Eventf("SpokeClusterAccepted", "spoke cluster %s is accepted by hub cluster admin", spokeClusterName)
|
||||
}
|
||||
return operatorhelpers.NewMultiLineAggregate(errs)
|
||||
}
|
||||
|
||||
func (c *spokeClusterController) removeSpokeClusterResources(ctx context.Context, spokeClusterName string) error {
|
||||
err := c.kubeClient.CoreV1().Namespaces().Delete(ctx, spokeClusterName, metav1.DeleteOptions{})
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
c.eventRecorder.Eventf("SpokeClusterNamespaceDeleted", "namespace %s is deleted", spokeClusterName)
|
||||
|
||||
clusterRoleName := fmt.Sprintf("%s:%s", clusterRolePrefix, spokeClusterName)
|
||||
err = c.kubeClient.RbacV1().ClusterRoles().Delete(ctx, clusterRoleName, metav1.DeleteOptions{})
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
c.eventRecorder.Eventf("SpokeClusterClusterRoleDeleted", "clusterrole %s is deleted", clusterRoleName)
|
||||
|
||||
//TODO search all clusterroles and roles for this group and remove the entry or delete the clusterrolebinding if it's the only subject.
|
||||
clusterRoleBindingName := fmt.Sprintf("%s:%s", clusterRolePrefix, spokeClusterName)
|
||||
err = c.kubeClient.RbacV1().ClusterRoleBindings().Delete(ctx, clusterRoleBindingName, metav1.DeleteOptions{})
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
c.eventRecorder.Eventf("SpokeClusterClusterRoleBindingDeleted", "clusterrolebinding %s is deleted", clusterRoleBindingName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *spokeClusterController) removeSpokeClusterFinalizer(ctx context.Context, spokeCluster *v1.SpokeCluster) error {
|
||||
copiedFinalizers := []string{}
|
||||
for i := range spokeCluster.Finalizers {
|
||||
if spokeCluster.Finalizers[i] == spokeClusterFinalizer {
|
||||
continue
|
||||
}
|
||||
copiedFinalizers = append(copiedFinalizers, spokeCluster.Finalizers[i])
|
||||
}
|
||||
|
||||
if len(spokeCluster.Finalizers) != len(copiedFinalizers) {
|
||||
spokeCluster.Finalizers = copiedFinalizers
|
||||
_, err := c.clusterClient.ClusterV1().SpokeClusters().Update(ctx, spokeCluster, metav1.UpdateOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
package spokecluster
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
clusterfake "github.com/open-cluster-management/api/client/cluster/clientset/versioned/fake"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
kubefake "k8s.io/client-go/kubernetes/fake"
|
||||
clienttesting "k8s.io/client-go/testing"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
|
||||
v1 "github.com/open-cluster-management/api/cluster/v1"
|
||||
"github.com/openshift/library-go/pkg/operator/events"
|
||||
"github.com/openshift/library-go/pkg/operator/events/eventstesting"
|
||||
)
|
||||
|
||||
const testSpokeClusterName = "test_spoke_cluster"
|
||||
|
||||
func TestSyncSpokeCluster(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
startingObjects []runtime.Object
|
||||
validateActions func(t *testing.T, actions []clienttesting.Action)
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "sync a deleted spoke cluster",
|
||||
startingObjects: []runtime.Object{},
|
||||
validateActions: func(t *testing.T, actions []clienttesting.Action) {
|
||||
if len(actions) != 1 {
|
||||
t.Errorf("expected 1 call but got: %#v", actions)
|
||||
}
|
||||
assertAction(t, actions[0], "get")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "create a new spoke cluster",
|
||||
startingObjects: []runtime.Object{newSpokeCluster()},
|
||||
validateActions: func(t *testing.T, actions []clienttesting.Action) {
|
||||
if len(actions) != 2 {
|
||||
t.Errorf("expected 1 call but got: %#v", actions)
|
||||
}
|
||||
assertAction(t, actions[1], "update")
|
||||
assertFinalizers(t, actions[1].(clienttesting.UpdateActionImpl).Object, []string{spokeClusterFinalizer})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "accept a spoke cluster",
|
||||
startingObjects: []runtime.Object{newAcceptedSpokeCluster([]string{spokeClusterFinalizer})},
|
||||
validateActions: func(t *testing.T, actions []clienttesting.Action) {
|
||||
if len(actions) != 3 {
|
||||
t.Errorf("expected 3 call but got: %#v", actions)
|
||||
}
|
||||
assertAction(t, actions[2], "update")
|
||||
assertCondition(t, actions[2].(clienttesting.UpdateActionImpl).Object, v1.SpokeClusterConditionHubAccepted, metav1.ConditionTrue)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sync an accepted spoke cluster",
|
||||
startingObjects: []runtime.Object{newAcceptedSpokeClusterWithCondition()},
|
||||
validateActions: func(t *testing.T, actions []clienttesting.Action) {
|
||||
if len(actions) != 2 {
|
||||
t.Errorf("expected 2 call but got: %#v", actions)
|
||||
}
|
||||
assertAction(t, actions[1], "get")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deny an accepted spoke cluster",
|
||||
startingObjects: []runtime.Object{newDeniedSpokeCluster()},
|
||||
validateActions: func(t *testing.T, actions []clienttesting.Action) {
|
||||
if len(actions) != 3 {
|
||||
t.Errorf("expected 3 call but got: %#v", actions)
|
||||
}
|
||||
assertAction(t, actions[2], "update")
|
||||
assertCondition(t, actions[2].(clienttesting.UpdateActionImpl).Object, v1.SpokeClusterConditionHubAccepted, metav1.ConditionFalse)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "delete a spoke cluster",
|
||||
startingObjects: []runtime.Object{newDeletingSpokeCluster()},
|
||||
validateActions: func(t *testing.T, actions []clienttesting.Action) {
|
||||
if len(actions) != 2 {
|
||||
t.Errorf("expected 2 call but got: %#v", actions)
|
||||
}
|
||||
assertAction(t, actions[1], "update")
|
||||
assertFinalizers(t, actions[1].(clienttesting.UpdateActionImpl).Object, []string{})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
clusterClient := clusterfake.NewSimpleClientset(c.startingObjects...)
|
||||
kubeClient := kubefake.NewSimpleClientset()
|
||||
|
||||
ctrl := spokeClusterController{kubeClient, clusterClient, eventstesting.NewTestingEventRecorder(t)}
|
||||
syncErr := ctrl.sync(context.TODO(), newFakeSyncContext(t))
|
||||
if len(c.expectedErr) > 0 && syncErr == nil {
|
||||
t.Errorf("expected %q error", c.expectedErr)
|
||||
return
|
||||
}
|
||||
if len(c.expectedErr) > 0 && syncErr != nil && syncErr.Error() != c.expectedErr {
|
||||
t.Errorf("expected %q error, got %q", c.expectedErr, syncErr.Error())
|
||||
return
|
||||
}
|
||||
if syncErr != nil {
|
||||
t.Errorf("unexpected err: %v", syncErr)
|
||||
}
|
||||
|
||||
c.validateActions(t, clusterClient.Actions())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func assertAction(t *testing.T, actual clienttesting.Action, expected string) {
|
||||
if actual.GetVerb() != expected {
|
||||
t.Errorf("expected %s action but got: %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func assertFinalizers(t *testing.T, actual runtime.Object, expected []string) {
|
||||
spokeCluster := actual.(*v1.SpokeCluster)
|
||||
if !reflect.DeepEqual(spokeCluster.Finalizers, expected) {
|
||||
t.Errorf("expected %#v but got %#v", expected, spokeCluster.Finalizers)
|
||||
}
|
||||
}
|
||||
|
||||
func assertCondition(t *testing.T, actual runtime.Object, expectedCondition string, expectedStatus metav1.ConditionStatus) {
|
||||
spokeCluster := actual.(*v1.SpokeCluster)
|
||||
conditions := spokeCluster.Status.Conditions
|
||||
if len(conditions) != 1 {
|
||||
t.Errorf("expected 1 condition but got: %#v", conditions)
|
||||
}
|
||||
condition := conditions[0]
|
||||
if condition.Type != expectedCondition {
|
||||
t.Errorf("expected %s but got: %s", expectedCondition, condition.Type)
|
||||
}
|
||||
if condition.Status != expectedStatus {
|
||||
t.Errorf("expected %s but got: %s", expectedStatus, condition.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func newSpokeCluster() *v1.SpokeCluster {
|
||||
return &v1.SpokeCluster{ObjectMeta: metav1.ObjectMeta{Name: testSpokeClusterName}}
|
||||
}
|
||||
|
||||
func newAcceptedSpokeCluster(finalizers []string) *v1.SpokeCluster {
|
||||
return &v1.SpokeCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: testSpokeClusterName,
|
||||
Finalizers: finalizers,
|
||||
},
|
||||
Spec: v1.SpokeClusterSpec{HubAcceptsClient: true},
|
||||
}
|
||||
}
|
||||
|
||||
func newAcceptedSpokeClusterWithCondition() *v1.SpokeCluster {
|
||||
spokeCluster := newAcceptedSpokeCluster([]string{spokeClusterFinalizer})
|
||||
spokeCluster.Finalizers = append(spokeCluster.Finalizers, spokeClusterFinalizer)
|
||||
spokeCluster.Status.Conditions = append(spokeCluster.Status.Conditions, v1.StatusCondition{
|
||||
Type: v1.SpokeClusterConditionHubAccepted,
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: "HubClusterAdminAccepted",
|
||||
Message: "Accepted by hub cluster admin",
|
||||
LastTransitionTime: metav1.Time{Time: metav1.Now().Add(-10 * time.Second)},
|
||||
})
|
||||
return spokeCluster
|
||||
}
|
||||
|
||||
func newDeniedSpokeCluster() *v1.SpokeCluster {
|
||||
spokeCluster := newAcceptedSpokeClusterWithCondition()
|
||||
spokeCluster.Spec.HubAcceptsClient = false
|
||||
return spokeCluster
|
||||
}
|
||||
|
||||
func newDeletingSpokeCluster() *v1.SpokeCluster {
|
||||
now := metav1.Now()
|
||||
return &v1.SpokeCluster{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: testSpokeClusterName,
|
||||
DeletionTimestamp: &now,
|
||||
Finalizers: []string{spokeClusterFinalizer},
|
||||
},
|
||||
Spec: v1.SpokeClusterSpec{HubAcceptsClient: true},
|
||||
}
|
||||
}
|
||||
|
||||
type fakeSyncContext struct {
|
||||
spokeName string
|
||||
recorder events.Recorder
|
||||
}
|
||||
|
||||
func newFakeSyncContext(t *testing.T) *fakeSyncContext {
|
||||
return &fakeSyncContext{
|
||||
spokeName: testSpokeClusterName,
|
||||
recorder: eventstesting.NewTestingEventRecorder(t),
|
||||
}
|
||||
}
|
||||
|
||||
func (f fakeSyncContext) Queue() workqueue.RateLimitingInterface { return nil }
|
||||
func (f fakeSyncContext) QueueKey() string { return f.spokeName }
|
||||
func (f fakeSyncContext) Recorder() events.Recorder { return f.recorder }
|
||||
@@ -0,0 +1,19 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: system:open-cluster-management:spokecluster:{{ .SpokeClusterName }}
|
||||
rules:
|
||||
# Allow spoke agent to rotate its certificate
|
||||
- apiGroups: ["certificates.k8s.io"]
|
||||
resources: ["certificatesigningrequests/spokeclusteragent"]
|
||||
verbs: ["create"]
|
||||
# Allow spoke agent to get/list/watch its owner spoke cluster
|
||||
- apiGroups: ["cluster.open-cluster-management.io"]
|
||||
resources: ["spokeclusters"]
|
||||
resourceNames: ["{{ .SpokeClusterName }}"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
# Allow spoke agent to update the status of its owner spoke cluster
|
||||
- apiGroups: ["cluster.open-cluster-management.io"]
|
||||
resources: ["spokeclusters/status"]
|
||||
resourceNames: ["{{ .SpokeClusterName }}"]
|
||||
verbs: ["patch", "update"]
|
||||
@@ -0,0 +1,12 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: system:open-cluster-management:spokecluster:{{ .SpokeClusterName }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: system:open-cluster-management:spokecluster:{{ .SpokeClusterName }}
|
||||
subjects:
|
||||
- kind: Group
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
name: system:open-cluster-management:spokecluster:{{ .SpokeClusterName }}
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: {{ .SpokeClusterName }}
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ .SpokeClusterName }}
|
||||
namespace: {{ .SpokeClusterName }}
|
||||
# TODO add rules later
|
||||
# rules: []
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ .SpokeClusterName }}
|
||||
namespace: {{ .SpokeClusterName }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: {{ .SpokeClusterName }}
|
||||
subjects:
|
||||
# Bind the role with spoke agent user group, the role will be as a common role for all spoke agents
|
||||
# TODO: we will consider bind a specific role for each spoke agent by spoke agent name
|
||||
- kind: Group
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
name: system:open-cluster-management:{{ .SpokeClusterName }}
|
||||
Generated
+20
@@ -0,0 +1,20 @@
|
||||
# OSX leaves these everywhere on SMB shares
|
||||
._*
|
||||
|
||||
# Eclipse files
|
||||
.classpath
|
||||
.project
|
||||
.settings/**
|
||||
|
||||
# Emacs save files
|
||||
*~
|
||||
|
||||
# Vim-related files
|
||||
[._]*.s[a-w][a-z]
|
||||
[._]s[a-w][a-z]
|
||||
*.un~
|
||||
Session.vim
|
||||
.netrwhist
|
||||
|
||||
# Go test binaries
|
||||
*.test
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.3
|
||||
- 1.4
|
||||
script:
|
||||
- go test
|
||||
- go build
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Sam Ghods
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
# YAML marshaling and unmarshaling support for Go
|
||||
|
||||
[](https://travis-ci.org/ghodss/yaml)
|
||||
|
||||
## Introduction
|
||||
|
||||
A wrapper around [go-yaml](https://github.com/go-yaml/yaml) designed to enable a better way of handling YAML when marshaling to and from structs.
|
||||
|
||||
In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/).
|
||||
|
||||
## Compatibility
|
||||
|
||||
This package uses [go-yaml](https://github.com/go-yaml/yaml) and therefore supports [everything go-yaml supports](https://github.com/go-yaml/yaml#compatibility).
|
||||
|
||||
## Caveats
|
||||
|
||||
**Caveat #1:** When using `yaml.Marshal` and `yaml.Unmarshal`, binary data should NOT be preceded with the `!!binary` YAML tag. If you do, go-yaml will convert the binary data from base64 to native binary data, which is not compatible with JSON. You can still use binary in your YAML files though - just store them without the `!!binary` tag and decode the base64 in your code (e.g. in the custom JSON methods `MarshalJSON` and `UnmarshalJSON`). This also has the benefit that your YAML and your JSON binary data will be decoded exactly the same way. As an example:
|
||||
|
||||
```
|
||||
BAD:
|
||||
exampleKey: !!binary gIGC
|
||||
|
||||
GOOD:
|
||||
exampleKey: gIGC
|
||||
... and decode the base64 data in your code.
|
||||
```
|
||||
|
||||
**Caveat #2:** When using `YAMLToJSON` directly, maps with keys that are maps will result in an error since this is not supported by JSON. This error will occur in `Unmarshal` as well since you can't unmarshal map keys anyways since struct fields can't be keys.
|
||||
|
||||
## Installation and usage
|
||||
|
||||
To install, run:
|
||||
|
||||
```
|
||||
$ go get github.com/ghodss/yaml
|
||||
```
|
||||
|
||||
And import using:
|
||||
|
||||
```
|
||||
import "github.com/ghodss/yaml"
|
||||
```
|
||||
|
||||
Usage is very similar to the JSON library:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
)
|
||||
|
||||
type Person struct {
|
||||
Name string `json:"name"` // Affects YAML field names too.
|
||||
Age int `json:"age"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Marshal a Person struct to YAML.
|
||||
p := Person{"John", 30}
|
||||
y, err := yaml.Marshal(p)
|
||||
if err != nil {
|
||||
fmt.Printf("err: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(y))
|
||||
/* Output:
|
||||
age: 30
|
||||
name: John
|
||||
*/
|
||||
|
||||
// Unmarshal the YAML back into a Person struct.
|
||||
var p2 Person
|
||||
err = yaml.Unmarshal(y, &p2)
|
||||
if err != nil {
|
||||
fmt.Printf("err: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(p2)
|
||||
/* Output:
|
||||
{John 30}
|
||||
*/
|
||||
}
|
||||
```
|
||||
|
||||
`yaml.YAMLToJSON` and `yaml.JSONToYAML` methods are also available:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
)
|
||||
|
||||
func main() {
|
||||
j := []byte(`{"name": "John", "age": 30}`)
|
||||
y, err := yaml.JSONToYAML(j)
|
||||
if err != nil {
|
||||
fmt.Printf("err: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(y))
|
||||
/* Output:
|
||||
name: John
|
||||
age: 30
|
||||
*/
|
||||
j2, err := yaml.YAMLToJSON(y)
|
||||
if err != nil {
|
||||
fmt.Printf("err: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(j2))
|
||||
/* Output:
|
||||
{"age":30,"name":"John"}
|
||||
*/
|
||||
}
|
||||
```
|
||||
+501
@@ -0,0 +1,501 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// indirect walks down v allocating pointers as needed,
|
||||
// until it gets to a non-pointer.
|
||||
// if it encounters an Unmarshaler, indirect stops and returns that.
|
||||
// if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
|
||||
func indirect(v reflect.Value, decodingNull bool) (json.Unmarshaler, encoding.TextUnmarshaler, reflect.Value) {
|
||||
// If v is a named type and is addressable,
|
||||
// start with its address, so that if the type has pointer methods,
|
||||
// we find them.
|
||||
if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
|
||||
v = v.Addr()
|
||||
}
|
||||
for {
|
||||
// Load value from interface, but only if the result will be
|
||||
// usefully addressable.
|
||||
if v.Kind() == reflect.Interface && !v.IsNil() {
|
||||
e := v.Elem()
|
||||
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
|
||||
v = e
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if v.Kind() != reflect.Ptr {
|
||||
break
|
||||
}
|
||||
|
||||
if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() {
|
||||
break
|
||||
}
|
||||
if v.IsNil() {
|
||||
if v.CanSet() {
|
||||
v.Set(reflect.New(v.Type().Elem()))
|
||||
} else {
|
||||
v = reflect.New(v.Type().Elem())
|
||||
}
|
||||
}
|
||||
if v.Type().NumMethod() > 0 {
|
||||
if u, ok := v.Interface().(json.Unmarshaler); ok {
|
||||
return u, nil, reflect.Value{}
|
||||
}
|
||||
if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
|
||||
return nil, u, reflect.Value{}
|
||||
}
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
return nil, nil, v
|
||||
}
|
||||
|
||||
// A field represents a single field found in a struct.
|
||||
type field struct {
|
||||
name string
|
||||
nameBytes []byte // []byte(name)
|
||||
equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent
|
||||
|
||||
tag bool
|
||||
index []int
|
||||
typ reflect.Type
|
||||
omitEmpty bool
|
||||
quoted bool
|
||||
}
|
||||
|
||||
func fillField(f field) field {
|
||||
f.nameBytes = []byte(f.name)
|
||||
f.equalFold = foldFunc(f.nameBytes)
|
||||
return f
|
||||
}
|
||||
|
||||
// byName sorts field by name, breaking ties with depth,
|
||||
// then breaking ties with "name came from json tag", then
|
||||
// breaking ties with index sequence.
|
||||
type byName []field
|
||||
|
||||
func (x byName) Len() int { return len(x) }
|
||||
|
||||
func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x byName) Less(i, j int) bool {
|
||||
if x[i].name != x[j].name {
|
||||
return x[i].name < x[j].name
|
||||
}
|
||||
if len(x[i].index) != len(x[j].index) {
|
||||
return len(x[i].index) < len(x[j].index)
|
||||
}
|
||||
if x[i].tag != x[j].tag {
|
||||
return x[i].tag
|
||||
}
|
||||
return byIndex(x).Less(i, j)
|
||||
}
|
||||
|
||||
// byIndex sorts field by index sequence.
|
||||
type byIndex []field
|
||||
|
||||
func (x byIndex) Len() int { return len(x) }
|
||||
|
||||
func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x byIndex) Less(i, j int) bool {
|
||||
for k, xik := range x[i].index {
|
||||
if k >= len(x[j].index) {
|
||||
return false
|
||||
}
|
||||
if xik != x[j].index[k] {
|
||||
return xik < x[j].index[k]
|
||||
}
|
||||
}
|
||||
return len(x[i].index) < len(x[j].index)
|
||||
}
|
||||
|
||||
// typeFields returns a list of fields that JSON should recognize for the given type.
|
||||
// The algorithm is breadth-first search over the set of structs to include - the top struct
|
||||
// and then any reachable anonymous structs.
|
||||
func typeFields(t reflect.Type) []field {
|
||||
// Anonymous fields to explore at the current level and the next.
|
||||
current := []field{}
|
||||
next := []field{{typ: t}}
|
||||
|
||||
// Count of queued names for current level and the next.
|
||||
count := map[reflect.Type]int{}
|
||||
nextCount := map[reflect.Type]int{}
|
||||
|
||||
// Types already visited at an earlier level.
|
||||
visited := map[reflect.Type]bool{}
|
||||
|
||||
// Fields found.
|
||||
var fields []field
|
||||
|
||||
for len(next) > 0 {
|
||||
current, next = next, current[:0]
|
||||
count, nextCount = nextCount, map[reflect.Type]int{}
|
||||
|
||||
for _, f := range current {
|
||||
if visited[f.typ] {
|
||||
continue
|
||||
}
|
||||
visited[f.typ] = true
|
||||
|
||||
// Scan f.typ for fields to include.
|
||||
for i := 0; i < f.typ.NumField(); i++ {
|
||||
sf := f.typ.Field(i)
|
||||
if sf.PkgPath != "" { // unexported
|
||||
continue
|
||||
}
|
||||
tag := sf.Tag.Get("json")
|
||||
if tag == "-" {
|
||||
continue
|
||||
}
|
||||
name, opts := parseTag(tag)
|
||||
if !isValidTag(name) {
|
||||
name = ""
|
||||
}
|
||||
index := make([]int, len(f.index)+1)
|
||||
copy(index, f.index)
|
||||
index[len(f.index)] = i
|
||||
|
||||
ft := sf.Type
|
||||
if ft.Name() == "" && ft.Kind() == reflect.Ptr {
|
||||
// Follow pointer.
|
||||
ft = ft.Elem()
|
||||
}
|
||||
|
||||
// Record found field and index sequence.
|
||||
if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
|
||||
tagged := name != ""
|
||||
if name == "" {
|
||||
name = sf.Name
|
||||
}
|
||||
fields = append(fields, fillField(field{
|
||||
name: name,
|
||||
tag: tagged,
|
||||
index: index,
|
||||
typ: ft,
|
||||
omitEmpty: opts.Contains("omitempty"),
|
||||
quoted: opts.Contains("string"),
|
||||
}))
|
||||
if count[f.typ] > 1 {
|
||||
// If there were multiple instances, add a second,
|
||||
// so that the annihilation code will see a duplicate.
|
||||
// It only cares about the distinction between 1 or 2,
|
||||
// so don't bother generating any more copies.
|
||||
fields = append(fields, fields[len(fields)-1])
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Record new anonymous struct to explore in next round.
|
||||
nextCount[ft]++
|
||||
if nextCount[ft] == 1 {
|
||||
next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(byName(fields))
|
||||
|
||||
// Delete all fields that are hidden by the Go rules for embedded fields,
|
||||
// except that fields with JSON tags are promoted.
|
||||
|
||||
// The fields are sorted in primary order of name, secondary order
|
||||
// of field index length. Loop over names; for each name, delete
|
||||
// hidden fields by choosing the one dominant field that survives.
|
||||
out := fields[:0]
|
||||
for advance, i := 0, 0; i < len(fields); i += advance {
|
||||
// One iteration per name.
|
||||
// Find the sequence of fields with the name of this first field.
|
||||
fi := fields[i]
|
||||
name := fi.name
|
||||
for advance = 1; i+advance < len(fields); advance++ {
|
||||
fj := fields[i+advance]
|
||||
if fj.name != name {
|
||||
break
|
||||
}
|
||||
}
|
||||
if advance == 1 { // Only one field with this name
|
||||
out = append(out, fi)
|
||||
continue
|
||||
}
|
||||
dominant, ok := dominantField(fields[i : i+advance])
|
||||
if ok {
|
||||
out = append(out, dominant)
|
||||
}
|
||||
}
|
||||
|
||||
fields = out
|
||||
sort.Sort(byIndex(fields))
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// dominantField looks through the fields, all of which are known to
|
||||
// have the same name, to find the single field that dominates the
|
||||
// others using Go's embedding rules, modified by the presence of
|
||||
// JSON tags. If there are multiple top-level fields, the boolean
|
||||
// will be false: This condition is an error in Go and we skip all
|
||||
// the fields.
|
||||
func dominantField(fields []field) (field, bool) {
|
||||
// The fields are sorted in increasing index-length order. The winner
|
||||
// must therefore be one with the shortest index length. Drop all
|
||||
// longer entries, which is easy: just truncate the slice.
|
||||
length := len(fields[0].index)
|
||||
tagged := -1 // Index of first tagged field.
|
||||
for i, f := range fields {
|
||||
if len(f.index) > length {
|
||||
fields = fields[:i]
|
||||
break
|
||||
}
|
||||
if f.tag {
|
||||
if tagged >= 0 {
|
||||
// Multiple tagged fields at the same level: conflict.
|
||||
// Return no field.
|
||||
return field{}, false
|
||||
}
|
||||
tagged = i
|
||||
}
|
||||
}
|
||||
if tagged >= 0 {
|
||||
return fields[tagged], true
|
||||
}
|
||||
// All remaining fields have the same length. If there's more than one,
|
||||
// we have a conflict (two fields named "X" at the same level) and we
|
||||
// return no field.
|
||||
if len(fields) > 1 {
|
||||
return field{}, false
|
||||
}
|
||||
return fields[0], true
|
||||
}
|
||||
|
||||
var fieldCache struct {
|
||||
sync.RWMutex
|
||||
m map[reflect.Type][]field
|
||||
}
|
||||
|
||||
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
|
||||
func cachedTypeFields(t reflect.Type) []field {
|
||||
fieldCache.RLock()
|
||||
f := fieldCache.m[t]
|
||||
fieldCache.RUnlock()
|
||||
if f != nil {
|
||||
return f
|
||||
}
|
||||
|
||||
// Compute fields without lock.
|
||||
// Might duplicate effort but won't hold other computations back.
|
||||
f = typeFields(t)
|
||||
if f == nil {
|
||||
f = []field{}
|
||||
}
|
||||
|
||||
fieldCache.Lock()
|
||||
if fieldCache.m == nil {
|
||||
fieldCache.m = map[reflect.Type][]field{}
|
||||
}
|
||||
fieldCache.m[t] = f
|
||||
fieldCache.Unlock()
|
||||
return f
|
||||
}
|
||||
|
||||
func isValidTag(s string) bool {
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
for _, c := range s {
|
||||
switch {
|
||||
case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
|
||||
// Backslash and quote chars are reserved, but
|
||||
// otherwise any punctuation chars are allowed
|
||||
// in a tag name.
|
||||
default:
|
||||
if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const (
|
||||
caseMask = ^byte(0x20) // Mask to ignore case in ASCII.
|
||||
kelvin = '\u212a'
|
||||
smallLongEss = '\u017f'
|
||||
)
|
||||
|
||||
// foldFunc returns one of four different case folding equivalence
|
||||
// functions, from most general (and slow) to fastest:
|
||||
//
|
||||
// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8
|
||||
// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S')
|
||||
// 3) asciiEqualFold, no special, but includes non-letters (including _)
|
||||
// 4) simpleLetterEqualFold, no specials, no non-letters.
|
||||
//
|
||||
// The letters S and K are special because they map to 3 runes, not just 2:
|
||||
// * S maps to s and to U+017F 'ſ' Latin small letter long s
|
||||
// * k maps to K and to U+212A 'K' Kelvin sign
|
||||
// See http://play.golang.org/p/tTxjOc0OGo
|
||||
//
|
||||
// The returned function is specialized for matching against s and
|
||||
// should only be given s. It's not curried for performance reasons.
|
||||
func foldFunc(s []byte) func(s, t []byte) bool {
|
||||
nonLetter := false
|
||||
special := false // special letter
|
||||
for _, b := range s {
|
||||
if b >= utf8.RuneSelf {
|
||||
return bytes.EqualFold
|
||||
}
|
||||
upper := b & caseMask
|
||||
if upper < 'A' || upper > 'Z' {
|
||||
nonLetter = true
|
||||
} else if upper == 'K' || upper == 'S' {
|
||||
// See above for why these letters are special.
|
||||
special = true
|
||||
}
|
||||
}
|
||||
if special {
|
||||
return equalFoldRight
|
||||
}
|
||||
if nonLetter {
|
||||
return asciiEqualFold
|
||||
}
|
||||
return simpleLetterEqualFold
|
||||
}
|
||||
|
||||
// equalFoldRight is a specialization of bytes.EqualFold when s is
|
||||
// known to be all ASCII (including punctuation), but contains an 's',
|
||||
// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t.
|
||||
// See comments on foldFunc.
|
||||
func equalFoldRight(s, t []byte) bool {
|
||||
for _, sb := range s {
|
||||
if len(t) == 0 {
|
||||
return false
|
||||
}
|
||||
tb := t[0]
|
||||
if tb < utf8.RuneSelf {
|
||||
if sb != tb {
|
||||
sbUpper := sb & caseMask
|
||||
if 'A' <= sbUpper && sbUpper <= 'Z' {
|
||||
if sbUpper != tb&caseMask {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
t = t[1:]
|
||||
continue
|
||||
}
|
||||
// sb is ASCII and t is not. t must be either kelvin
|
||||
// sign or long s; sb must be s, S, k, or K.
|
||||
tr, size := utf8.DecodeRune(t)
|
||||
switch sb {
|
||||
case 's', 'S':
|
||||
if tr != smallLongEss {
|
||||
return false
|
||||
}
|
||||
case 'k', 'K':
|
||||
if tr != kelvin {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
t = t[size:]
|
||||
|
||||
}
|
||||
if len(t) > 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// asciiEqualFold is a specialization of bytes.EqualFold for use when
|
||||
// s is all ASCII (but may contain non-letters) and contains no
|
||||
// special-folding letters.
|
||||
// See comments on foldFunc.
|
||||
func asciiEqualFold(s, t []byte) bool {
|
||||
if len(s) != len(t) {
|
||||
return false
|
||||
}
|
||||
for i, sb := range s {
|
||||
tb := t[i]
|
||||
if sb == tb {
|
||||
continue
|
||||
}
|
||||
if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') {
|
||||
if sb&caseMask != tb&caseMask {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// simpleLetterEqualFold is a specialization of bytes.EqualFold for
|
||||
// use when s is all ASCII letters (no underscores, etc) and also
|
||||
// doesn't contain 'k', 'K', 's', or 'S'.
|
||||
// See comments on foldFunc.
|
||||
func simpleLetterEqualFold(s, t []byte) bool {
|
||||
if len(s) != len(t) {
|
||||
return false
|
||||
}
|
||||
for i, b := range s {
|
||||
if b&caseMask != t[i]&caseMask {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// tagOptions is the string following a comma in a struct field's "json"
|
||||
// tag, or the empty string. It does not include the leading comma.
|
||||
type tagOptions string
|
||||
|
||||
// parseTag splits a struct field's json tag into its name and
|
||||
// comma-separated options.
|
||||
func parseTag(tag string) (string, tagOptions) {
|
||||
if idx := strings.Index(tag, ","); idx != -1 {
|
||||
return tag[:idx], tagOptions(tag[idx+1:])
|
||||
}
|
||||
return tag, tagOptions("")
|
||||
}
|
||||
|
||||
// Contains reports whether a comma-separated list of options
|
||||
// contains a particular substr flag. substr must be surrounded by a
|
||||
// string boundary or commas.
|
||||
func (o tagOptions) Contains(optionName string) bool {
|
||||
if len(o) == 0 {
|
||||
return false
|
||||
}
|
||||
s := string(o)
|
||||
for s != "" {
|
||||
var next string
|
||||
i := strings.Index(s, ",")
|
||||
if i >= 0 {
|
||||
s, next = s[:i], s[i+1:]
|
||||
}
|
||||
if s == optionName {
|
||||
return true
|
||||
}
|
||||
s = next
|
||||
}
|
||||
return false
|
||||
}
|
||||
+277
@@ -0,0 +1,277 @@
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// Marshals the object into JSON then converts JSON to YAML and returns the
|
||||
// YAML.
|
||||
func Marshal(o interface{}) ([]byte, error) {
|
||||
j, err := json.Marshal(o)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error marshaling into JSON: %v", err)
|
||||
}
|
||||
|
||||
y, err := JSONToYAML(j)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting JSON to YAML: %v", err)
|
||||
}
|
||||
|
||||
return y, nil
|
||||
}
|
||||
|
||||
// Converts YAML to JSON then uses JSON to unmarshal into an object.
|
||||
func Unmarshal(y []byte, o interface{}) error {
|
||||
vo := reflect.ValueOf(o)
|
||||
j, err := yamlToJSON(y, &vo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error converting YAML to JSON: %v", err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(j, o)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error unmarshaling JSON: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert JSON to YAML.
|
||||
func JSONToYAML(j []byte) ([]byte, error) {
|
||||
// Convert the JSON to an object.
|
||||
var jsonObj interface{}
|
||||
// We are using yaml.Unmarshal here (instead of json.Unmarshal) because the
|
||||
// Go JSON library doesn't try to pick the right number type (int, float,
|
||||
// etc.) when unmarshalling to interface{}, it just picks float64
|
||||
// universally. go-yaml does go through the effort of picking the right
|
||||
// number type, so we can preserve number type throughout this process.
|
||||
err := yaml.Unmarshal(j, &jsonObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Marshal this object into YAML.
|
||||
return yaml.Marshal(jsonObj)
|
||||
}
|
||||
|
||||
// Convert YAML to JSON. Since JSON is a subset of YAML, passing JSON through
|
||||
// this method should be a no-op.
|
||||
//
|
||||
// Things YAML can do that are not supported by JSON:
|
||||
// * In YAML you can have binary and null keys in your maps. These are invalid
|
||||
// in JSON. (int and float keys are converted to strings.)
|
||||
// * Binary data in YAML with the !!binary tag is not supported. If you want to
|
||||
// use binary data with this library, encode the data as base64 as usual but do
|
||||
// not use the !!binary tag in your YAML. This will ensure the original base64
|
||||
// encoded data makes it all the way through to the JSON.
|
||||
func YAMLToJSON(y []byte) ([]byte, error) {
|
||||
return yamlToJSON(y, nil)
|
||||
}
|
||||
|
||||
func yamlToJSON(y []byte, jsonTarget *reflect.Value) ([]byte, error) {
|
||||
// Convert the YAML to an object.
|
||||
var yamlObj interface{}
|
||||
err := yaml.Unmarshal(y, &yamlObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// YAML objects are not completely compatible with JSON objects (e.g. you
|
||||
// can have non-string keys in YAML). So, convert the YAML-compatible object
|
||||
// to a JSON-compatible object, failing with an error if irrecoverable
|
||||
// incompatibilties happen along the way.
|
||||
jsonObj, err := convertToJSONableObject(yamlObj, jsonTarget)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Convert this object to JSON and return the data.
|
||||
return json.Marshal(jsonObj)
|
||||
}
|
||||
|
||||
func convertToJSONableObject(yamlObj interface{}, jsonTarget *reflect.Value) (interface{}, error) {
|
||||
var err error
|
||||
|
||||
// Resolve jsonTarget to a concrete value (i.e. not a pointer or an
|
||||
// interface). We pass decodingNull as false because we're not actually
|
||||
// decoding into the value, we're just checking if the ultimate target is a
|
||||
// string.
|
||||
if jsonTarget != nil {
|
||||
ju, tu, pv := indirect(*jsonTarget, false)
|
||||
// We have a JSON or Text Umarshaler at this level, so we can't be trying
|
||||
// to decode into a string.
|
||||
if ju != nil || tu != nil {
|
||||
jsonTarget = nil
|
||||
} else {
|
||||
jsonTarget = &pv
|
||||
}
|
||||
}
|
||||
|
||||
// If yamlObj is a number or a boolean, check if jsonTarget is a string -
|
||||
// if so, coerce. Else return normal.
|
||||
// If yamlObj is a map or array, find the field that each key is
|
||||
// unmarshaling to, and when you recurse pass the reflect.Value for that
|
||||
// field back into this function.
|
||||
switch typedYAMLObj := yamlObj.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
// JSON does not support arbitrary keys in a map, so we must convert
|
||||
// these keys to strings.
|
||||
//
|
||||
// From my reading of go-yaml v2 (specifically the resolve function),
|
||||
// keys can only have the types string, int, int64, float64, binary
|
||||
// (unsupported), or null (unsupported).
|
||||
strMap := make(map[string]interface{})
|
||||
for k, v := range typedYAMLObj {
|
||||
// Resolve the key to a string first.
|
||||
var keyString string
|
||||
switch typedKey := k.(type) {
|
||||
case string:
|
||||
keyString = typedKey
|
||||
case int:
|
||||
keyString = strconv.Itoa(typedKey)
|
||||
case int64:
|
||||
// go-yaml will only return an int64 as a key if the system
|
||||
// architecture is 32-bit and the key's value is between 32-bit
|
||||
// and 64-bit. Otherwise the key type will simply be int.
|
||||
keyString = strconv.FormatInt(typedKey, 10)
|
||||
case float64:
|
||||
// Stolen from go-yaml to use the same conversion to string as
|
||||
// the go-yaml library uses to convert float to string when
|
||||
// Marshaling.
|
||||
s := strconv.FormatFloat(typedKey, 'g', -1, 32)
|
||||
switch s {
|
||||
case "+Inf":
|
||||
s = ".inf"
|
||||
case "-Inf":
|
||||
s = "-.inf"
|
||||
case "NaN":
|
||||
s = ".nan"
|
||||
}
|
||||
keyString = s
|
||||
case bool:
|
||||
if typedKey {
|
||||
keyString = "true"
|
||||
} else {
|
||||
keyString = "false"
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("Unsupported map key of type: %s, key: %+#v, value: %+#v",
|
||||
reflect.TypeOf(k), k, v)
|
||||
}
|
||||
|
||||
// jsonTarget should be a struct or a map. If it's a struct, find
|
||||
// the field it's going to map to and pass its reflect.Value. If
|
||||
// it's a map, find the element type of the map and pass the
|
||||
// reflect.Value created from that type. If it's neither, just pass
|
||||
// nil - JSON conversion will error for us if it's a real issue.
|
||||
if jsonTarget != nil {
|
||||
t := *jsonTarget
|
||||
if t.Kind() == reflect.Struct {
|
||||
keyBytes := []byte(keyString)
|
||||
// Find the field that the JSON library would use.
|
||||
var f *field
|
||||
fields := cachedTypeFields(t.Type())
|
||||
for i := range fields {
|
||||
ff := &fields[i]
|
||||
if bytes.Equal(ff.nameBytes, keyBytes) {
|
||||
f = ff
|
||||
break
|
||||
}
|
||||
// Do case-insensitive comparison.
|
||||
if f == nil && ff.equalFold(ff.nameBytes, keyBytes) {
|
||||
f = ff
|
||||
}
|
||||
}
|
||||
if f != nil {
|
||||
// Find the reflect.Value of the most preferential
|
||||
// struct field.
|
||||
jtf := t.Field(f.index[0])
|
||||
strMap[keyString], err = convertToJSONableObject(v, &jtf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
} else if t.Kind() == reflect.Map {
|
||||
// Create a zero value of the map's element type to use as
|
||||
// the JSON target.
|
||||
jtv := reflect.Zero(t.Type().Elem())
|
||||
strMap[keyString], err = convertToJSONableObject(v, &jtv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
strMap[keyString], err = convertToJSONableObject(v, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return strMap, nil
|
||||
case []interface{}:
|
||||
// We need to recurse into arrays in case there are any
|
||||
// map[interface{}]interface{}'s inside and to convert any
|
||||
// numbers to strings.
|
||||
|
||||
// If jsonTarget is a slice (which it really should be), find the
|
||||
// thing it's going to map to. If it's not a slice, just pass nil
|
||||
// - JSON conversion will error for us if it's a real issue.
|
||||
var jsonSliceElemValue *reflect.Value
|
||||
if jsonTarget != nil {
|
||||
t := *jsonTarget
|
||||
if t.Kind() == reflect.Slice {
|
||||
// By default slices point to nil, but we need a reflect.Value
|
||||
// pointing to a value of the slice type, so we create one here.
|
||||
ev := reflect.Indirect(reflect.New(t.Type().Elem()))
|
||||
jsonSliceElemValue = &ev
|
||||
}
|
||||
}
|
||||
|
||||
// Make and use a new array.
|
||||
arr := make([]interface{}, len(typedYAMLObj))
|
||||
for i, v := range typedYAMLObj {
|
||||
arr[i], err = convertToJSONableObject(v, jsonSliceElemValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return arr, nil
|
||||
default:
|
||||
// If the target type is a string and the YAML type is a number,
|
||||
// convert the YAML type to a string.
|
||||
if jsonTarget != nil && (*jsonTarget).Kind() == reflect.String {
|
||||
// Based on my reading of go-yaml, it may return int, int64,
|
||||
// float64, or uint64.
|
||||
var s string
|
||||
switch typedVal := typedYAMLObj.(type) {
|
||||
case int:
|
||||
s = strconv.FormatInt(int64(typedVal), 10)
|
||||
case int64:
|
||||
s = strconv.FormatInt(typedVal, 10)
|
||||
case float64:
|
||||
s = strconv.FormatFloat(typedVal, 'g', -1, 32)
|
||||
case uint64:
|
||||
s = strconv.FormatUint(typedVal, 10)
|
||||
case bool:
|
||||
if typedVal {
|
||||
s = "true"
|
||||
} else {
|
||||
s = "false"
|
||||
}
|
||||
}
|
||||
if len(s) > 0 {
|
||||
yamlObj = interface{}(s)
|
||||
}
|
||||
}
|
||||
return yamlObj, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
## Contribution guidelines.
|
||||
|
||||
So you wish to contribute to this project? Fantastic!
|
||||
Here are a few guidelines to help you do this in a
|
||||
streamlined fashion.
|
||||
|
||||
|
||||
## Bug reports
|
||||
|
||||
When supplying a bug report, please consider the following guidelines.
|
||||
These serve to make it easier for us to address the issue and find a solution.
|
||||
Most of these are pretty self-evident, but sometimes it is still necessary
|
||||
to reiterate them.
|
||||
|
||||
* Be clear in the way you express the problem. Use simple language and
|
||||
just enough of it to clearly define the issue. Not everyone is a native
|
||||
English speaker. And while most can handle themselves pretty well,
|
||||
it helps to stay away from more esoteric vocabulary.
|
||||
|
||||
Be patient with non-native English speakers. If their bug reports
|
||||
or comments are hard to understand, just ask for clarification.
|
||||
Do not start guessing at their meaning, as this may just lead to
|
||||
more confusion and misunderstandings.
|
||||
* Clearly define any information which is relevant to the problem.
|
||||
This includes library versions, operating system and any other
|
||||
external dependencies which may be needed.
|
||||
* Where applicable, provide a step-by-step listing of the way to
|
||||
reproduce the problem. Make sure this is the simplest possible
|
||||
way to do so. Omit any and all unneccesary steps, because they may
|
||||
just complicate our understanding of the real problem.
|
||||
If need be, create a whole new code project on your local machine,
|
||||
which specifically tries to create the problem you are running into;
|
||||
nothing more, nothing less.
|
||||
|
||||
Include this program in the bug report. It often suffices to paste
|
||||
the code in a [Gist](https://gist.github.com) or on the
|
||||
[Go playground](http://play.golang.org).
|
||||
* If possible, provide us with a listing of the steps you have already
|
||||
undertaken to solve the problem. This can save us a great deal of
|
||||
wasted time, trying out solutions you have already covered.
|
||||
|
||||
|
||||
## Pull requests
|
||||
|
||||
Bug reports are great. Supplying fixes to bugs is even better.
|
||||
When submitting a pull request, the following guidelines are
|
||||
good to keep in mind:
|
||||
|
||||
* `go fmt`: **Always** run your code through `go fmt`, before
|
||||
committing it. Code has to be readable by many different
|
||||
people. And the only way this will be as painless as possible,
|
||||
is if we all stick to the same code style.
|
||||
|
||||
Some of our projects may have automated build-servers hooked up
|
||||
to commit hooks. These will vet any submitted code and determine
|
||||
if it meets a set of properties. One of which is code formatting.
|
||||
These servers will outright deny a submission which has not been
|
||||
run through `go fmt`, even if the code itself is correct.
|
||||
|
||||
We try to maintain a zero-tolerance policy on this matter,
|
||||
because consistently formatted code makes life a great deal
|
||||
easier for everyone involved.
|
||||
* Commit log messages: When committing changes, do so often and
|
||||
clearly -- Even if you have changed only 1 character in a code
|
||||
comment. This means that commit log messages should clearly state
|
||||
exactly what the change does and why. If it fixes a known issue,
|
||||
then mention the issue number in the commit log. E.g.:
|
||||
|
||||
> Fixes return value for `foo/boo.Baz()` to be consistent with
|
||||
> the rest of the API. This addresses issue #32
|
||||
|
||||
Do not pile a lot of unrelated changes into a single commit.
|
||||
Pick and choose only those changes for a single commit, which are
|
||||
directly related. We would much rather see a hundred commits
|
||||
saying nothing but `"Runs go fmt"` in between any real fixes
|
||||
than have these style changes embedded in those real fixes.
|
||||
It creates a lot of noise when trying to review code.
|
||||
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
license. Its contents can be found at:
|
||||
http://creativecommons.org/publicdomain/zero/1.0
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
make -C testdata
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
## bindata
|
||||
|
||||
This package converts any file into managable Go source code. Useful for
|
||||
embedding binary data into a go program. The file data is optionally gzip
|
||||
compressed before being converted to a raw byte slice.
|
||||
|
||||
It comes with a command line tool in the `go-bindata` sub directory.
|
||||
This tool offers a set of command line options, used to customize the
|
||||
output being generated.
|
||||
|
||||
|
||||
### Installation
|
||||
|
||||
To install the library and command line program, use the following:
|
||||
|
||||
go get -u github.com/jteeuwen/go-bindata/...
|
||||
|
||||
|
||||
### Usage
|
||||
|
||||
Conversion is done on one or more sets of files. They are all embedded in a new
|
||||
Go source file, along with a table of contents and an `Asset` function,
|
||||
which allows quick access to the asset, based on its name.
|
||||
|
||||
The simplest invocation generates a `bindata.go` file in the current
|
||||
working directory. It includes all assets from the `data` directory.
|
||||
|
||||
$ go-bindata data/
|
||||
|
||||
To include all input sub-directories recursively, use the elipsis postfix
|
||||
as defined for Go import paths. Otherwise it will only consider assets in the
|
||||
input directory itself.
|
||||
|
||||
$ go-bindata data/...
|
||||
|
||||
To specify the name of the output file being generated, we use the following:
|
||||
|
||||
$ go-bindata -o myfile.go data/
|
||||
|
||||
Multiple input directories can be specified if necessary.
|
||||
|
||||
$ go-bindata dir1/... /path/to/dir2/... dir3
|
||||
|
||||
|
||||
The following paragraphs detail some of the command line options which can be
|
||||
supplied to `go-bindata`. Refer to the `testdata/out` directory for various
|
||||
output examples from the assets in `testdata/in`. Each example uses different
|
||||
command line options.
|
||||
|
||||
To ignore files, pass in regexes using -ignore, for example:
|
||||
|
||||
$ go-bindata -ignore=\\.gitignore data/...
|
||||
|
||||
### Accessing an asset
|
||||
|
||||
To access asset data, we use the `Asset(string) ([]byte, error)` function which
|
||||
is included in the generated output.
|
||||
|
||||
data, err := Asset("pub/style/foo.css")
|
||||
if err != nil {
|
||||
// Asset was not found.
|
||||
}
|
||||
|
||||
// use asset data
|
||||
|
||||
|
||||
### Debug vs Release builds
|
||||
|
||||
When invoking the program with the `-debug` flag, the generated code does
|
||||
not actually include the asset data. Instead, it generates function stubs
|
||||
which load the data from the original file on disk. The asset API remains
|
||||
identical between debug and release builds, so your code will not have to
|
||||
change.
|
||||
|
||||
This is useful during development when you expect the assets to change often.
|
||||
The host application using these assets uses the same API in both cases and
|
||||
will not have to care where the actual data comes from.
|
||||
|
||||
An example is a Go webserver with some embedded, static web content like
|
||||
HTML, JS and CSS files. While developing it, you do not want to rebuild the
|
||||
whole server and restart it every time you make a change to a bit of
|
||||
javascript. You just want to build and launch the server once. Then just press
|
||||
refresh in the browser to see those changes. Embedding the assets with the
|
||||
`debug` flag allows you to do just that. When you are finished developing and
|
||||
ready for deployment, just re-invoke `go-bindata` without the `-debug` flag.
|
||||
It will now embed the latest version of the assets.
|
||||
|
||||
|
||||
### Lower memory footprint
|
||||
|
||||
Using the `-nomemcopy` flag, will alter the way the output file is generated.
|
||||
It will employ a hack that allows us to read the file data directly from
|
||||
the compiled program's `.rodata` section. This ensures that when we call
|
||||
call our generated function, we omit unnecessary memcopies.
|
||||
|
||||
The downside of this, is that it requires dependencies on the `reflect` and
|
||||
`unsafe` packages. These may be restricted on platforms like AppEngine and
|
||||
thus prevent you from using this mode.
|
||||
|
||||
Another disadvantage is that the byte slice we create, is strictly read-only.
|
||||
For most use-cases this is not a problem, but if you ever try to alter the
|
||||
returned byte slice, a runtime panic is thrown. Use this mode only on target
|
||||
platforms where memory constraints are an issue.
|
||||
|
||||
The default behaviour is to use the old code generation method. This
|
||||
prevents the two previously mentioned issues, but will employ at least one
|
||||
extra memcopy and thus increase memory requirements.
|
||||
|
||||
For instance, consider the following two examples:
|
||||
|
||||
This would be the default mode, using an extra memcopy but gives a safe
|
||||
implementation without dependencies on `reflect` and `unsafe`:
|
||||
|
||||
```go
|
||||
func myfile() []byte {
|
||||
return []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a}
|
||||
}
|
||||
```
|
||||
|
||||
Here is the same functionality, but uses the `.rodata` hack.
|
||||
The byte slice returned from this example can not be written to without
|
||||
generating a runtime error.
|
||||
|
||||
```go
|
||||
var _myfile = "\x89\x50\x4e\x47\x0d\x0a\x1a"
|
||||
|
||||
func myfile() []byte {
|
||||
var empty [0]byte
|
||||
sx := (*reflect.StringHeader)(unsafe.Pointer(&_myfile))
|
||||
b := empty[:]
|
||||
bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
bx.Data = sx.Data
|
||||
bx.Len = len(_myfile)
|
||||
bx.Cap = bx.Len
|
||||
return b
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Optional compression
|
||||
|
||||
When the `-nocompress` flag is given, the supplied resource is *not* GZIP
|
||||
compressed before being turned into Go code. The data should still be accessed
|
||||
through a function call, so nothing changes in the usage of the generated file.
|
||||
|
||||
This feature is useful if you do not care for compression, or the supplied
|
||||
resource is already compressed. Doing it again would not add any value and may
|
||||
even increase the size of the data.
|
||||
|
||||
The default behaviour of the program is to use compression.
|
||||
|
||||
|
||||
### Path prefix stripping
|
||||
|
||||
The keys used in the `_bindata` map, are the same as the input file name
|
||||
passed to `go-bindata`. This includes the path. In most cases, this is not
|
||||
desireable, as it puts potentially sensitive information in your code base.
|
||||
For this purpose, the tool supplies another command line flag `-prefix`.
|
||||
This accepts a portion of a path name, which should be stripped off from
|
||||
the map keys and function names.
|
||||
|
||||
For example, running without the `-prefix` flag, we get:
|
||||
|
||||
$ go-bindata /path/to/templates/
|
||||
|
||||
_bindata["/path/to/templates/foo.html"] = path_to_templates_foo_html
|
||||
|
||||
Running with the `-prefix` flag, we get:
|
||||
|
||||
$ go-bindata -prefix "/path/to/" /path/to/templates/
|
||||
|
||||
_bindata["templates/foo.html"] = templates_foo_html
|
||||
|
||||
|
||||
### Build tags
|
||||
|
||||
With the optional `-tags` flag, you can specify any go build tags that
|
||||
must be fulfilled for the output file to be included in a build. This
|
||||
is useful when including binary data in multiple formats, where the desired
|
||||
format is specified at build time with the appropriate tags.
|
||||
|
||||
The tags are appended to a `// +build` line in the beginning of the output file
|
||||
and must follow the build tags syntax specified by the go tool.
|
||||
|
||||
### Related projects
|
||||
|
||||
[go-bindata-assetfs](https://github.com/elazarl/go-bindata-assetfs#readme) -
|
||||
implements `http.FileSystem` interface. Allows you to serve assets with `net/http`.
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
// license. Its contents can be found at:
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
package bindata
|
||||
|
||||
// Asset holds information about a single asset to be processed.
|
||||
type Asset struct {
|
||||
Path string // Full file path.
|
||||
Name string // Key used in TOC -- name by which asset is referenced.
|
||||
Func string // Function name for the procedure returning the asset contents.
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
// license. Its contents can be found at:
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
package bindata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
newline = []byte{'\n'}
|
||||
dataindent = []byte{'\t', '\t'}
|
||||
space = []byte{' '}
|
||||
)
|
||||
|
||||
type ByteWriter struct {
|
||||
io.Writer
|
||||
c int
|
||||
}
|
||||
|
||||
func (w *ByteWriter) Write(p []byte) (n int, err error) {
|
||||
if len(p) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for n = range p {
|
||||
if w.c%12 == 0 {
|
||||
w.Writer.Write(newline)
|
||||
w.Writer.Write(dataindent)
|
||||
w.c = 0
|
||||
} else {
|
||||
w.Writer.Write(space)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w.Writer, "0x%02x,", p[n])
|
||||
w.c++
|
||||
}
|
||||
|
||||
n++
|
||||
|
||||
return
|
||||
}
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
// license. Its contents can be found at:
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
package bindata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// InputConfig defines options on a asset directory to be convert.
|
||||
type InputConfig struct {
|
||||
// Path defines a directory containing asset files to be included
|
||||
// in the generated output.
|
||||
Path string
|
||||
|
||||
// Recusive defines whether subdirectories of Path
|
||||
// should be recursively included in the conversion.
|
||||
Recursive bool
|
||||
}
|
||||
|
||||
// Config defines a set of options for the asset conversion.
|
||||
type Config struct {
|
||||
// Name of the package to use. Defaults to 'main'.
|
||||
Package string
|
||||
|
||||
// Tags specify a set of optional build tags, which should be
|
||||
// included in the generated output. The tags are appended to a
|
||||
// `// +build` line in the beginning of the output file
|
||||
// and must follow the build tags syntax specified by the go tool.
|
||||
Tags string
|
||||
|
||||
// Input defines the directory path, containing all asset files as
|
||||
// well as whether to recursively process assets in any sub directories.
|
||||
Input []InputConfig
|
||||
|
||||
// Output defines the output file for the generated code.
|
||||
// If left empty, this defaults to 'bindata.go' in the current
|
||||
// working directory.
|
||||
Output string
|
||||
|
||||
// Prefix defines a path prefix which should be stripped from all
|
||||
// file names when generating the keys in the table of contents.
|
||||
// For example, running without the `-prefix` flag, we get:
|
||||
//
|
||||
// $ go-bindata /path/to/templates
|
||||
// go_bindata["/path/to/templates/foo.html"] = _path_to_templates_foo_html
|
||||
//
|
||||
// Running with the `-prefix` flag, we get:
|
||||
//
|
||||
// $ go-bindata -prefix "/path/to/" /path/to/templates/foo.html
|
||||
// go_bindata["templates/foo.html"] = templates_foo_html
|
||||
Prefix string
|
||||
|
||||
// NoMemCopy will alter the way the output file is generated.
|
||||
//
|
||||
// It will employ a hack that allows us to read the file data directly from
|
||||
// the compiled program's `.rodata` section. This ensures that when we call
|
||||
// call our generated function, we omit unnecessary mem copies.
|
||||
//
|
||||
// The downside of this, is that it requires dependencies on the `reflect` and
|
||||
// `unsafe` packages. These may be restricted on platforms like AppEngine and
|
||||
// thus prevent you from using this mode.
|
||||
//
|
||||
// Another disadvantage is that the byte slice we create, is strictly read-only.
|
||||
// For most use-cases this is not a problem, but if you ever try to alter the
|
||||
// returned byte slice, a runtime panic is thrown. Use this mode only on target
|
||||
// platforms where memory constraints are an issue.
|
||||
//
|
||||
// The default behaviour is to use the old code generation method. This
|
||||
// prevents the two previously mentioned issues, but will employ at least one
|
||||
// extra memcopy and thus increase memory requirements.
|
||||
//
|
||||
// For instance, consider the following two examples:
|
||||
//
|
||||
// This would be the default mode, using an extra memcopy but gives a safe
|
||||
// implementation without dependencies on `reflect` and `unsafe`:
|
||||
//
|
||||
// func myfile() []byte {
|
||||
// return []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a}
|
||||
// }
|
||||
//
|
||||
// Here is the same functionality, but uses the `.rodata` hack.
|
||||
// The byte slice returned from this example can not be written to without
|
||||
// generating a runtime error.
|
||||
//
|
||||
// var _myfile = "\x89\x50\x4e\x47\x0d\x0a\x1a"
|
||||
//
|
||||
// func myfile() []byte {
|
||||
// var empty [0]byte
|
||||
// sx := (*reflect.StringHeader)(unsafe.Pointer(&_myfile))
|
||||
// b := empty[:]
|
||||
// bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
// bx.Data = sx.Data
|
||||
// bx.Len = len(_myfile)
|
||||
// bx.Cap = bx.Len
|
||||
// return b
|
||||
// }
|
||||
NoMemCopy bool
|
||||
|
||||
// NoCompress means the assets are /not/ GZIP compressed before being turned
|
||||
// into Go code. The generated function will automatically unzip
|
||||
// the file data when called. Defaults to false.
|
||||
NoCompress bool
|
||||
|
||||
// Perform a debug build. This generates an asset file, which
|
||||
// loads the asset contents directly from disk at their original
|
||||
// location, instead of embedding the contents in the code.
|
||||
//
|
||||
// This is mostly useful if you anticipate that the assets are
|
||||
// going to change during your development cycle. You will always
|
||||
// want your code to access the latest version of the asset.
|
||||
// Only in release mode, will the assets actually be embedded
|
||||
// in the code. The default behaviour is Release mode.
|
||||
Debug bool
|
||||
|
||||
// Perform a dev build, which is nearly identical to the debug option. The
|
||||
// only difference is that instead of absolute file paths in generated code,
|
||||
// it expects a variable, `rootDir`, to be set in the generated code's
|
||||
// package (the author needs to do this manually), which it then prepends to
|
||||
// an asset's name to construct the file path on disk.
|
||||
//
|
||||
// This is mainly so you can push the generated code file to a shared
|
||||
// repository.
|
||||
Dev bool
|
||||
|
||||
// When true, size, mode and modtime are not preserved from files
|
||||
NoMetadata bool
|
||||
// When nonzero, use this as mode for all files.
|
||||
Mode uint
|
||||
// When nonzero, use this as unix timestamp for all files.
|
||||
ModTime int64
|
||||
|
||||
// Ignores any filenames matching the regex pattern specified, e.g.
|
||||
// path/to/file.ext will ignore only that file, or \\.gitignore
|
||||
// will match any .gitignore file.
|
||||
//
|
||||
// This parameter can be provided multiple times.
|
||||
Ignore []*regexp.Regexp
|
||||
}
|
||||
|
||||
// NewConfig returns a default configuration struct.
|
||||
func NewConfig() *Config {
|
||||
c := new(Config)
|
||||
c.Package = "main"
|
||||
c.NoMemCopy = false
|
||||
c.NoCompress = false
|
||||
c.Debug = false
|
||||
c.Output = "./bindata.go"
|
||||
c.Ignore = make([]*regexp.Regexp, 0)
|
||||
return c
|
||||
}
|
||||
|
||||
// validate ensures the config has sane values.
|
||||
// Part of which means checking if certain file/directory paths exist.
|
||||
func (c *Config) validate() error {
|
||||
if len(c.Package) == 0 {
|
||||
return fmt.Errorf("Missing package name")
|
||||
}
|
||||
|
||||
for _, input := range c.Input {
|
||||
_, err := os.Lstat(input.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to stat input path '%s': %v", input.Path, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.Output) == 0 {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to determine current working directory.")
|
||||
}
|
||||
|
||||
c.Output = filepath.Join(cwd, "bindata.go")
|
||||
}
|
||||
|
||||
stat, err := os.Lstat(c.Output)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return fmt.Errorf("Output path: %v", err)
|
||||
}
|
||||
|
||||
// File does not exist. This is fine, just make
|
||||
// sure the directory it is to be in exists.
|
||||
dir, _ := filepath.Split(c.Output)
|
||||
if dir != "" {
|
||||
err = os.MkdirAll(dir, 0744)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Create output directory: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if stat != nil && stat.IsDir() {
|
||||
return fmt.Errorf("Output path is a directory.")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
// license. Its contents can be found at:
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
package bindata
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Translate reads assets from an input directory, converts them
|
||||
// to Go code and writes new files to the output specified
|
||||
// in the given configuration.
|
||||
func Translate(c *Config) error {
|
||||
var toc []Asset
|
||||
|
||||
// Ensure our configuration has sane values.
|
||||
err := c.validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var knownFuncs = make(map[string]int)
|
||||
var visitedPaths = make(map[string]bool)
|
||||
// Locate all the assets.
|
||||
for _, input := range c.Input {
|
||||
err = findFiles(input.Path, c.Prefix, input.Recursive, &toc, c.Ignore, knownFuncs, visitedPaths)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create output file.
|
||||
fd, err := os.Create(c.Output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer fd.Close()
|
||||
|
||||
// Create a buffered writer for better performance.
|
||||
bfd := bufio.NewWriter(fd)
|
||||
defer bfd.Flush()
|
||||
|
||||
// Write the header. This makes e.g. Github ignore diffs in generated files.
|
||||
if _, err = fmt.Fprint(bfd, "// Code generated by go-bindata.\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = fmt.Fprint(bfd, "// sources:\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, asset := range toc {
|
||||
relative, _ := filepath.Rel(wd, asset.Path)
|
||||
if _, err = fmt.Fprintf(bfd, "// %s\n", filepath.ToSlash(relative)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err = fmt.Fprint(bfd, "// DO NOT EDIT!\n\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write build tags, if applicable.
|
||||
if len(c.Tags) > 0 {
|
||||
if _, err = fmt.Fprintf(bfd, "// +build %s\n\n", c.Tags); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Write package declaration.
|
||||
_, err = fmt.Fprintf(bfd, "package %s\n\n", c.Package)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write assets.
|
||||
if c.Debug || c.Dev {
|
||||
err = writeDebug(bfd, c, toc)
|
||||
} else {
|
||||
err = writeRelease(bfd, c, toc)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write table of contents
|
||||
if err := writeTOC(bfd, toc); err != nil {
|
||||
return err
|
||||
}
|
||||
// Write hierarchical tree of assets
|
||||
if err := writeTOCTree(bfd, toc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write restore procedure
|
||||
return writeRestore(bfd)
|
||||
}
|
||||
|
||||
// Implement sort.Interface for []os.FileInfo based on Name()
|
||||
type ByName []os.FileInfo
|
||||
|
||||
func (v ByName) Len() int { return len(v) }
|
||||
func (v ByName) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
|
||||
func (v ByName) Less(i, j int) bool { return v[i].Name() < v[j].Name() }
|
||||
|
||||
// findFiles recursively finds all the file paths in the given directory tree.
|
||||
// They are added to the given map as keys. Values will be safe function names
|
||||
// for each file, which will be used when generating the output code.
|
||||
func findFiles(dir, prefix string, recursive bool, toc *[]Asset, ignore []*regexp.Regexp, knownFuncs map[string]int, visitedPaths map[string]bool) error {
|
||||
dirpath := dir
|
||||
if len(prefix) > 0 {
|
||||
dirpath, _ = filepath.Abs(dirpath)
|
||||
prefix, _ = filepath.Abs(prefix)
|
||||
prefix = filepath.ToSlash(prefix)
|
||||
}
|
||||
|
||||
fi, err := os.Stat(dirpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var list []os.FileInfo
|
||||
|
||||
if !fi.IsDir() {
|
||||
dirpath = filepath.Dir(dirpath)
|
||||
list = []os.FileInfo{fi}
|
||||
} else {
|
||||
visitedPaths[dirpath] = true
|
||||
fd, err := os.Open(dirpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer fd.Close()
|
||||
|
||||
list, err = fd.Readdir(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Sort to make output stable between invocations
|
||||
sort.Sort(ByName(list))
|
||||
}
|
||||
|
||||
for _, file := range list {
|
||||
var asset Asset
|
||||
asset.Path = filepath.Join(dirpath, file.Name())
|
||||
asset.Name = filepath.ToSlash(asset.Path)
|
||||
|
||||
ignoring := false
|
||||
for _, re := range ignore {
|
||||
if re.MatchString(asset.Path) {
|
||||
ignoring = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if ignoring {
|
||||
continue
|
||||
}
|
||||
|
||||
if file.IsDir() {
|
||||
if recursive {
|
||||
recursivePath := filepath.Join(dir, file.Name())
|
||||
visitedPaths[asset.Path] = true
|
||||
findFiles(recursivePath, prefix, recursive, toc, ignore, knownFuncs, visitedPaths)
|
||||
}
|
||||
continue
|
||||
} else if file.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
var linkPath string
|
||||
if linkPath, err = os.Readlink(asset.Path); err != nil {
|
||||
return err
|
||||
}
|
||||
if !filepath.IsAbs(linkPath) {
|
||||
if linkPath, err = filepath.Abs(dirpath + "/" + linkPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, ok := visitedPaths[linkPath]; !ok {
|
||||
visitedPaths[linkPath] = true
|
||||
findFiles(asset.Path, prefix, recursive, toc, ignore, knownFuncs, visitedPaths)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(asset.Name, prefix) {
|
||||
asset.Name = asset.Name[len(prefix):]
|
||||
} else {
|
||||
asset.Name = filepath.Join(dir, file.Name())
|
||||
}
|
||||
|
||||
// If we have a leading slash, get rid of it.
|
||||
if len(asset.Name) > 0 && asset.Name[0] == '/' {
|
||||
asset.Name = asset.Name[1:]
|
||||
}
|
||||
|
||||
// This shouldn't happen.
|
||||
if len(asset.Name) == 0 {
|
||||
return fmt.Errorf("Invalid file: %v", asset.Path)
|
||||
}
|
||||
|
||||
asset.Func = safeFunctionName(asset.Name, knownFuncs)
|
||||
asset.Path, _ = filepath.Abs(asset.Path)
|
||||
*toc = append(*toc, asset)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var regFuncName = regexp.MustCompile(`[^a-zA-Z0-9_]`)
|
||||
|
||||
// safeFunctionName converts the given name into a name
|
||||
// which qualifies as a valid function identifier. It
|
||||
// also compares against a known list of functions to
|
||||
// prevent conflict based on name translation.
|
||||
func safeFunctionName(name string, knownFuncs map[string]int) string {
|
||||
var inBytes, outBytes []byte
|
||||
var toUpper bool
|
||||
|
||||
name = strings.ToLower(name)
|
||||
inBytes = []byte(name)
|
||||
|
||||
for i := 0; i < len(inBytes); i++ {
|
||||
if regFuncName.Match([]byte{inBytes[i]}) {
|
||||
toUpper = true
|
||||
} else if toUpper {
|
||||
outBytes = append(outBytes, []byte(strings.ToUpper(string(inBytes[i])))...)
|
||||
toUpper = false
|
||||
} else {
|
||||
outBytes = append(outBytes, inBytes[i])
|
||||
}
|
||||
}
|
||||
|
||||
name = string(outBytes)
|
||||
|
||||
// Identifier can't start with a digit.
|
||||
if unicode.IsDigit(rune(name[0])) {
|
||||
name = "_" + name
|
||||
}
|
||||
|
||||
if num, ok := knownFuncs[name]; ok {
|
||||
knownFuncs[name] = num + 1
|
||||
name = fmt.Sprintf("%s%d", name, num)
|
||||
} else {
|
||||
knownFuncs[name] = 2
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
// license. Its contents can be found at:
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
package bindata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// writeDebug writes the debug code file.
|
||||
func writeDebug(w io.Writer, c *Config, toc []Asset) error {
|
||||
err := writeDebugHeader(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range toc {
|
||||
err = writeDebugAsset(w, c, &toc[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeDebugHeader writes output file headers.
|
||||
// This targets debug builds.
|
||||
func writeDebugHeader(w io.Writer) error {
|
||||
_, err := fmt.Fprintf(w, `import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// bindataRead reads the given file from disk. It returns an error on failure.
|
||||
func bindataRead(path, name string) ([]byte, error) {
|
||||
buf, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error reading asset %%s at %%s: %%v", name, path, err)
|
||||
}
|
||||
return buf, err
|
||||
}
|
||||
|
||||
type asset struct {
|
||||
bytes []byte
|
||||
info os.FileInfo
|
||||
}
|
||||
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
// writeDebugAsset write a debug entry for the given asset.
|
||||
// A debug entry is simply a function which reads the asset from
|
||||
// the original file (e.g.: from disk).
|
||||
func writeDebugAsset(w io.Writer, c *Config, asset *Asset) error {
|
||||
pathExpr := fmt.Sprintf("%q", asset.Path)
|
||||
if c.Dev {
|
||||
pathExpr = fmt.Sprintf("filepath.Join(rootDir, %q)", asset.Name)
|
||||
}
|
||||
|
||||
_, err := fmt.Fprintf(w, `// %s reads file data from disk. It returns an error on failure.
|
||||
func %s() (*asset, error) {
|
||||
path := %s
|
||||
name := %q
|
||||
bytes, err := bindataRead(path, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error reading asset info %%s at %%s: %%v", name, path, err)
|
||||
}
|
||||
|
||||
a := &asset{bytes: bytes, info: fi}
|
||||
return a, err
|
||||
}
|
||||
|
||||
`, asset.Func, asset.Func, pathExpr, asset.Name)
|
||||
return err
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
// license. Its contents can be found at:
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
/*
|
||||
bindata converts any file into managable Go source code. Useful for
|
||||
embedding binary data into a go program. The file data is optionally gzip
|
||||
compressed before being converted to a raw byte slice.
|
||||
|
||||
The following paragraphs cover some of the customization options
|
||||
which can be specified in the Config struct, which must be passed into
|
||||
the Translate() call.
|
||||
|
||||
|
||||
Debug vs Release builds
|
||||
|
||||
When used with the `Debug` option, the generated code does not actually include
|
||||
the asset data. Instead, it generates function stubs which load the data from
|
||||
the original file on disk. The asset API remains identical between debug and
|
||||
release builds, so your code will not have to change.
|
||||
|
||||
This is useful during development when you expect the assets to change often.
|
||||
The host application using these assets uses the same API in both cases and
|
||||
will not have to care where the actual data comes from.
|
||||
|
||||
An example is a Go webserver with some embedded, static web content like
|
||||
HTML, JS and CSS files. While developing it, you do not want to rebuild the
|
||||
whole server and restart it every time you make a change to a bit of
|
||||
javascript. You just want to build and launch the server once. Then just press
|
||||
refresh in the browser to see those changes. Embedding the assets with the
|
||||
`debug` flag allows you to do just that. When you are finished developing and
|
||||
ready for deployment, just re-invoke `go-bindata` without the `-debug` flag.
|
||||
It will now embed the latest version of the assets.
|
||||
|
||||
|
||||
Lower memory footprint
|
||||
|
||||
The `NoMemCopy` option will alter the way the output file is generated.
|
||||
It will employ a hack that allows us to read the file data directly from
|
||||
the compiled program's `.rodata` section. This ensures that when we call
|
||||
call our generated function, we omit unnecessary memcopies.
|
||||
|
||||
The downside of this, is that it requires dependencies on the `reflect` and
|
||||
`unsafe` packages. These may be restricted on platforms like AppEngine and
|
||||
thus prevent you from using this mode.
|
||||
|
||||
Another disadvantage is that the byte slice we create, is strictly read-only.
|
||||
For most use-cases this is not a problem, but if you ever try to alter the
|
||||
returned byte slice, a runtime panic is thrown. Use this mode only on target
|
||||
platforms where memory constraints are an issue.
|
||||
|
||||
The default behaviour is to use the old code generation method. This
|
||||
prevents the two previously mentioned issues, but will employ at least one
|
||||
extra memcopy and thus increase memory requirements.
|
||||
|
||||
For instance, consider the following two examples:
|
||||
|
||||
This would be the default mode, using an extra memcopy but gives a safe
|
||||
implementation without dependencies on `reflect` and `unsafe`:
|
||||
|
||||
func myfile() []byte {
|
||||
return []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a}
|
||||
}
|
||||
|
||||
Here is the same functionality, but uses the `.rodata` hack.
|
||||
The byte slice returned from this example can not be written to without
|
||||
generating a runtime error.
|
||||
|
||||
var _myfile = "\x89\x50\x4e\x47\x0d\x0a\x1a"
|
||||
|
||||
func myfile() []byte {
|
||||
var empty [0]byte
|
||||
sx := (*reflect.StringHeader)(unsafe.Pointer(&_myfile))
|
||||
b := empty[:]
|
||||
bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
bx.Data = sx.Data
|
||||
bx.Len = len(_myfile)
|
||||
bx.Cap = bx.Len
|
||||
return b
|
||||
}
|
||||
|
||||
|
||||
Optional compression
|
||||
|
||||
The NoCompress option indicates that the supplied assets are *not* GZIP
|
||||
compressed before being turned into Go code. The data should still be accessed
|
||||
through a function call, so nothing changes in the API.
|
||||
|
||||
This feature is useful if you do not care for compression, or the supplied
|
||||
resource is already compressed. Doing it again would not add any value and may
|
||||
even increase the size of the data.
|
||||
|
||||
The default behaviour of the program is to use compression.
|
||||
|
||||
|
||||
Path prefix stripping
|
||||
|
||||
The keys used in the `_bindata` map are the same as the input file name
|
||||
passed to `go-bindata`. This includes the path. In most cases, this is not
|
||||
desireable, as it puts potentially sensitive information in your code base.
|
||||
For this purpose, the tool supplies another command line flag `-prefix`.
|
||||
This accepts a portion of a path name, which should be stripped off from
|
||||
the map keys and function names.
|
||||
|
||||
For example, running without the `-prefix` flag, we get:
|
||||
|
||||
$ go-bindata /path/to/templates/
|
||||
|
||||
_bindata["/path/to/templates/foo.html"] = path_to_templates_foo_html
|
||||
|
||||
Running with the `-prefix` flag, we get:
|
||||
|
||||
$ go-bindata -prefix "/path/to/" /path/to/templates/
|
||||
|
||||
_bindata["templates/foo.html"] = templates_foo_html
|
||||
|
||||
|
||||
Build tags
|
||||
|
||||
With the optional Tags field, you can specify any go build tags that
|
||||
must be fulfilled for the output file to be included in a build. This
|
||||
is useful when including binary data in multiple formats, where the desired
|
||||
format is specified at build time with the appropriate tags.
|
||||
|
||||
The tags are appended to a `// +build` line in the beginning of the output file
|
||||
and must follow the build tags syntax specified by the go tool.
|
||||
|
||||
*/
|
||||
package bindata
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import "strings"
|
||||
|
||||
// borrowed from https://github.com/hashicorp/serf/blob/master/command/agent/flag_slice_value.go
|
||||
|
||||
// AppendSliceValue implements the flag.Value interface and allows multiple
|
||||
// calls to the same variable to append a list.
|
||||
type AppendSliceValue []string
|
||||
|
||||
func (s *AppendSliceValue) String() string {
|
||||
return strings.Join(*s, ",")
|
||||
}
|
||||
|
||||
func (s *AppendSliceValue) Set(value string) error {
|
||||
if *s == nil {
|
||||
*s = make([]string, 0, 1)
|
||||
}
|
||||
|
||||
*s = append(*s, value)
|
||||
return nil
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
// license. Its contents can be found at:
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/jteeuwen/go-bindata"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg := parseArgs()
|
||||
err := bindata.Translate(cfg)
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "bindata: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// parseArgs create s a new, filled configuration instance
|
||||
// by reading and parsing command line options.
|
||||
//
|
||||
// This function exits the program with an error, if
|
||||
// any of the command line options are incorrect.
|
||||
func parseArgs() *bindata.Config {
|
||||
var version bool
|
||||
|
||||
c := bindata.NewConfig()
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Printf("Usage: %s [options] <input directories>\n\n", os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
flag.BoolVar(&c.Debug, "debug", c.Debug, "Do not embed the assets, but provide the embedding API. Contents will still be loaded from disk.")
|
||||
flag.BoolVar(&c.Dev, "dev", c.Dev, "Similar to debug, but does not emit absolute paths. Expects a rootDir variable to already exist in the generated code's package.")
|
||||
flag.StringVar(&c.Tags, "tags", c.Tags, "Optional set of build tags to include.")
|
||||
flag.StringVar(&c.Prefix, "prefix", c.Prefix, "Optional path prefix to strip off asset names.")
|
||||
flag.StringVar(&c.Package, "pkg", c.Package, "Package name to use in the generated code.")
|
||||
flag.BoolVar(&c.NoMemCopy, "nomemcopy", c.NoMemCopy, "Use a .rodata hack to get rid of unnecessary memcopies. Refer to the documentation to see what implications this carries.")
|
||||
flag.BoolVar(&c.NoCompress, "nocompress", c.NoCompress, "Assets will *not* be GZIP compressed when this flag is specified.")
|
||||
flag.BoolVar(&c.NoMetadata, "nometadata", c.NoMetadata, "Assets will not preserve size, mode, and modtime info.")
|
||||
flag.UintVar(&c.Mode, "mode", c.Mode, "Optional file mode override for all files.")
|
||||
flag.Int64Var(&c.ModTime, "modtime", c.ModTime, "Optional modification unix timestamp override for all files.")
|
||||
flag.StringVar(&c.Output, "o", c.Output, "Optional name of the output file to be generated.")
|
||||
flag.BoolVar(&version, "version", false, "Displays version information.")
|
||||
|
||||
ignore := make([]string, 0)
|
||||
flag.Var((*AppendSliceValue)(&ignore), "ignore", "Regex pattern to ignore")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
patterns := make([]*regexp.Regexp, 0)
|
||||
for _, pattern := range ignore {
|
||||
patterns = append(patterns, regexp.MustCompile(pattern))
|
||||
}
|
||||
c.Ignore = patterns
|
||||
|
||||
if version {
|
||||
fmt.Printf("%s\n", Version())
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Make sure we have input paths.
|
||||
if flag.NArg() == 0 {
|
||||
fmt.Fprintf(os.Stderr, "Missing <input dir>\n\n")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Create input configurations.
|
||||
c.Input = make([]bindata.InputConfig, flag.NArg())
|
||||
for i := range c.Input {
|
||||
c.Input[i] = parseInput(flag.Arg(i))
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// parseRecursive determines whether the given path has a recrusive indicator and
|
||||
// returns a new path with the recursive indicator chopped off if it does.
|
||||
//
|
||||
// ex:
|
||||
// /path/to/foo/... -> (/path/to/foo, true)
|
||||
// /path/to/bar -> (/path/to/bar, false)
|
||||
func parseInput(path string) bindata.InputConfig {
|
||||
if strings.HasSuffix(path, "/...") {
|
||||
return bindata.InputConfig{
|
||||
Path: filepath.Clean(path[:len(path)-4]),
|
||||
Recursive: true,
|
||||
}
|
||||
} else {
|
||||
return bindata.InputConfig{
|
||||
Path: filepath.Clean(path),
|
||||
Recursive: false,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
// license. Its contents can be found at:
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
const (
|
||||
AppName = "go-bindata"
|
||||
AppVersionMajor = 3
|
||||
AppVersionMinor = 1
|
||||
)
|
||||
|
||||
// revision part of the program version.
|
||||
// This will be set automatically at build time like so:
|
||||
//
|
||||
// go build -ldflags "-X main.AppVersionRev `date -u +%s`"
|
||||
var AppVersionRev string
|
||||
|
||||
func Version() string {
|
||||
if len(AppVersionRev) == 0 {
|
||||
AppVersionRev = "0"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s %d.%d.%s (Go runtime %s).\nCopyright (c) 2010-2013, Jim Teeuwen.",
|
||||
AppName, AppVersionMajor, AppVersionMinor, AppVersionRev, runtime.Version())
|
||||
}
|
||||
+387
@@ -0,0 +1,387 @@
|
||||
// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
// license. Its contents can be found at:
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
package bindata
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// writeRelease writes the release code file.
|
||||
func writeRelease(w io.Writer, c *Config, toc []Asset) error {
|
||||
err := writeReleaseHeader(w, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range toc {
|
||||
err = writeReleaseAsset(w, c, &toc[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeReleaseHeader writes output file headers.
|
||||
// This targets release builds.
|
||||
func writeReleaseHeader(w io.Writer, c *Config) error {
|
||||
var err error
|
||||
if c.NoCompress {
|
||||
if c.NoMemCopy {
|
||||
err = header_uncompressed_nomemcopy(w)
|
||||
} else {
|
||||
err = header_uncompressed_memcopy(w)
|
||||
}
|
||||
} else {
|
||||
if c.NoMemCopy {
|
||||
err = header_compressed_nomemcopy(w)
|
||||
} else {
|
||||
err = header_compressed_memcopy(w)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return header_release_common(w)
|
||||
}
|
||||
|
||||
// writeReleaseAsset write a release entry for the given asset.
|
||||
// A release entry is a function which embeds and returns
|
||||
// the file's byte content.
|
||||
func writeReleaseAsset(w io.Writer, c *Config, asset *Asset) error {
|
||||
fd, err := os.Open(asset.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer fd.Close()
|
||||
|
||||
if c.NoCompress {
|
||||
if c.NoMemCopy {
|
||||
err = uncompressed_nomemcopy(w, asset, fd)
|
||||
} else {
|
||||
err = uncompressed_memcopy(w, asset, fd)
|
||||
}
|
||||
} else {
|
||||
if c.NoMemCopy {
|
||||
err = compressed_nomemcopy(w, asset, fd)
|
||||
} else {
|
||||
err = compressed_memcopy(w, asset, fd)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return asset_release_common(w, c, asset)
|
||||
}
|
||||
|
||||
// sanitize prepares a valid UTF-8 string as a raw string constant.
|
||||
// Based on https://code.google.com/p/go/source/browse/godoc/static/makestatic.go?repo=tools
|
||||
func sanitize(b []byte) []byte {
|
||||
// Replace ` with `+"`"+`
|
||||
b = bytes.Replace(b, []byte("`"), []byte("`+\"`\"+`"), -1)
|
||||
|
||||
// Replace BOM with `+"\xEF\xBB\xBF"+`
|
||||
// (A BOM is valid UTF-8 but not permitted in Go source files.
|
||||
// I wouldn't bother handling this, but for some insane reason
|
||||
// jquery.js has a BOM somewhere in the middle.)
|
||||
return bytes.Replace(b, []byte("\xEF\xBB\xBF"), []byte("`+\"\\xEF\\xBB\\xBF\"+`"), -1)
|
||||
}
|
||||
|
||||
func header_compressed_nomemcopy(w io.Writer) error {
|
||||
_, err := fmt.Fprintf(w, `import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func bindataRead(data, name string) ([]byte, error) {
|
||||
gz, err := gzip.NewReader(strings.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %%q: %%v", name, err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, gz)
|
||||
clErr := gz.Close()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %%q: %%v", name, err)
|
||||
}
|
||||
if clErr != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func header_compressed_memcopy(w io.Writer) error {
|
||||
_, err := fmt.Fprintf(w, `import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func bindataRead(data []byte, name string) ([]byte, error) {
|
||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %%q: %%v", name, err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, gz)
|
||||
clErr := gz.Close()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %%q: %%v", name, err)
|
||||
}
|
||||
if clErr != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func header_uncompressed_nomemcopy(w io.Writer) error {
|
||||
_, err := fmt.Fprintf(w, `import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func bindataRead(data, name string) ([]byte, error) {
|
||||
var empty [0]byte
|
||||
sx := (*reflect.StringHeader)(unsafe.Pointer(&data))
|
||||
b := empty[:]
|
||||
bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
bx.Data = sx.Data
|
||||
bx.Len = len(data)
|
||||
bx.Cap = bx.Len
|
||||
return b, nil
|
||||
}
|
||||
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func header_uncompressed_memcopy(w io.Writer) error {
|
||||
_, err := fmt.Fprintf(w, `import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func header_release_common(w io.Writer) error {
|
||||
_, err := fmt.Fprintf(w, `type asset struct {
|
||||
bytes []byte
|
||||
info os.FileInfo
|
||||
}
|
||||
|
||||
type bindataFileInfo struct {
|
||||
name string
|
||||
size int64
|
||||
mode os.FileMode
|
||||
modTime time.Time
|
||||
}
|
||||
|
||||
func (fi bindataFileInfo) Name() string {
|
||||
return fi.name
|
||||
}
|
||||
func (fi bindataFileInfo) Size() int64 {
|
||||
return fi.size
|
||||
}
|
||||
func (fi bindataFileInfo) Mode() os.FileMode {
|
||||
return fi.mode
|
||||
}
|
||||
func (fi bindataFileInfo) ModTime() time.Time {
|
||||
return fi.modTime
|
||||
}
|
||||
func (fi bindataFileInfo) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
func (fi bindataFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
func compressed_nomemcopy(w io.Writer, asset *Asset, r io.Reader) error {
|
||||
_, err := fmt.Fprintf(w, `var _%s = "`, asset.Func)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gz := gzip.NewWriter(&StringWriter{Writer: w})
|
||||
_, err = io.Copy(gz, r)
|
||||
gz.Close()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintf(w, `"
|
||||
|
||||
func %sBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_%s,
|
||||
%q,
|
||||
)
|
||||
}
|
||||
|
||||
`, asset.Func, asset.Func, asset.Name)
|
||||
return err
|
||||
}
|
||||
|
||||
func compressed_memcopy(w io.Writer, asset *Asset, r io.Reader) error {
|
||||
_, err := fmt.Fprintf(w, `var _%s = []byte("`, asset.Func)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gz := gzip.NewWriter(&StringWriter{Writer: w})
|
||||
_, err = io.Copy(gz, r)
|
||||
gz.Close()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintf(w, `")
|
||||
|
||||
func %sBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_%s,
|
||||
%q,
|
||||
)
|
||||
}
|
||||
|
||||
`, asset.Func, asset.Func, asset.Name)
|
||||
return err
|
||||
}
|
||||
|
||||
func uncompressed_nomemcopy(w io.Writer, asset *Asset, r io.Reader) error {
|
||||
_, err := fmt.Fprintf(w, `var _%s = "`, asset.Func)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(&StringWriter{Writer: w}, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintf(w, `"
|
||||
|
||||
func %sBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_%s,
|
||||
%q,
|
||||
)
|
||||
}
|
||||
|
||||
`, asset.Func, asset.Func, asset.Name)
|
||||
return err
|
||||
}
|
||||
|
||||
func uncompressed_memcopy(w io.Writer, asset *Asset, r io.Reader) error {
|
||||
_, err := fmt.Fprintf(w, `var _%s = []byte(`, asset.Func)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if utf8.Valid(b) && !bytes.Contains(b, []byte{0}) {
|
||||
fmt.Fprintf(w, "`%s`", sanitize(b))
|
||||
} else {
|
||||
fmt.Fprintf(w, "%+q", b)
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintf(w, `)
|
||||
|
||||
func %sBytes() ([]byte, error) {
|
||||
return _%s, nil
|
||||
}
|
||||
|
||||
`, asset.Func, asset.Func)
|
||||
return err
|
||||
}
|
||||
|
||||
func asset_release_common(w io.Writer, c *Config, asset *Asset) error {
|
||||
fi, err := os.Stat(asset.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mode := uint(fi.Mode())
|
||||
modTime := fi.ModTime().Unix()
|
||||
size := fi.Size()
|
||||
if c.NoMetadata {
|
||||
mode = 0
|
||||
modTime = 0
|
||||
size = 0
|
||||
}
|
||||
if c.Mode > 0 {
|
||||
mode = uint(os.ModePerm) & c.Mode
|
||||
}
|
||||
if c.ModTime > 0 {
|
||||
modTime = c.ModTime
|
||||
}
|
||||
_, err = fmt.Fprintf(w, `func %s() (*asset, error) {
|
||||
bytes, err := %sBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: %q, size: %d, mode: os.FileMode(%d), modTime: time.Unix(%d, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
`, asset.Func, asset.Func, asset.Name, size, mode, modTime)
|
||||
return err
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
// license. Its contents can be found at:
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
package bindata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
func writeRestore(w io.Writer) error {
|
||||
_, err := fmt.Fprintf(w, `
|
||||
// RestoreAsset restores an asset under the given directory
|
||||
func RestoreAsset(dir, name string) error {
|
||||
data, err := Asset(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := AssetInfo(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RestoreAssets restores an asset under the given directory recursively
|
||||
func RestoreAssets(dir, name string) error {
|
||||
children, err := AssetDir(name)
|
||||
// File
|
||||
if err != nil {
|
||||
return RestoreAsset(dir, name)
|
||||
}
|
||||
// Dir
|
||||
for _, child := range children {
|
||||
err = RestoreAssets(dir, filepath.Join(name, child))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func _filePath(dir, name string) string {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
|
||||
}
|
||||
|
||||
`)
|
||||
return err
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
// license. Its contents can be found at:
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
package bindata
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
const lowerHex = "0123456789abcdef"
|
||||
|
||||
type StringWriter struct {
|
||||
io.Writer
|
||||
c int
|
||||
}
|
||||
|
||||
func (w *StringWriter) Write(p []byte) (n int, err error) {
|
||||
if len(p) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
buf := []byte(`\x00`)
|
||||
var b byte
|
||||
|
||||
for n, b = range p {
|
||||
buf[2] = lowerHex[b/16]
|
||||
buf[3] = lowerHex[b%16]
|
||||
w.Writer.Write(buf)
|
||||
w.c++
|
||||
}
|
||||
|
||||
n++
|
||||
|
||||
return
|
||||
}
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
// license. Its contents can be found at:
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
package bindata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type assetTree struct {
|
||||
Asset Asset
|
||||
Children map[string]*assetTree
|
||||
}
|
||||
|
||||
func newAssetTree() *assetTree {
|
||||
tree := &assetTree{}
|
||||
tree.Children = make(map[string]*assetTree)
|
||||
return tree
|
||||
}
|
||||
|
||||
func (node *assetTree) child(name string) *assetTree {
|
||||
rv, ok := node.Children[name]
|
||||
if !ok {
|
||||
rv = newAssetTree()
|
||||
node.Children[name] = rv
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func (root *assetTree) Add(route []string, asset Asset) {
|
||||
for _, name := range route {
|
||||
root = root.child(name)
|
||||
}
|
||||
root.Asset = asset
|
||||
}
|
||||
|
||||
func ident(w io.Writer, n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
w.Write([]byte{'\t'})
|
||||
}
|
||||
}
|
||||
|
||||
func (root *assetTree) funcOrNil() string {
|
||||
if root.Asset.Func == "" {
|
||||
return "nil"
|
||||
} else {
|
||||
return root.Asset.Func
|
||||
}
|
||||
}
|
||||
|
||||
func (root *assetTree) writeGoMap(w io.Writer, nident int) {
|
||||
fmt.Fprintf(w, "&bintree{%s, map[string]*bintree{", root.funcOrNil())
|
||||
|
||||
if len(root.Children) > 0 {
|
||||
io.WriteString(w, "\n")
|
||||
|
||||
// Sort to make output stable between invocations
|
||||
filenames := make([]string, len(root.Children))
|
||||
i := 0
|
||||
for filename, _ := range root.Children {
|
||||
filenames[i] = filename
|
||||
i++
|
||||
}
|
||||
sort.Strings(filenames)
|
||||
|
||||
for _, p := range filenames {
|
||||
ident(w, nident+1)
|
||||
fmt.Fprintf(w, `"%s": `, p)
|
||||
root.Children[p].writeGoMap(w, nident+1)
|
||||
}
|
||||
ident(w, nident)
|
||||
}
|
||||
|
||||
io.WriteString(w, "}}")
|
||||
if nident > 0 {
|
||||
io.WriteString(w, ",")
|
||||
}
|
||||
io.WriteString(w, "\n")
|
||||
}
|
||||
|
||||
func (root *assetTree) WriteAsGoMap(w io.Writer) error {
|
||||
_, err := fmt.Fprint(w, `type bintree struct {
|
||||
Func func() (*asset, error)
|
||||
Children map[string]*bintree
|
||||
}
|
||||
var _bintree = `)
|
||||
root.writeGoMap(w, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
func writeTOCTree(w io.Writer, toc []Asset) error {
|
||||
_, err := fmt.Fprintf(w, `// AssetDir returns the file names below a certain
|
||||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
// AssetDir("") will return []string{"data"}.
|
||||
func AssetDir(name string) ([]string, error) {
|
||||
node := _bintree
|
||||
if len(name) != 0 {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
pathList := strings.Split(cannonicalName, "/")
|
||||
for _, p := range pathList {
|
||||
node = node.Children[p]
|
||||
if node == nil {
|
||||
return nil, fmt.Errorf("Asset %%s not found", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.Func != nil {
|
||||
return nil, fmt.Errorf("Asset %%s not found", name)
|
||||
}
|
||||
rv := make([]string, 0, len(node.Children))
|
||||
for childName := range node.Children {
|
||||
rv = append(rv, childName)
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tree := newAssetTree()
|
||||
for i := range toc {
|
||||
pathList := strings.Split(toc[i].Name, "/")
|
||||
tree.Add(pathList, toc[i])
|
||||
}
|
||||
return tree.WriteAsGoMap(w)
|
||||
}
|
||||
|
||||
// writeTOC writes the table of contents file.
|
||||
func writeTOC(w io.Writer, toc []Asset) error {
|
||||
err := writeTOCHeader(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range toc {
|
||||
err = writeTOCAsset(w, &toc[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return writeTOCFooter(w)
|
||||
}
|
||||
|
||||
// writeTOCHeader writes the table of contents file header.
|
||||
func writeTOCHeader(w io.Writer) error {
|
||||
_, err := fmt.Fprintf(w, `// Asset loads and returns the asset for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func Asset(name string) ([]byte, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Asset %%s can't read by error: %%v", name, err)
|
||||
}
|
||||
return a.bytes, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Asset %%s not found", name)
|
||||
}
|
||||
|
||||
// MustAsset is like Asset but panics when Asset would return an error.
|
||||
// It simplifies safe initialization of global variables.
|
||||
func MustAsset(name string) []byte {
|
||||
a, err := Asset(name)
|
||||
if err != nil {
|
||||
panic("asset: Asset(" + name + "): " + err.Error())
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// AssetInfo loads and returns the asset info for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func AssetInfo(name string) (os.FileInfo, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("AssetInfo %%s can't read by error: %%v", name, err)
|
||||
}
|
||||
return a.info, nil
|
||||
}
|
||||
return nil, fmt.Errorf("AssetInfo %%s not found", name)
|
||||
}
|
||||
|
||||
// AssetNames returns the names of the assets.
|
||||
func AssetNames() []string {
|
||||
names := make([]string, 0, len(_bindata))
|
||||
for name := range _bindata {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() (*asset, error){
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
// writeTOCAsset write a TOC entry for the given asset.
|
||||
func writeTOCAsset(w io.Writer, asset *Asset) error {
|
||||
_, err := fmt.Fprintf(w, "\t%q: %s,\n", asset.Name, asset.Func)
|
||||
return err
|
||||
}
|
||||
|
||||
// writeTOCFooter writes the table of contents file footer.
|
||||
func writeTOCFooter(w io.Writer) error {
|
||||
_, err := fmt.Fprintf(w, `}
|
||||
|
||||
`)
|
||||
return err
|
||||
}
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
Generated
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package versioned
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
clusterv1 "github.com/open-cluster-management/api/client/cluster/clientset/versioned/typed/cluster/v1"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
rest "k8s.io/client-go/rest"
|
||||
flowcontrol "k8s.io/client-go/util/flowcontrol"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
Discovery() discovery.DiscoveryInterface
|
||||
ClusterV1() clusterv1.ClusterV1Interface
|
||||
}
|
||||
|
||||
// Clientset contains the clients for groups. Each group has exactly one
|
||||
// version included in a Clientset.
|
||||
type Clientset struct {
|
||||
*discovery.DiscoveryClient
|
||||
clusterV1 *clusterv1.ClusterV1Client
|
||||
}
|
||||
|
||||
// ClusterV1 retrieves the ClusterV1Client
|
||||
func (c *Clientset) ClusterV1() clusterv1.ClusterV1Interface {
|
||||
return c.clusterV1
|
||||
}
|
||||
|
||||
// Discovery retrieves the DiscoveryClient
|
||||
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.DiscoveryClient
|
||||
}
|
||||
|
||||
// NewForConfig creates a new Clientset for the given config.
|
||||
// If config's RateLimiter is not set and QPS and Burst are acceptable,
|
||||
// NewForConfig will generate a rate-limiter in configShallowCopy.
|
||||
func NewForConfig(c *rest.Config) (*Clientset, error) {
|
||||
configShallowCopy := *c
|
||||
if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
|
||||
if configShallowCopy.Burst <= 0 {
|
||||
return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
|
||||
}
|
||||
configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
|
||||
}
|
||||
var cs Clientset
|
||||
var err error
|
||||
cs.clusterV1, err = clusterv1.NewForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &cs, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new Clientset for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *Clientset {
|
||||
var cs Clientset
|
||||
cs.clusterV1 = clusterv1.NewForConfigOrDie(c)
|
||||
|
||||
cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
|
||||
return &cs
|
||||
}
|
||||
|
||||
// New creates a new Clientset for the given RESTClient.
|
||||
func New(c rest.Interface) *Clientset {
|
||||
var cs Clientset
|
||||
cs.clusterV1 = clusterv1.New(c)
|
||||
|
||||
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
|
||||
return &cs
|
||||
}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated clientset.
|
||||
package versioned
|
||||
Generated
Vendored
+66
@@ -0,0 +1,66 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
clientset "github.com/open-cluster-management/api/client/cluster/clientset/versioned"
|
||||
clusterv1 "github.com/open-cluster-management/api/client/cluster/clientset/versioned/typed/cluster/v1"
|
||||
fakeclusterv1 "github.com/open-cluster-management/api/client/cluster/clientset/versioned/typed/cluster/v1/fake"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/discovery"
|
||||
fakediscovery "k8s.io/client-go/discovery/fake"
|
||||
"k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// NewSimpleClientset returns a clientset that will respond with the provided objects.
|
||||
// It's backed by a very simple object tracker that processes creates, updates and deletions as-is,
|
||||
// without applying any validations and/or defaults. It shouldn't be considered a replacement
|
||||
// for a real clientset and is mostly useful in simple unit tests.
|
||||
func NewSimpleClientset(objects ...runtime.Object) *Clientset {
|
||||
o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
|
||||
for _, obj := range objects {
|
||||
if err := o.Add(obj); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
cs := &Clientset{tracker: o}
|
||||
cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake}
|
||||
cs.AddReactor("*", "*", testing.ObjectReaction(o))
|
||||
cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
|
||||
gvr := action.GetResource()
|
||||
ns := action.GetNamespace()
|
||||
watch, err := o.Watch(gvr, ns)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return true, watch, nil
|
||||
})
|
||||
|
||||
return cs
|
||||
}
|
||||
|
||||
// Clientset implements clientset.Interface. 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 Clientset struct {
|
||||
testing.Fake
|
||||
discovery *fakediscovery.FakeDiscovery
|
||||
tracker testing.ObjectTracker
|
||||
}
|
||||
|
||||
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
||||
return c.discovery
|
||||
}
|
||||
|
||||
func (c *Clientset) Tracker() testing.ObjectTracker {
|
||||
return c.tracker
|
||||
}
|
||||
|
||||
var _ clientset.Interface = &Clientset{}
|
||||
|
||||
// ClusterV1 retrieves the ClusterV1Client
|
||||
func (c *Clientset) ClusterV1() clusterv1.ClusterV1Interface {
|
||||
return &fakeclusterv1.FakeClusterV1{Fake: &c.Fake}
|
||||
}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated fake clientset.
|
||||
package fake
|
||||
Generated
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
clusterv1 "github.com/open-cluster-management/api/cluster/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
)
|
||||
|
||||
var scheme = runtime.NewScheme()
|
||||
var codecs = serializer.NewCodecFactory(scheme)
|
||||
var parameterCodec = runtime.NewParameterCodec(scheme)
|
||||
var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
clusterv1.AddToScheme,
|
||||
}
|
||||
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
// of clientsets, like in:
|
||||
//
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
//
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
//
|
||||
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
|
||||
// correctly.
|
||||
var AddToScheme = localSchemeBuilder.AddToScheme
|
||||
|
||||
func init() {
|
||||
v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
|
||||
utilruntime.Must(AddToScheme(scheme))
|
||||
}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package contains the scheme of the automatically generated clientset.
|
||||
package scheme
|
||||
Generated
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package scheme
|
||||
|
||||
import (
|
||||
clusterv1 "github.com/open-cluster-management/api/cluster/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
)
|
||||
|
||||
var Scheme = runtime.NewScheme()
|
||||
var Codecs = serializer.NewCodecFactory(Scheme)
|
||||
var ParameterCodec = runtime.NewParameterCodec(Scheme)
|
||||
var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
clusterv1.AddToScheme,
|
||||
}
|
||||
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
// of clientsets, like in:
|
||||
//
|
||||
// import (
|
||||
// "k8s.io/client-go/kubernetes"
|
||||
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
|
||||
// )
|
||||
//
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
//
|
||||
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
|
||||
// correctly.
|
||||
var AddToScheme = localSchemeBuilder.AddToScheme
|
||||
|
||||
func init() {
|
||||
v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
|
||||
utilruntime.Must(AddToScheme(Scheme))
|
||||
}
|
||||
Generated
Vendored
+73
@@ -0,0 +1,73 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/open-cluster-management/api/client/cluster/clientset/versioned/scheme"
|
||||
v1 "github.com/open-cluster-management/api/cluster/v1"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type ClusterV1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
SpokeClustersGetter
|
||||
}
|
||||
|
||||
// ClusterV1Client is used to interact with features provided by the cluster.open-cluster-management.io group.
|
||||
type ClusterV1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *ClusterV1Client) SpokeClusters() SpokeClusterInterface {
|
||||
return newSpokeClusters(c)
|
||||
}
|
||||
|
||||
// NewForConfig creates a new ClusterV1Client for the given config.
|
||||
func NewForConfig(c *rest.Config) (*ClusterV1Client, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := rest.RESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ClusterV1Client{client}, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new ClusterV1Client for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *ClusterV1Client {
|
||||
client, err := NewForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
// New creates a new ClusterV1Client for the given RESTClient.
|
||||
func New(c rest.Interface) *ClusterV1Client {
|
||||
return &ClusterV1Client{c}
|
||||
}
|
||||
|
||||
func setConfigDefaults(config *rest.Config) error {
|
||||
gv := v1.SchemeGroupVersion
|
||||
config.GroupVersion = &gv
|
||||
config.APIPath = "/apis"
|
||||
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
|
||||
|
||||
if config.UserAgent == "" {
|
||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *ClusterV1Client) RESTClient() rest.Interface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.restClient
|
||||
}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated typed clients.
|
||||
package v1
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// Package fake has the automatically generated clients.
|
||||
package fake
|
||||
Generated
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1 "github.com/open-cluster-management/api/client/cluster/clientset/versioned/typed/cluster/v1"
|
||||
rest "k8s.io/client-go/rest"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
type FakeClusterV1 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeClusterV1) SpokeClusters() v1.SpokeClusterInterface {
|
||||
return &FakeSpokeClusters{c}
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *FakeClusterV1) RESTClient() rest.Interface {
|
||||
var ret *rest.RESTClient
|
||||
return ret
|
||||
}
|
||||
Generated
Vendored
+117
@@ -0,0 +1,117 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
clusterv1 "github.com/open-cluster-management/api/cluster/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeSpokeClusters implements SpokeClusterInterface
|
||||
type FakeSpokeClusters struct {
|
||||
Fake *FakeClusterV1
|
||||
}
|
||||
|
||||
var spokeclustersResource = schema.GroupVersionResource{Group: "cluster.open-cluster-management.io", Version: "v1", Resource: "spokeclusters"}
|
||||
|
||||
var spokeclustersKind = schema.GroupVersionKind{Group: "cluster.open-cluster-management.io", Version: "v1", Kind: "SpokeCluster"}
|
||||
|
||||
// Get takes name of the spokeCluster, and returns the corresponding spokeCluster object, and an error if there is any.
|
||||
func (c *FakeSpokeClusters) Get(ctx context.Context, name string, options v1.GetOptions) (result *clusterv1.SpokeCluster, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootGetAction(spokeclustersResource, name), &clusterv1.SpokeCluster{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*clusterv1.SpokeCluster), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of SpokeClusters that match those selectors.
|
||||
func (c *FakeSpokeClusters) List(ctx context.Context, opts v1.ListOptions) (result *clusterv1.SpokeClusterList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootListAction(spokeclustersResource, spokeclustersKind, opts), &clusterv1.SpokeClusterList{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &clusterv1.SpokeClusterList{ListMeta: obj.(*clusterv1.SpokeClusterList).ListMeta}
|
||||
for _, item := range obj.(*clusterv1.SpokeClusterList).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 spokeClusters.
|
||||
func (c *FakeSpokeClusters) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewRootWatchAction(spokeclustersResource, opts))
|
||||
}
|
||||
|
||||
// Create takes the representation of a spokeCluster and creates it. Returns the server's representation of the spokeCluster, and an error, if there is any.
|
||||
func (c *FakeSpokeClusters) Create(ctx context.Context, spokeCluster *clusterv1.SpokeCluster, opts v1.CreateOptions) (result *clusterv1.SpokeCluster, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootCreateAction(spokeclustersResource, spokeCluster), &clusterv1.SpokeCluster{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*clusterv1.SpokeCluster), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a spokeCluster and updates it. Returns the server's representation of the spokeCluster, and an error, if there is any.
|
||||
func (c *FakeSpokeClusters) Update(ctx context.Context, spokeCluster *clusterv1.SpokeCluster, opts v1.UpdateOptions) (result *clusterv1.SpokeCluster, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootUpdateAction(spokeclustersResource, spokeCluster), &clusterv1.SpokeCluster{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*clusterv1.SpokeCluster), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeSpokeClusters) UpdateStatus(ctx context.Context, spokeCluster *clusterv1.SpokeCluster, opts v1.UpdateOptions) (*clusterv1.SpokeCluster, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootUpdateSubresourceAction(spokeclustersResource, "status", spokeCluster), &clusterv1.SpokeCluster{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*clusterv1.SpokeCluster), err
|
||||
}
|
||||
|
||||
// Delete takes name of the spokeCluster and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeSpokeClusters) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewRootDeleteAction(spokeclustersResource, name), &clusterv1.SpokeCluster{})
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeSpokeClusters) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
|
||||
action := testing.NewRootDeleteCollectionAction(spokeclustersResource, listOpts)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &clusterv1.SpokeClusterList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched spokeCluster.
|
||||
func (c *FakeSpokeClusters) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *clusterv1.SpokeCluster, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootPatchSubresourceAction(spokeclustersResource, name, pt, data, subresources...), &clusterv1.SpokeCluster{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*clusterv1.SpokeCluster), err
|
||||
}
|
||||
Generated
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
type SpokeClusterExpansion interface{}
|
||||
Generated
Vendored
+168
@@ -0,0 +1,168 @@
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
scheme "github.com/open-cluster-management/api/client/cluster/clientset/versioned/scheme"
|
||||
v1 "github.com/open-cluster-management/api/cluster/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// SpokeClustersGetter has a method to return a SpokeClusterInterface.
|
||||
// A group's client should implement this interface.
|
||||
type SpokeClustersGetter interface {
|
||||
SpokeClusters() SpokeClusterInterface
|
||||
}
|
||||
|
||||
// SpokeClusterInterface has methods to work with SpokeCluster resources.
|
||||
type SpokeClusterInterface interface {
|
||||
Create(ctx context.Context, spokeCluster *v1.SpokeCluster, opts metav1.CreateOptions) (*v1.SpokeCluster, error)
|
||||
Update(ctx context.Context, spokeCluster *v1.SpokeCluster, opts metav1.UpdateOptions) (*v1.SpokeCluster, error)
|
||||
UpdateStatus(ctx context.Context, spokeCluster *v1.SpokeCluster, opts metav1.UpdateOptions) (*v1.SpokeCluster, error)
|
||||
Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
|
||||
DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||
Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.SpokeCluster, error)
|
||||
List(ctx context.Context, opts metav1.ListOptions) (*v1.SpokeClusterList, error)
|
||||
Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
|
||||
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.SpokeCluster, err error)
|
||||
SpokeClusterExpansion
|
||||
}
|
||||
|
||||
// spokeClusters implements SpokeClusterInterface
|
||||
type spokeClusters struct {
|
||||
client rest.Interface
|
||||
}
|
||||
|
||||
// newSpokeClusters returns a SpokeClusters
|
||||
func newSpokeClusters(c *ClusterV1Client) *spokeClusters {
|
||||
return &spokeClusters{
|
||||
client: c.RESTClient(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the spokeCluster, and returns the corresponding spokeCluster object, and an error if there is any.
|
||||
func (c *spokeClusters) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.SpokeCluster, err error) {
|
||||
result = &v1.SpokeCluster{}
|
||||
err = c.client.Get().
|
||||
Resource("spokeclusters").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of SpokeClusters that match those selectors.
|
||||
func (c *spokeClusters) List(ctx context.Context, opts metav1.ListOptions) (result *v1.SpokeClusterList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1.SpokeClusterList{}
|
||||
err = c.client.Get().
|
||||
Resource("spokeclusters").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested spokeClusters.
|
||||
func (c *spokeClusters) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Resource("spokeclusters").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch(ctx)
|
||||
}
|
||||
|
||||
// Create takes the representation of a spokeCluster and creates it. Returns the server's representation of the spokeCluster, and an error, if there is any.
|
||||
func (c *spokeClusters) Create(ctx context.Context, spokeCluster *v1.SpokeCluster, opts metav1.CreateOptions) (result *v1.SpokeCluster, err error) {
|
||||
result = &v1.SpokeCluster{}
|
||||
err = c.client.Post().
|
||||
Resource("spokeclusters").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(spokeCluster).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a spokeCluster and updates it. Returns the server's representation of the spokeCluster, and an error, if there is any.
|
||||
func (c *spokeClusters) Update(ctx context.Context, spokeCluster *v1.SpokeCluster, opts metav1.UpdateOptions) (result *v1.SpokeCluster, err error) {
|
||||
result = &v1.SpokeCluster{}
|
||||
err = c.client.Put().
|
||||
Resource("spokeclusters").
|
||||
Name(spokeCluster.Name).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(spokeCluster).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *spokeClusters) UpdateStatus(ctx context.Context, spokeCluster *v1.SpokeCluster, opts metav1.UpdateOptions) (result *v1.SpokeCluster, err error) {
|
||||
result = &v1.SpokeCluster{}
|
||||
err = c.client.Put().
|
||||
Resource("spokeclusters").
|
||||
Name(spokeCluster.Name).
|
||||
SubResource("status").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(spokeCluster).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the spokeCluster and deletes it. Returns an error if one occurs.
|
||||
func (c *spokeClusters) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Resource("spokeclusters").
|
||||
Name(name).
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *spokeClusters) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOpts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Resource("spokeclusters").
|
||||
VersionedParams(&listOpts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(&opts).
|
||||
Do(ctx).
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched spokeCluster.
|
||||
func (c *spokeClusters) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.SpokeCluster, err error) {
|
||||
result = &v1.SpokeCluster{}
|
||||
err = c.client.Patch(pt).
|
||||
Resource("spokeclusters").
|
||||
Name(name).
|
||||
SubResource(subresources...).
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Body(data).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
Generated
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package cluster
|
||||
|
||||
import (
|
||||
v1 "github.com/open-cluster-management/api/client/cluster/informers/externalversions/cluster/v1"
|
||||
internalinterfaces "github.com/open-cluster-management/api/client/cluster/informers/externalversions/internalinterfaces"
|
||||
)
|
||||
|
||||
// Interface provides access to each of this group's versions.
|
||||
type Interface interface {
|
||||
// V1 provides access to shared informers for resources in V1.
|
||||
V1() v1.Interface
|
||||
}
|
||||
|
||||
type group struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// New returns a new Interface.
|
||||
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
|
||||
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// V1 returns a new v1.Interface.
|
||||
func (g *group) V1() v1.Interface {
|
||||
return v1.New(g.factory, g.namespace, g.tweakListOptions)
|
||||
}
|
||||
Generated
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
internalinterfaces "github.com/open-cluster-management/api/client/cluster/informers/externalversions/internalinterfaces"
|
||||
)
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// SpokeClusters returns a SpokeClusterInformer.
|
||||
SpokeClusters() SpokeClusterInformer
|
||||
}
|
||||
|
||||
type version struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// New returns a new Interface.
|
||||
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
|
||||
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// SpokeClusters returns a SpokeClusterInformer.
|
||||
func (v *version) SpokeClusters() SpokeClusterInformer {
|
||||
return &spokeClusterInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
Generated
Vendored
+73
@@ -0,0 +1,73 @@
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
time "time"
|
||||
|
||||
versioned "github.com/open-cluster-management/api/client/cluster/clientset/versioned"
|
||||
internalinterfaces "github.com/open-cluster-management/api/client/cluster/informers/externalversions/internalinterfaces"
|
||||
v1 "github.com/open-cluster-management/api/client/cluster/listers/cluster/v1"
|
||||
clusterv1 "github.com/open-cluster-management/api/cluster/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// SpokeClusterInformer provides access to a shared informer and lister for
|
||||
// SpokeClusters.
|
||||
type SpokeClusterInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1.SpokeClusterLister
|
||||
}
|
||||
|
||||
type spokeClusterInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// NewSpokeClusterInformer constructs a new informer for SpokeCluster type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewSpokeClusterInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredSpokeClusterInformer(client, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredSpokeClusterInformer constructs a new informer for SpokeCluster type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredSpokeClusterInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.ClusterV1().SpokeClusters().List(context.TODO(), options)
|
||||
},
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.ClusterV1().SpokeClusters().Watch(context.TODO(), options)
|
||||
},
|
||||
},
|
||||
&clusterv1.SpokeCluster{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *spokeClusterInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredSpokeClusterInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *spokeClusterInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&clusterv1.SpokeCluster{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *spokeClusterInformer) Lister() v1.SpokeClusterLister {
|
||||
return v1.NewSpokeClusterLister(f.Informer().GetIndexer())
|
||||
}
|
||||
Generated
Vendored
+164
@@ -0,0 +1,164 @@
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package externalversions
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
time "time"
|
||||
|
||||
versioned "github.com/open-cluster-management/api/client/cluster/clientset/versioned"
|
||||
cluster "github.com/open-cluster-management/api/client/cluster/informers/externalversions/cluster"
|
||||
internalinterfaces "github.com/open-cluster-management/api/client/cluster/informers/externalversions/internalinterfaces"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// SharedInformerOption defines the functional option type for SharedInformerFactory.
|
||||
type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory
|
||||
|
||||
type sharedInformerFactory struct {
|
||||
client versioned.Interface
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
lock sync.Mutex
|
||||
defaultResync time.Duration
|
||||
customResync map[reflect.Type]time.Duration
|
||||
|
||||
informers map[reflect.Type]cache.SharedIndexInformer
|
||||
// startedInformers is used for tracking which informers have been started.
|
||||
// This allows Start() to be called multiple times safely.
|
||||
startedInformers map[reflect.Type]bool
|
||||
}
|
||||
|
||||
// WithCustomResyncConfig sets a custom resync period for the specified informer types.
|
||||
func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption {
|
||||
return func(factory *sharedInformerFactory) *sharedInformerFactory {
|
||||
for k, v := range resyncConfig {
|
||||
factory.customResync[reflect.TypeOf(k)] = v
|
||||
}
|
||||
return factory
|
||||
}
|
||||
}
|
||||
|
||||
// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory.
|
||||
func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption {
|
||||
return func(factory *sharedInformerFactory) *sharedInformerFactory {
|
||||
factory.tweakListOptions = tweakListOptions
|
||||
return factory
|
||||
}
|
||||
}
|
||||
|
||||
// WithNamespace limits the SharedInformerFactory to the specified namespace.
|
||||
func WithNamespace(namespace string) SharedInformerOption {
|
||||
return func(factory *sharedInformerFactory) *sharedInformerFactory {
|
||||
factory.namespace = namespace
|
||||
return factory
|
||||
}
|
||||
}
|
||||
|
||||
// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces.
|
||||
func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory {
|
||||
return NewSharedInformerFactoryWithOptions(client, defaultResync)
|
||||
}
|
||||
|
||||
// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory.
|
||||
// Listers obtained via this SharedInformerFactory will be subject to the same filters
|
||||
// as specified here.
|
||||
// Deprecated: Please use NewSharedInformerFactoryWithOptions instead
|
||||
func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory {
|
||||
return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions))
|
||||
}
|
||||
|
||||
// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options.
|
||||
func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory {
|
||||
factory := &sharedInformerFactory{
|
||||
client: client,
|
||||
namespace: v1.NamespaceAll,
|
||||
defaultResync: defaultResync,
|
||||
informers: make(map[reflect.Type]cache.SharedIndexInformer),
|
||||
startedInformers: make(map[reflect.Type]bool),
|
||||
customResync: make(map[reflect.Type]time.Duration),
|
||||
}
|
||||
|
||||
// Apply all options
|
||||
for _, opt := range options {
|
||||
factory = opt(factory)
|
||||
}
|
||||
|
||||
return factory
|
||||
}
|
||||
|
||||
// Start initializes all requested informers.
|
||||
func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
for informerType, informer := range f.informers {
|
||||
if !f.startedInformers[informerType] {
|
||||
go informer.Run(stopCh)
|
||||
f.startedInformers[informerType] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WaitForCacheSync waits for all started informers' cache were synced.
|
||||
func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool {
|
||||
informers := func() map[reflect.Type]cache.SharedIndexInformer {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
informers := map[reflect.Type]cache.SharedIndexInformer{}
|
||||
for informerType, informer := range f.informers {
|
||||
if f.startedInformers[informerType] {
|
||||
informers[informerType] = informer
|
||||
}
|
||||
}
|
||||
return informers
|
||||
}()
|
||||
|
||||
res := map[reflect.Type]bool{}
|
||||
for informType, informer := range informers {
|
||||
res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// InternalInformerFor returns the SharedIndexInformer for obj using an internal
|
||||
// client.
|
||||
func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
informerType := reflect.TypeOf(obj)
|
||||
informer, exists := f.informers[informerType]
|
||||
if exists {
|
||||
return informer
|
||||
}
|
||||
|
||||
resyncPeriod, exists := f.customResync[informerType]
|
||||
if !exists {
|
||||
resyncPeriod = f.defaultResync
|
||||
}
|
||||
|
||||
informer = newFunc(f.client, resyncPeriod)
|
||||
f.informers[informerType] = informer
|
||||
|
||||
return informer
|
||||
}
|
||||
|
||||
// SharedInformerFactory provides shared informers for resources in all known
|
||||
// API group versions.
|
||||
type SharedInformerFactory interface {
|
||||
internalinterfaces.SharedInformerFactory
|
||||
ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
|
||||
WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
|
||||
|
||||
Cluster() cluster.Interface
|
||||
}
|
||||
|
||||
func (f *sharedInformerFactory) Cluster() cluster.Interface {
|
||||
return cluster.New(f, f.namespace, f.tweakListOptions)
|
||||
}
|
||||
Generated
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package externalversions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
v1 "github.com/open-cluster-management/api/cluster/v1"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// GenericInformer is type of SharedIndexInformer which will locate and delegate to other
|
||||
// sharedInformers based on type
|
||||
type GenericInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() cache.GenericLister
|
||||
}
|
||||
|
||||
type genericInformer struct {
|
||||
informer cache.SharedIndexInformer
|
||||
resource schema.GroupResource
|
||||
}
|
||||
|
||||
// Informer returns the SharedIndexInformer.
|
||||
func (f *genericInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.informer
|
||||
}
|
||||
|
||||
// Lister returns the GenericLister.
|
||||
func (f *genericInformer) Lister() cache.GenericLister {
|
||||
return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource)
|
||||
}
|
||||
|
||||
// ForResource gives generic access to a shared informer of the matching type
|
||||
// TODO extend this to unknown resources with a client pool
|
||||
func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
|
||||
switch resource {
|
||||
// Group=cluster.open-cluster-management.io, Version=v1
|
||||
case v1.SchemeGroupVersion.WithResource("spokeclusters"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Cluster().V1().SpokeClusters().Informer()}, nil
|
||||
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no informer found for %v", resource)
|
||||
}
|
||||
Generated
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package internalinterfaces
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
versioned "github.com/open-cluster-management/api/client/cluster/clientset/versioned"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer.
|
||||
type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer
|
||||
|
||||
// SharedInformerFactory a small interface to allow for adding an informer without an import cycle
|
||||
type SharedInformerFactory interface {
|
||||
Start(stopCh <-chan struct{})
|
||||
InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer
|
||||
}
|
||||
|
||||
// TweakListOptionsFunc is a function that transforms a v1.ListOptions.
|
||||
type TweakListOptionsFunc func(*v1.ListOptions)
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
// SpokeClusterListerExpansion allows custom methods to be added to
|
||||
// SpokeClusterLister.
|
||||
type SpokeClusterListerExpansion interface{}
|
||||
Generated
Vendored
+49
@@ -0,0 +1,49 @@
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "github.com/open-cluster-management/api/cluster/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// SpokeClusterLister helps list SpokeClusters.
|
||||
type SpokeClusterLister interface {
|
||||
// List lists all SpokeClusters in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1.SpokeCluster, err error)
|
||||
// Get retrieves the SpokeCluster from the index for a given name.
|
||||
Get(name string) (*v1.SpokeCluster, error)
|
||||
SpokeClusterListerExpansion
|
||||
}
|
||||
|
||||
// spokeClusterLister implements the SpokeClusterLister interface.
|
||||
type spokeClusterLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewSpokeClusterLister returns a new SpokeClusterLister.
|
||||
func NewSpokeClusterLister(indexer cache.Indexer) SpokeClusterLister {
|
||||
return &spokeClusterLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all SpokeClusters in the indexer.
|
||||
func (s *spokeClusterLister) List(selector labels.Selector) (ret []*v1.SpokeCluster, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1.SpokeCluster))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the SpokeCluster from the index for a given name.
|
||||
func (s *spokeClusterLister) Get(name string) (*v1.SpokeCluster, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1.Resource("spokecluster"), name)
|
||||
}
|
||||
return obj.(*v1.SpokeCluster), nil
|
||||
}
|
||||
Generated
Vendored
+130
@@ -0,0 +1,130 @@
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: spokeclusters.cluster.open-cluster-management.io
|
||||
spec:
|
||||
group: cluster.open-cluster-management.io
|
||||
names:
|
||||
kind: SpokeCluster
|
||||
listKind: SpokeClusterList
|
||||
plural: spokeclusters
|
||||
singular: spokecluster
|
||||
scope: "Cluster"
|
||||
preserveUnknownFields: false
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
description: 'SpokeCluster represents the current status of spoke cluster. SpokeCluster
|
||||
is cluster scoped resources. The name is the cluster UID. The cluster join
|
||||
follows the double opt-in proceess: 1. agent on spoke cluster creates CSR
|
||||
on hub with cluster UID and agent name. 2. agent on spoke cluster creates
|
||||
spokecluster on hub. 3. cluster admin on hub approves the CSR for the spoke''s
|
||||
cluster UID and agent name. 4. cluster admin set spec.acceptSpokeCluster of
|
||||
spokecluster to true. 5. cluster admin on spoke creates credential of kubeconfig
|
||||
to spoke. Once hub creates the cluster namespace, the spoke agent pushes the
|
||||
credential to hub to use against spoke''s kube-apiserver'
|
||||
type: object
|
||||
properties:
|
||||
apiVersion:
|
||||
description: '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: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: '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: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec represents a desired configuration for the agent on the
|
||||
spoke cluster.
|
||||
type: object
|
||||
properties:
|
||||
hubAcceptsClient:
|
||||
description: AcceptSpokeCluster reprsents that hub accepts the join
|
||||
of spoke agent. Its default value is false, and can only be set true
|
||||
when the user on hub has an RBAC rule to UPDATE on the virtual subresource
|
||||
of spokeclusters/accept. When the vaule is set true, a namespace whose
|
||||
name is same as the name of SpokeCluster is created on hub representing
|
||||
the spoke cluster, also role/rolebinding is created on the namespace
|
||||
to grant the permision of access from agent on spoke. When the value
|
||||
is set false, the namespace representing the spoke cluster is deleted.
|
||||
type: boolean
|
||||
spokeClientConfig:
|
||||
description: SpokeClientConfig represents the apiserver address of the
|
||||
spoke cluster
|
||||
type: object
|
||||
properties:
|
||||
caBundle:
|
||||
description: CABundle is the ca bundle to connect to apiserver of
|
||||
the spoke cluster. System certs is used if it is not set.
|
||||
type: string
|
||||
format: byte
|
||||
url:
|
||||
description: URL is the url of apiserver endpoint of the spoke cluster
|
||||
type: string
|
||||
status:
|
||||
description: Status represents the current status of joined spoke cluster
|
||||
type: object
|
||||
properties:
|
||||
allocatable:
|
||||
description: Allocatable represents the total allocatable resources
|
||||
on the spoke cluster
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: string
|
||||
capacity:
|
||||
description: Capacity represents the total resource capacity from all
|
||||
nodeStatuses on the spoke cluster
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: string
|
||||
conditions:
|
||||
description: Conditions contains the different condition statuses for
|
||||
this spoke cluster.
|
||||
type: array
|
||||
items:
|
||||
description: StatusCondition contains condition information for a
|
||||
spoke cluster.
|
||||
type: object
|
||||
properties:
|
||||
lastTransitionTime:
|
||||
description: LastTransitionTime is the last time the condition
|
||||
changed from one status to another.
|
||||
type: string
|
||||
format: date-time
|
||||
message:
|
||||
description: Message is a human-readable message indicating details
|
||||
about the last status change.
|
||||
type: string
|
||||
reason:
|
||||
description: Reason is a (brief) reason for the condition's last
|
||||
status change.
|
||||
type: string
|
||||
status:
|
||||
description: Status is the status of the condition. One of True,
|
||||
False, Unknown.
|
||||
type: string
|
||||
type:
|
||||
description: Type is the type of the cluster condition.
|
||||
type: string
|
||||
version:
|
||||
description: Version represents the kubernetes version of the spoke
|
||||
cluster
|
||||
type: object
|
||||
properties:
|
||||
kubernetes:
|
||||
description: Kubernetes is the kubernetes version of spoke cluster
|
||||
type: string
|
||||
version: v1
|
||||
versions:
|
||||
- name: v1
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// Package v1 contains API Schema definitions for the operators v1 API group
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
// +k8s:conversion-gen=github.com/open-cluster-management/api/cluster
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +k8s:openapi-gen=true
|
||||
|
||||
// +kubebuilder:validation:Optional
|
||||
// +groupName=cluster.open-cluster-management.io
|
||||
package v1
|
||||
+2187
File diff suppressed because it is too large
Load Diff
+125
@@ -0,0 +1,125 @@
|
||||
|
||||
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
|
||||
|
||||
syntax = 'proto2';
|
||||
|
||||
package github.com.open_cluster_management.api.cluster.v1;
|
||||
|
||||
import "k8s.io/apimachinery/pkg/api/resource/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
|
||||
|
||||
// Package-wide variables from generator "generated".
|
||||
option go_package = "v1";
|
||||
|
||||
// ClientConfig represents apiserver address of the spoke cluster
|
||||
// TODO include credential to connect to spoke cluster kube-apiserver
|
||||
message ClientConfig {
|
||||
// URL is the url of apiserver endpoint of the spoke cluster
|
||||
// +required
|
||||
optional string url = 1;
|
||||
|
||||
// CABundle is the ca bundle to connect to apiserver of the spoke cluster.
|
||||
// System certs is used if it is not set.
|
||||
// +optional
|
||||
optional bytes caBundle = 2;
|
||||
}
|
||||
|
||||
// SpokeCluster represents the current status of spoke cluster.
|
||||
// SpokeCluster is cluster scoped resources. The name is the cluster UID.
|
||||
// The cluster join follows the double opt-in proceess:
|
||||
// 1. agent on spoke cluster creates CSR on hub with cluster UID and agent name.
|
||||
// 2. agent on spoke cluster creates spokecluster on hub.
|
||||
// 3. cluster admin on hub approves the CSR for the spoke's cluster UID and agent name.
|
||||
// 4. cluster admin set spec.acceptSpokeCluster of spokecluster to true.
|
||||
// 5. cluster admin on spoke creates credential of kubeconfig to spoke. Once hub creates the
|
||||
// cluster namespace, the spoke agent pushes the credential to hub to use against spoke's
|
||||
// kube-apiserver
|
||||
message SpokeCluster {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||
|
||||
// Spec represents a desired configuration for the agent on the spoke cluster.
|
||||
optional SpokeClusterSpec spec = 2;
|
||||
|
||||
// Status represents the current status of joined spoke cluster
|
||||
// +optional
|
||||
optional SpokeClusterStatus status = 3;
|
||||
}
|
||||
|
||||
// SpokeClusterList is a collection of spoke cluster
|
||||
message SpokeClusterList {
|
||||
// Standard list metadata.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
|
||||
// +optional
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1;
|
||||
|
||||
// Items is a list of spoke cluster.
|
||||
repeated SpokeCluster items = 2;
|
||||
}
|
||||
|
||||
// SpokeClusterSpec provides the information to securely connect to a remote server
|
||||
// and verify its identity
|
||||
message SpokeClusterSpec {
|
||||
// SpokeClientConfig represents the apiserver address of the spoke cluster
|
||||
// +optional
|
||||
optional ClientConfig spokeClientConfig = 1;
|
||||
|
||||
// AcceptSpokeCluster reprsents that hub accepts the join of spoke agent.
|
||||
// Its default value is false, and can only be set true when the user on hub
|
||||
// has an RBAC rule to UPDATE on the virtual subresource of spokeclusters/accept.
|
||||
// When the vaule is set true, a namespace whose name is same as the name of SpokeCluster
|
||||
// is created on hub representing the spoke cluster, also role/rolebinding is created on
|
||||
// the namespace to grant the permision of access from agent on spoke.
|
||||
// When the value is set false, the namespace representing the spoke cluster is
|
||||
// deleted.
|
||||
// +required
|
||||
optional bool hubAcceptsClient = 2;
|
||||
}
|
||||
|
||||
// SpokeClusterStatus represents the current status of joined spoke cluster
|
||||
message SpokeClusterStatus {
|
||||
// Conditions contains the different condition statuses for this spoke cluster.
|
||||
repeated StatusCondition conditions = 1;
|
||||
|
||||
// Capacity represents the total resource capacity from all nodeStatuses
|
||||
// on the spoke cluster
|
||||
map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> capacity = 2;
|
||||
|
||||
// Allocatable represents the total allocatable resources on the spoke cluster
|
||||
map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> allocatable = 3;
|
||||
|
||||
// Version represents the kubernetes version of the spoke cluster
|
||||
optional SpokeVersion version = 4;
|
||||
}
|
||||
|
||||
// SpokeVersion represents the Kubernetes version of spoke cluster
|
||||
// TODO add spoke agent versions
|
||||
message SpokeVersion {
|
||||
// Kubernetes is the kubernetes version of spoke cluster
|
||||
// +optional
|
||||
optional string kubernetes = 1;
|
||||
}
|
||||
|
||||
// StatusCondition contains condition information for a spoke cluster.
|
||||
message StatusCondition {
|
||||
// Type is the type of the cluster condition.
|
||||
// +required
|
||||
optional string type = 1;
|
||||
|
||||
// Status is the status of the condition. One of True, False, Unknown.
|
||||
// +required
|
||||
optional string status = 2;
|
||||
|
||||
// LastTransitionTime is the last time the condition changed from one status to another.
|
||||
// +required
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3;
|
||||
|
||||
// Reason is a (brief) reason for the condition's last status change.
|
||||
// +required
|
||||
optional string reason = 4;
|
||||
|
||||
// Message is a human-readable message indicating details about the last status change.
|
||||
// +required
|
||||
optional string message = 5;
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
GroupName = "cluster.open-cluster-management.io"
|
||||
GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
|
||||
schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||
// Install is a function which adds this version to a scheme
|
||||
Install = schemeBuilder.AddToScheme
|
||||
|
||||
// SchemeGroupVersion generated code relies on this name
|
||||
// Deprecated
|
||||
SchemeGroupVersion = GroupVersion
|
||||
// AddToScheme exists solely to keep the old generators creating valid code
|
||||
// DEPRECATED
|
||||
AddToScheme = schemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// Resource generated code relies on this being here, but it logically belongs to the group
|
||||
// DEPRECATED
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return schema.GroupResource{Group: GroupName, Resource: resource}
|
||||
}
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(GroupVersion,
|
||||
&SpokeCluster{},
|
||||
&SpokeClusterList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, GroupVersion)
|
||||
return nil
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// +genclient
|
||||
// +genclient:nonNamespaced
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// SpokeCluster represents the current status of spoke cluster.
|
||||
// SpokeCluster is cluster scoped resources. The name is the cluster UID.
|
||||
// The cluster join follows the double opt-in proceess:
|
||||
// 1. agent on spoke cluster creates CSR on hub with cluster UID and agent name.
|
||||
// 2. agent on spoke cluster creates spokecluster on hub.
|
||||
// 3. cluster admin on hub approves the CSR for the spoke's cluster UID and agent name.
|
||||
// 4. cluster admin set spec.acceptSpokeCluster of spokecluster to true.
|
||||
// 5. cluster admin on spoke creates credential of kubeconfig to spoke. Once hub creates the
|
||||
// cluster namespace, the spoke agent pushes the credential to hub to use against spoke's
|
||||
// kube-apiserver
|
||||
type SpokeCluster struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Spec represents a desired configuration for the agent on the spoke cluster.
|
||||
Spec SpokeClusterSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
|
||||
|
||||
// Status represents the current status of joined spoke cluster
|
||||
// +optional
|
||||
Status SpokeClusterStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
}
|
||||
|
||||
// SpokeClusterSpec provides the information to securely connect to a remote server
|
||||
// and verify its identity
|
||||
type SpokeClusterSpec struct {
|
||||
// SpokeClientConfig represents the apiserver address of the spoke cluster
|
||||
// +optional
|
||||
SpokeClientConfig ClientConfig `json:"spokeClientConfig,omitempty" protobuf:"bytes,1,opt,name=spokeClientConfig"`
|
||||
|
||||
// AcceptSpokeCluster reprsents that hub accepts the join of spoke agent.
|
||||
// Its default value is false, and can only be set true when the user on hub
|
||||
// has an RBAC rule to UPDATE on the virtual subresource of spokeclusters/accept.
|
||||
// When the vaule is set true, a namespace whose name is same as the name of SpokeCluster
|
||||
// is created on hub representing the spoke cluster, also role/rolebinding is created on
|
||||
// the namespace to grant the permision of access from agent on spoke.
|
||||
// When the value is set false, the namespace representing the spoke cluster is
|
||||
// deleted.
|
||||
// +required
|
||||
HubAcceptsClient bool `json:"hubAcceptsClient" protobuf:"bytes,2,opt,name=hubAcceptsClient"`
|
||||
}
|
||||
|
||||
// ClientConfig represents apiserver address of the spoke cluster
|
||||
// TODO include credential to connect to spoke cluster kube-apiserver
|
||||
type ClientConfig struct {
|
||||
// URL is the url of apiserver endpoint of the spoke cluster
|
||||
// +required
|
||||
URL string `json:"url" protobuf:"bytes,1,opt,name=url"`
|
||||
|
||||
// CABundle is the ca bundle to connect to apiserver of the spoke cluster.
|
||||
// System certs is used if it is not set.
|
||||
// +optional
|
||||
CABundle []byte `json:"caBundle,omitempty" protobuf:"bytes,2,opt,name=caBundle"`
|
||||
}
|
||||
|
||||
// SpokeClusterStatus represents the current status of joined spoke cluster
|
||||
type SpokeClusterStatus struct {
|
||||
// Conditions contains the different condition statuses for this spoke cluster.
|
||||
Conditions []StatusCondition `json:"conditions" protobuf:"bytes,1,rep,name=conditions"`
|
||||
|
||||
// Capacity represents the total resource capacity from all nodeStatuses
|
||||
// on the spoke cluster
|
||||
Capacity ResourceList `json:"capacity,omitempty" protobuf:"bytes,2,rep,name=capacity,casttype=ResourceList,castkey=ResourceName"`
|
||||
|
||||
// Allocatable represents the total allocatable resources on the spoke cluster
|
||||
Allocatable ResourceList `json:"allocatable,omitempty" protobuf:"bytes,3,rep,name=allocatable,casttype=ResourceList,castkey=ResourceName"`
|
||||
|
||||
// Version represents the kubernetes version of the spoke cluster
|
||||
Version SpokeVersion `json:"version,omitempty" protobuf:"bytes,4,opt,name=version"`
|
||||
}
|
||||
|
||||
// SpokeVersion represents the Kubernetes version of spoke cluster
|
||||
// TODO add spoke agent versions
|
||||
type SpokeVersion struct {
|
||||
// Kubernetes is the kubernetes version of spoke cluster
|
||||
// +optional
|
||||
Kubernetes string `json:"kubernetes,omitempty" protobuf:"bytes,1,opt,name=kubernetes"`
|
||||
}
|
||||
|
||||
const (
|
||||
// SpokeClusterConditionJoined means the spoke cluster has successfully joined the hub
|
||||
SpokeClusterConditionJoined string = "SpokeClusterJoined"
|
||||
// SpokeClusterConditionHubAccepted means the request to join the cluster is
|
||||
// approved by cluster-admin on hub
|
||||
SpokeClusterConditionHubAccepted string = "HubAcceptedSpoke"
|
||||
// SpokeClusterConditionHubDenied means the request to join the cluster is denied by
|
||||
// cluster-admin on hub
|
||||
SpokeClusterConditionHubDenied string = "HubDeniedSpoke"
|
||||
)
|
||||
|
||||
// ResourceName is the name identifying various resources in a ResourceList.
|
||||
type ResourceName string
|
||||
|
||||
const (
|
||||
// CPU, in cores. (500m = .5 cores)
|
||||
ResourceCPU ResourceName = "cpu"
|
||||
// Memory, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
|
||||
ResourceMemory ResourceName = "memory"
|
||||
)
|
||||
|
||||
// ResourceList defines a map for the quantity of different resources, the definition
|
||||
// matches the ResourceList defined in k8s.io/api/core/v1
|
||||
type ResourceList map[ResourceName]resource.Quantity
|
||||
|
||||
// StatusCondition contains condition information for a spoke cluster.
|
||||
type StatusCondition struct {
|
||||
// Type is the type of the cluster condition.
|
||||
// +required
|
||||
Type string `json:"type" protobuf:"bytes,1,opt,name=type"`
|
||||
|
||||
// Status is the status of the condition. One of True, False, Unknown.
|
||||
// +required
|
||||
Status metav1.ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=k8s.io/apimachinery/pkg/apis/meta/v1.ConditionStatus"`
|
||||
|
||||
// LastTransitionTime is the last time the condition changed from one status to another.
|
||||
// +required
|
||||
LastTransitionTime metav1.Time `json:"lastTransitionTime" protobuf:"bytes,3,opt,name=lastTransitionTime"`
|
||||
|
||||
// Reason is a (brief) reason for the condition's last status change.
|
||||
// +required
|
||||
Reason string `json:"reason" protobuf:"bytes,4,opt,name=reason"`
|
||||
|
||||
// Message is a human-readable message indicating details about the last status change.
|
||||
// +required
|
||||
Message string `json:"message" protobuf:"bytes,5,opt,name=message"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// SpokeClusterList is a collection of spoke cluster
|
||||
type SpokeClusterList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// Standard list metadata.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
|
||||
// +optional
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Items is a list of spoke cluster.
|
||||
Items []SpokeCluster `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
Generated
Vendored
+201
@@ -0,0 +1,201 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClientConfig) DeepCopyInto(out *ClientConfig) {
|
||||
*out = *in
|
||||
if in.CABundle != nil {
|
||||
in, out := &in.CABundle, &out.CABundle
|
||||
*out = make([]byte, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientConfig.
|
||||
func (in *ClientConfig) DeepCopy() *ClientConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClientConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in ResourceList) DeepCopyInto(out *ResourceList) {
|
||||
{
|
||||
in := &in
|
||||
*out = make(ResourceList, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val.DeepCopy()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceList.
|
||||
func (in ResourceList) DeepCopy() ResourceList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ResourceList)
|
||||
in.DeepCopyInto(out)
|
||||
return *out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SpokeCluster) DeepCopyInto(out *SpokeCluster) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SpokeCluster.
|
||||
func (in *SpokeCluster) DeepCopy() *SpokeCluster {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SpokeCluster)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *SpokeCluster) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SpokeClusterList) DeepCopyInto(out *SpokeClusterList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]SpokeCluster, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SpokeClusterList.
|
||||
func (in *SpokeClusterList) DeepCopy() *SpokeClusterList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SpokeClusterList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *SpokeClusterList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SpokeClusterSpec) DeepCopyInto(out *SpokeClusterSpec) {
|
||||
*out = *in
|
||||
in.SpokeClientConfig.DeepCopyInto(&out.SpokeClientConfig)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SpokeClusterSpec.
|
||||
func (in *SpokeClusterSpec) DeepCopy() *SpokeClusterSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SpokeClusterSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SpokeClusterStatus) DeepCopyInto(out *SpokeClusterStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]StatusCondition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Capacity != nil {
|
||||
in, out := &in.Capacity, &out.Capacity
|
||||
*out = make(ResourceList, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val.DeepCopy()
|
||||
}
|
||||
}
|
||||
if in.Allocatable != nil {
|
||||
in, out := &in.Allocatable, &out.Allocatable
|
||||
*out = make(ResourceList, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val.DeepCopy()
|
||||
}
|
||||
}
|
||||
out.Version = in.Version
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SpokeClusterStatus.
|
||||
func (in *SpokeClusterStatus) DeepCopy() *SpokeClusterStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SpokeClusterStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SpokeVersion) DeepCopyInto(out *SpokeVersion) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SpokeVersion.
|
||||
func (in *SpokeVersion) DeepCopy() *SpokeVersion {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SpokeVersion)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StatusCondition) DeepCopyInto(out *StatusCondition) {
|
||||
*out = *in
|
||||
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatusCondition.
|
||||
func (in *StatusCondition) DeepCopy() *StatusCondition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(StatusCondition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
Generated
Vendored
+88
@@ -0,0 +1,88 @@
|
||||
package v1
|
||||
|
||||
// This file contains a collection of methods that can be used from go-restful to
|
||||
// generate Swagger API documentation for its models. Please read this PR for more
|
||||
// information on the implementation: https://github.com/emicklei/go-restful/pull/215
|
||||
//
|
||||
// TODOs are ignored from the parser (e.g. TODO(andronat):... || TODO:...) if and only if
|
||||
// they are on one line! For multiple line or blocks that you want to ignore use ---.
|
||||
// Any context after a --- is ignored.
|
||||
//
|
||||
// Those methods can be generated by using hack/update-swagger-docs.sh
|
||||
|
||||
// AUTO-GENERATED FUNCTIONS START HERE
|
||||
var map_ClientConfig = map[string]string{
|
||||
"": "ClientConfig represents apiserver address of the spoke cluster",
|
||||
"url": "URL is the url of apiserver endpoint of the spoke cluster",
|
||||
"caBundle": "CABundle is the ca bundle to connect to apiserver of the spoke cluster. System certs is used if it is not set.",
|
||||
}
|
||||
|
||||
func (ClientConfig) SwaggerDoc() map[string]string {
|
||||
return map_ClientConfig
|
||||
}
|
||||
|
||||
var map_SpokeCluster = map[string]string{
|
||||
"": "SpokeCluster represents the current status of spoke cluster. SpokeCluster is cluster scoped resources. The name is the cluster UID. The cluster join follows the double opt-in proceess: 1. agent on spoke cluster creates CSR on hub with cluster UID and agent name. 2. agent on spoke cluster creates spokecluster on hub. 3. cluster admin on hub approves the CSR for the spoke's cluster UID and agent name. 4. cluster admin set spec.acceptSpokeCluster of spokecluster to true. 5. cluster admin on spoke creates credential of kubeconfig to spoke. Once hub creates the cluster namespace, the spoke agent pushes the credential to hub to use against spoke's kube-apiserver",
|
||||
"spec": "Spec represents a desired configuration for the agent on the spoke cluster.",
|
||||
"status": "Status represents the current status of joined spoke cluster",
|
||||
}
|
||||
|
||||
func (SpokeCluster) SwaggerDoc() map[string]string {
|
||||
return map_SpokeCluster
|
||||
}
|
||||
|
||||
var map_SpokeClusterList = map[string]string{
|
||||
"": "SpokeClusterList is a collection of spoke cluster",
|
||||
"metadata": "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
|
||||
"items": "Items is a list of spoke cluster.",
|
||||
}
|
||||
|
||||
func (SpokeClusterList) SwaggerDoc() map[string]string {
|
||||
return map_SpokeClusterList
|
||||
}
|
||||
|
||||
var map_SpokeClusterSpec = map[string]string{
|
||||
"": "SpokeClusterSpec provides the information to securely connect to a remote server and verify its identity",
|
||||
"spokeClientConfig": "SpokeClientConfig represents the apiserver address of the spoke cluster",
|
||||
"hubAcceptsClient": "AcceptSpokeCluster reprsents that hub accepts the join of spoke agent. Its default value is false, and can only be set true when the user on hub has an RBAC rule to UPDATE on the virtual subresource of spokeclusters/accept. When the vaule is set true, a namespace whose name is same as the name of SpokeCluster is created on hub representing the spoke cluster, also role/rolebinding is created on the namespace to grant the permision of access from agent on spoke. When the value is set false, the namespace representing the spoke cluster is deleted.",
|
||||
}
|
||||
|
||||
func (SpokeClusterSpec) SwaggerDoc() map[string]string {
|
||||
return map_SpokeClusterSpec
|
||||
}
|
||||
|
||||
var map_SpokeClusterStatus = map[string]string{
|
||||
"": "SpokeClusterStatus represents the current status of joined spoke cluster",
|
||||
"conditions": "Conditions contains the different condition statuses for this spoke cluster.",
|
||||
"capacity": "Capacity represents the total resource capacity from all nodeStatuses on the spoke cluster",
|
||||
"allocatable": "Allocatable represents the total allocatable resources on the spoke cluster",
|
||||
"version": "Version represents the kubernetes version of the spoke cluster",
|
||||
}
|
||||
|
||||
func (SpokeClusterStatus) SwaggerDoc() map[string]string {
|
||||
return map_SpokeClusterStatus
|
||||
}
|
||||
|
||||
var map_SpokeVersion = map[string]string{
|
||||
"": "SpokeVersion represents the Kubernetes version of spoke cluster",
|
||||
"kubernetes": "Kubernetes is the kubernetes version of spoke cluster",
|
||||
}
|
||||
|
||||
func (SpokeVersion) SwaggerDoc() map[string]string {
|
||||
return map_SpokeVersion
|
||||
}
|
||||
|
||||
var map_StatusCondition = map[string]string{
|
||||
"": "StatusCondition contains condition information for a spoke cluster.",
|
||||
"type": "Type is the type of the cluster condition.",
|
||||
"status": "Status is the status of the condition. One of True, False, Unknown.",
|
||||
"lastTransitionTime": "LastTransitionTime is the last time the condition changed from one status to another.",
|
||||
"reason": "Reason is a (brief) reason for the condition's last status change.",
|
||||
"message": "Message is a human-readable message indicating details about the last status change.",
|
||||
}
|
||||
|
||||
func (StatusCondition) SwaggerDoc() map[string]string {
|
||||
return map_StatusCondition
|
||||
}
|
||||
|
||||
// AUTO-GENERATED FUNCTIONS END HERE
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
# Set unix LF EOL for shell scripts
|
||||
*.sh text eol=lf
|
||||
|
||||
**/zz_generated.*.go linguist-generated=true
|
||||
**/types.generated.go linguist-generated=true
|
||||
**/generated.pb.go linguist-generated=true
|
||||
**/generated.proto linguist-generated=true
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
# Binaries for programs and plugins
|
||||
genswaggertypedocs
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
.idea/
|
||||
_output/
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
FROM fedora:31
|
||||
|
||||
ENV GOPATH=/go
|
||||
ENV PATH=/go/bin:$PATH
|
||||
|
||||
RUN dnf -y install make git unzip golang wget
|
||||
RUN go get -u -v golang.org/x/tools/cmd/...
|
||||
RUN wget https://github.com/google/protobuf/releases/download/v3.0.2/protoc-3.0.2-linux-x86_64.zip && \
|
||||
mkdir protoc && \
|
||||
unzip protoc-3.0.2-linux-x86_64.zip -d protoc/ && \
|
||||
mv protoc/bin/protoc /usr/bin && \
|
||||
rm -rf protoc
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
all: build
|
||||
.PHONY: all
|
||||
|
||||
# Include the library makefile
|
||||
include $(addprefix ./vendor/github.com/openshift/build-machinery-go/make/, \
|
||||
golang.mk \
|
||||
targets/openshift/deps.mk \
|
||||
targets/openshift/crd-schema-gen.mk \
|
||||
)
|
||||
|
||||
GO_PACKAGES :=$(addsuffix ...,$(addprefix ./,$(filter-out vendor/,$(filter-out hack/,$(wildcard */)))))
|
||||
GO_BUILD_PACKAGES :=$(GO_PACKAGES)
|
||||
GO_BUILD_PACKAGES_EXPANDED :=$(GO_BUILD_PACKAGES)
|
||||
# LDFLAGS are not needed for dummy builds (saving time on calling git commands)
|
||||
GO_LD_FLAGS:=
|
||||
|
||||
# $1 - target name
|
||||
# $2 - apis
|
||||
# $3 - manifests
|
||||
# $4 - output
|
||||
$(call add-crd-gen,authorization,./authorization/v1,./authorization/v1,./authorization/v1)
|
||||
$(call add-crd-gen,config,./config/v1,./config/v1,./config/v1)
|
||||
$(call add-crd-gen,console,./console/v1,./console/v1,./console/v1)
|
||||
$(call add-crd-gen,imageregistry,./imageregistry/v1,./imageregistry/v1,./imageregistry/v1)
|
||||
$(call add-crd-gen,operator,./operator/v1,./operator/v1,./operator/v1)
|
||||
$(call add-crd-gen,operator-alpha,./operator/v1alpha1,./operator/v1alpha1,./operator/v1alpha1)
|
||||
$(call add-crd-gen,operatoringress,./operatoringress/v1,./operatoringress/v1,./operatoringress/v1)
|
||||
$(call add-crd-gen,quota,./quota/v1,./quota/v1,./quota/v1)
|
||||
$(call add-crd-gen,samples,./samples/v1,./samples/v1,./samples/v1)
|
||||
$(call add-crd-gen,security,./security/v1,./security/v1,./security/v1)
|
||||
$(call add-crd-gen,network,./network/v1,./network/v1,./network/v1)
|
||||
|
||||
RUNTIME ?= podman
|
||||
RUNTIME_IMAGE_NAME ?= openshift-api-generator
|
||||
|
||||
verify-scripts:
|
||||
bash -x hack/verify-deepcopy.sh
|
||||
bash -x hack/verify-protobuf.sh
|
||||
bash -x hack/verify-swagger-docs.sh
|
||||
bash -x hack/verify-crds.sh
|
||||
.PHONY: verify-scripts
|
||||
verify: verify-scripts verify-codegen-crds
|
||||
|
||||
update-scripts:
|
||||
hack/update-deepcopy.sh
|
||||
hack/update-protobuf.sh
|
||||
hack/update-swagger-docs.sh
|
||||
.PHONY: update-scripts
|
||||
update: update-scripts update-codegen-crds
|
||||
|
||||
generate-with-container: Dockerfile.build
|
||||
$(RUNTIME) build -t $(RUNTIME_IMAGE_NAME) -f Dockerfile.build .
|
||||
$(RUNTIME) run -ti --rm -v $(PWD):/go/src/github.com/openshift/api:z -w /go/src/github.com/openshift/api $(RUNTIME_IMAGE_NAME) make update-scripts
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
reviewers:
|
||||
- adambkaplan
|
||||
- abhinavdahiya
|
||||
approvers:
|
||||
- smarterclayton
|
||||
- deads2k
|
||||
- derekwaynecarr
|
||||
- eparis
|
||||
- jwforres
|
||||
- knobunc
|
||||
- sjenning
|
||||
- mfojtik
|
||||
- soltysh
|
||||
- sttts
|
||||
- bparees
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
# api
|
||||
The canonical location of the OpenShift API definition. This repo holds the API type definitions and serialization code used by [openshift/client-go](https://github.com/openshift/client-go)
|
||||
|
||||
## pull request process
|
||||
|
||||
Pull requests that change API types in this repo that have corresponding "internal" API objects in the
|
||||
[openshift/origin](https://github.com/openshift/origin) repo must be paired with a pull request to
|
||||
[openshift/origin](https://github.com/openshift/origin).
|
||||
|
||||
To ensure the corresponding origin pull request is ready to merge as soon as the pull request to this repo is merged:
|
||||
1. Base your pull request to this repo on latest [openshift/api#master](https://github.com/openshift/api/commits/master) and ensure CI is green
|
||||
2. Base your pull request to openshift/origin on latest [openshift/origin#master](https://github.com/openshift/origin/commits/master)
|
||||
3. In your openshift/origin pull request:
|
||||
1. Add a TMP commit that points [glide.yaml](https://github.com/openshift/origin/blob/master/glide.yaml#L39-L41) at your fork of openshift/api, and the branch of your pull request:
|
||||
|
||||
```
|
||||
- package: github.com/openshift/api
|
||||
repo: https://github.com/<your-username>/api.git
|
||||
version: "<your-openshift-api-branch>"
|
||||
```
|
||||
|
||||
2. Update your `bump(*)` commit to include the result of running `hack/update-deps.sh`, which will pull in the changes from your openshift/api pull request
|
||||
3. Make sure CI is green on your openshift/origin pull request
|
||||
4. Get LGTM on your openshift/api pull request (for API changes) and your openshift/origin pull request (for code changes)
|
||||
|
||||
Once both pull requests are ready, the openshift/api pull request can be merged.
|
||||
|
||||
Then do the following with your openshift/origin pull request:
|
||||
1. Drop the TMP commit (pointing glide back at openshift/api#master)
|
||||
2. Rerun `hack/update-deps.sh` and update your `bump(*)` commit
|
||||
3. It can then be tagged and merged by CI
|
||||
|
||||
## generating CRD schemas
|
||||
|
||||
Since Kubernetes 1.16, every CRD created in `apiextensions.k8s.io/v1` is required to have a [structural OpenAPIV3 schema](https://kubernetes.io/blog/2019/06/20/crd-structural-schema/). The schemas provide server-side validation for fields, as well as providing the descriptions for `oc explain`. Moreover, schemas ensure structural consistency of data in etcd. Without it anything can be stored in a resource which can have security implications. As we host many of our CRDs in this repo along with their corresponding Go types we also require them to have schemas. However, the following instructions apply for CRDs that are not hosted here as well.
|
||||
|
||||
These schemas are often very long and complex, and should not be written by hand. For OpenShift, we provide Makefile targets in [library-go's alpha-build-machinery](https://github.com/openshift/library-go/tree/master/alpha-build-machinery) which generate the schema, built on upstream's [controller-gen](https://github.com/kubernetes-sigs/controller-tools) tool.
|
||||
|
||||
If you make a change to a CRD type in this repo, simply calling `make update-codegen-crds` should regenerate all CRDs and update the manifests. If yours is not updated, ensure that the path to its API is included in our [calls to the Makefile targets](https://github.com/openshift/api/blob/release-4.5/Makefile#L17-L29).
|
||||
|
||||
To add this generator to another repo:
|
||||
1. Vendor `github.com/openshift/library-go` (and ensure that the `alpha-build-machinery` subdirectory is also included in your `vendor`)
|
||||
|
||||
2. Update your `Makefile` to include the following:
|
||||
```
|
||||
include $(addprefix ./vendor/github.com/openshift/library-go/alpha-build-machinery/make/, \
|
||||
targets/openshift/crd-schema-gen.mk \
|
||||
)
|
||||
|
||||
$(call add-crd-gen,<TARGET_NAME>,<API_DIRECTORY>,<CRD_MANIFESTS>,<MANIFEST_OUTPUT>)
|
||||
```
|
||||
The parameters for the call are:
|
||||
|
||||
1. `TARGET_NAME`: The name of your generated Make target. This can be anything, as long as it does not conflict with another make target. Recommended to be your api name.
|
||||
2. `API_DIRECTORY`: The location of your API. For example if your Go types are located under `pkg/apis/myoperator/v1/types.go`, this should be `./pkg/apis/myoperator/v1`.
|
||||
3. `CRD_MANIFESTS`: The directory your CRDs are located in. For example, if that is `manifests/my_operator.crd.yaml` then it should be `./manifests`
|
||||
4. `MANIFEST_OUTPUT`: This should most likely be the same as `CRD_MANIFESTS`, and is only provided for flexibility to output generated code to a different directory.
|
||||
|
||||
You can include as many calls to different APIs as necessary, or if you have multiple APIs under the same directory (eg, `v1` and `v2beta1`) you can use 1 call to the parent directory pointing to your API.
|
||||
|
||||
After this, calling `make update-codegen-crds` should generate a new structural OpenAPIV3 schema for your CRDs.
|
||||
|
||||
**Notes**
|
||||
- This will not generate entire CRDs, only their OpenAPIV3 schemas. If you do not already have a CRD, you will get no output from the generator.
|
||||
- Ensure that your API is correctly declared for the generator to pick it up. That means, in your `doc.go`, include the following:
|
||||
1. `// +groupName=<API_GROUP_NAME>`, this should match the `group` in your CRD `spec`
|
||||
2. `// +kubebuilder:validation:Optional`, this tells the operator that fields should be optional unless explicitly marked with `// +kubebuilder:validation:Required`
|
||||
|
||||
For more information on the API markers to add to your Go types, see the [Kubebuilder book](https://book.kubebuilder.io/reference/markers.html)
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
reviewers:
|
||||
- mfojtik
|
||||
- soltysh
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package apps
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
appsv1 "github.com/openshift/api/apps/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
GroupName = "apps.openshift.io"
|
||||
)
|
||||
|
||||
var (
|
||||
schemeBuilder = runtime.NewSchemeBuilder(appsv1.Install)
|
||||
// Install is a function which adds every version of this group to a scheme
|
||||
Install = schemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return schema.GroupResource{Group: GroupName, Resource: resource}
|
||||
}
|
||||
|
||||
func Kind(kind string) schema.GroupKind {
|
||||
return schema.GroupKind{Group: GroupName, Kind: kind}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
package v1
|
||||
|
||||
const (
|
||||
// DeploymentStatusReasonAnnotation represents the reason for deployment being in a given state
|
||||
// Used for specifying the reason for cancellation or failure of a deployment
|
||||
// This is on replication controller set by deployer controller.
|
||||
DeploymentStatusReasonAnnotation = "openshift.io/deployment.status-reason"
|
||||
|
||||
// DeploymentPodAnnotation is an annotation on a deployment (a ReplicationController). The
|
||||
// annotation value is the name of the deployer Pod which will act upon the ReplicationController
|
||||
// to implement the deployment behavior.
|
||||
// This is set on replication controller by deployer controller.
|
||||
DeploymentPodAnnotation = "openshift.io/deployer-pod.name"
|
||||
|
||||
// DeploymentConfigAnnotation is an annotation name used to correlate a deployment with the
|
||||
// DeploymentConfig on which the deployment is based.
|
||||
// This is set on replication controller pod template by deployer controller.
|
||||
DeploymentConfigAnnotation = "openshift.io/deployment-config.name"
|
||||
|
||||
// DeploymentCancelledAnnotation indicates that the deployment has been cancelled
|
||||
// The annotation value does not matter and its mere presence indicates cancellation.
|
||||
// This is set on replication controller by deployment config controller or oc rollout cancel command.
|
||||
DeploymentCancelledAnnotation = "openshift.io/deployment.cancelled"
|
||||
|
||||
// DeploymentEncodedConfigAnnotation is an annotation name used to retrieve specific encoded
|
||||
// DeploymentConfig on which a given deployment is based.
|
||||
// This is set on replication controller by deployer controller.
|
||||
DeploymentEncodedConfigAnnotation = "openshift.io/encoded-deployment-config"
|
||||
|
||||
// DeploymentVersionAnnotation is an annotation on a deployment (a ReplicationController). The
|
||||
// annotation value is the LatestVersion value of the DeploymentConfig which was the basis for
|
||||
// the deployment.
|
||||
// This is set on replication controller pod template by deployment config controller.
|
||||
DeploymentVersionAnnotation = "openshift.io/deployment-config.latest-version"
|
||||
|
||||
// DeployerPodForDeploymentLabel is a label which groups pods related to a
|
||||
// deployment. The value is a deployment name. The deployer pod and hook pods
|
||||
// created by the internal strategies will have this label. Custom
|
||||
// strategies can apply this label to any pods they create, enabling
|
||||
// platform-provided cancellation and garbage collection support.
|
||||
// This is set on deployer pod by deployer controller.
|
||||
DeployerPodForDeploymentLabel = "openshift.io/deployer-pod-for.name"
|
||||
|
||||
// DeploymentStatusAnnotation is an annotation name used to retrieve the DeploymentPhase of
|
||||
// a deployment.
|
||||
// This is set on replication controller by deployer controller.
|
||||
DeploymentStatusAnnotation = "openshift.io/deployment.phase"
|
||||
)
|
||||
|
||||
type DeploymentConditionReason string
|
||||
|
||||
var (
|
||||
// ReplicationControllerUpdatedReason is added in a deployment config when one of its replication
|
||||
// controllers is updated as part of the rollout process.
|
||||
ReplicationControllerUpdatedReason DeploymentConditionReason = "ReplicationControllerUpdated"
|
||||
|
||||
// ReplicationControllerCreateError is added in a deployment config when it cannot create a new replication
|
||||
// controller.
|
||||
ReplicationControllerCreateErrorReason DeploymentConditionReason = "ReplicationControllerCreateError"
|
||||
|
||||
// ReplicationControllerCreatedReason is added in a deployment config when it creates a new replication
|
||||
// controller.
|
||||
NewReplicationControllerCreatedReason DeploymentConditionReason = "NewReplicationControllerCreated"
|
||||
|
||||
// NewReplicationControllerAvailableReason is added in a deployment config when its newest replication controller is made
|
||||
// available ie. the number of new pods that have passed readiness checks and run for at least
|
||||
// minReadySeconds is at least the minimum available pods that need to run for the deployment config.
|
||||
NewReplicationControllerAvailableReason DeploymentConditionReason = "NewReplicationControllerAvailable"
|
||||
|
||||
// ProgressDeadlineExceededReason is added in a deployment config when its newest replication controller fails to show
|
||||
// any progress within the given deadline (progressDeadlineSeconds).
|
||||
ProgressDeadlineExceededReason DeploymentConditionReason = "ProgressDeadlineExceeded"
|
||||
|
||||
// DeploymentConfigPausedReason is added in a deployment config when it is paused. Lack of progress shouldn't be
|
||||
// estimated once a deployment config is paused.
|
||||
DeploymentConfigPausedReason DeploymentConditionReason = "DeploymentConfigPaused"
|
||||
|
||||
// DeploymentConfigResumedReason is added in a deployment config when it is resumed. Useful for not failing accidentally
|
||||
// deployment configs that paused amidst a rollout.
|
||||
DeploymentConfigResumedReason DeploymentConditionReason = "DeploymentConfigResumed"
|
||||
|
||||
// RolloutCancelledReason is added in a deployment config when its newest rollout was
|
||||
// interrupted by cancellation.
|
||||
RolloutCancelledReason DeploymentConditionReason = "RolloutCancelled"
|
||||
)
|
||||
|
||||
// DeploymentStatus describes the possible states a deployment can be in.
|
||||
type DeploymentStatus string
|
||||
|
||||
var (
|
||||
|
||||
// DeploymentStatusNew means the deployment has been accepted but not yet acted upon.
|
||||
DeploymentStatusNew DeploymentStatus = "New"
|
||||
|
||||
// DeploymentStatusPending means the deployment been handed over to a deployment strategy,
|
||||
// but the strategy has not yet declared the deployment to be running.
|
||||
DeploymentStatusPending DeploymentStatus = "Pending"
|
||||
|
||||
// DeploymentStatusRunning means the deployment strategy has reported the deployment as
|
||||
// being in-progress.
|
||||
DeploymentStatusRunning DeploymentStatus = "Running"
|
||||
|
||||
// DeploymentStatusComplete means the deployment finished without an error.
|
||||
DeploymentStatusComplete DeploymentStatus = "Complete"
|
||||
|
||||
// DeploymentStatusFailed means the deployment finished with an error.
|
||||
DeploymentStatusFailed DeploymentStatus = "Failed"
|
||||
)
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package v1
|
||||
|
||||
// This file contains consts that are not shared between components and set just internally.
|
||||
// They will likely be removed in (near) future.
|
||||
|
||||
const (
|
||||
// DeployerPodCreatedAtAnnotation is an annotation on a deployment that
|
||||
// records the time in RFC3339 format of when the deployer pod for this particular
|
||||
// deployment was created.
|
||||
// This is set by deployer controller, but not consumed by any command or internally.
|
||||
// DEPRECATED: will be removed soon
|
||||
DeployerPodCreatedAtAnnotation = "openshift.io/deployer-pod.created-at"
|
||||
|
||||
// DeployerPodStartedAtAnnotation is an annotation on a deployment that
|
||||
// records the time in RFC3339 format of when the deployer pod for this particular
|
||||
// deployment was started.
|
||||
// This is set by deployer controller, but not consumed by any command or internally.
|
||||
// DEPRECATED: will be removed soon
|
||||
DeployerPodStartedAtAnnotation = "openshift.io/deployer-pod.started-at"
|
||||
|
||||
// DeployerPodCompletedAtAnnotation is an annotation on deployment that records
|
||||
// the time in RFC3339 format of when the deployer pod finished.
|
||||
// This is set by deployer controller, but not consumed by any command or internally.
|
||||
// DEPRECATED: will be removed soon
|
||||
DeployerPodCompletedAtAnnotation = "openshift.io/deployer-pod.completed-at"
|
||||
|
||||
// DesiredReplicasAnnotation represents the desired number of replicas for a
|
||||
// new deployment.
|
||||
// This is set by deployer controller, but not consumed by any command or internally.
|
||||
// DEPRECATED: will be removed soon
|
||||
DesiredReplicasAnnotation = "kubectl.kubernetes.io/desired-replicas"
|
||||
|
||||
// DeploymentAnnotation is an annotation on a deployer Pod. The annotation value is the name
|
||||
// of the deployment (a ReplicationController) on which the deployer Pod acts.
|
||||
// This is set by deployer controller and consumed internally and in oc adm top command.
|
||||
// DEPRECATED: will be removed soon
|
||||
DeploymentAnnotation = "openshift.io/deployment.name"
|
||||
)
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
// +k8s:conversion-gen=github.com/openshift/origin/pkg/apps/apis/apps
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +k8s:openapi-gen=true
|
||||
|
||||
// +groupName=apps.openshift.io
|
||||
// Package v1 is the v1 version of the API.
|
||||
package v1
|
||||
+7530
File diff suppressed because it is too large
Load Diff
+466
@@ -0,0 +1,466 @@
|
||||
|
||||
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
|
||||
|
||||
syntax = 'proto2';
|
||||
|
||||
package github.com.openshift.api.apps.v1;
|
||||
|
||||
import "k8s.io/api/core/v1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/util/intstr/generated.proto";
|
||||
|
||||
// Package-wide variables from generator "generated".
|
||||
option go_package = "v1";
|
||||
|
||||
// CustomDeploymentStrategyParams are the input to the Custom deployment strategy.
|
||||
message CustomDeploymentStrategyParams {
|
||||
// Image specifies a container image which can carry out a deployment.
|
||||
optional string image = 1;
|
||||
|
||||
// Environment holds the environment which will be given to the container for Image.
|
||||
repeated k8s.io.api.core.v1.EnvVar environment = 2;
|
||||
|
||||
// Command is optional and overrides CMD in the container Image.
|
||||
repeated string command = 3;
|
||||
}
|
||||
|
||||
// DeploymentCause captures information about a particular cause of a deployment.
|
||||
message DeploymentCause {
|
||||
// Type of the trigger that resulted in the creation of a new deployment
|
||||
optional string type = 1;
|
||||
|
||||
// ImageTrigger contains the image trigger details, if this trigger was fired based on an image change
|
||||
optional DeploymentCauseImageTrigger imageTrigger = 2;
|
||||
}
|
||||
|
||||
// DeploymentCauseImageTrigger represents details about the cause of a deployment originating
|
||||
// from an image change trigger
|
||||
message DeploymentCauseImageTrigger {
|
||||
// From is a reference to the changed object which triggered a deployment. The field may have
|
||||
// the kinds DockerImage, ImageStreamTag, or ImageStreamImage.
|
||||
optional k8s.io.api.core.v1.ObjectReference from = 1;
|
||||
}
|
||||
|
||||
// DeploymentCondition describes the state of a deployment config at a certain point.
|
||||
message DeploymentCondition {
|
||||
// Type of deployment condition.
|
||||
optional string type = 1;
|
||||
|
||||
// Status of the condition, one of True, False, Unknown.
|
||||
optional string status = 2;
|
||||
|
||||
// The last time this condition was updated.
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastUpdateTime = 6;
|
||||
|
||||
// The last time the condition transitioned from one status to another.
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3;
|
||||
|
||||
// The reason for the condition's last transition.
|
||||
optional string reason = 4;
|
||||
|
||||
// A human readable message indicating details about the transition.
|
||||
optional string message = 5;
|
||||
}
|
||||
|
||||
// Deployment Configs define the template for a pod and manages deploying new images or configuration changes.
|
||||
// A single deployment configuration is usually analogous to a single micro-service. Can support many different
|
||||
// deployment patterns, including full restart, customizable rolling updates, and fully custom behaviors, as
|
||||
// well as pre- and post- deployment hooks. Each individual deployment is represented as a replication controller.
|
||||
//
|
||||
// A deployment is "triggered" when its configuration is changed or a tag in an Image Stream is changed.
|
||||
// Triggers can be disabled to allow manual control over a deployment. The "strategy" determines how the deployment
|
||||
// is carried out and may be changed at any time. The `latestVersion` field is updated when a new deployment
|
||||
// is triggered by any means.
|
||||
message DeploymentConfig {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||
|
||||
// Spec represents a desired deployment state and how to deploy to it.
|
||||
optional DeploymentConfigSpec spec = 2;
|
||||
|
||||
// Status represents the current deployment state.
|
||||
// +optional
|
||||
optional DeploymentConfigStatus status = 3;
|
||||
}
|
||||
|
||||
// DeploymentConfigList is a collection of deployment configs.
|
||||
message DeploymentConfigList {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1;
|
||||
|
||||
// Items is a list of deployment configs
|
||||
repeated DeploymentConfig items = 2;
|
||||
}
|
||||
|
||||
// DeploymentConfigRollback provides the input to rollback generation.
|
||||
message DeploymentConfigRollback {
|
||||
// Name of the deployment config that will be rolled back.
|
||||
optional string name = 1;
|
||||
|
||||
// UpdatedAnnotations is a set of new annotations that will be added in the deployment config.
|
||||
map<string, string> updatedAnnotations = 2;
|
||||
|
||||
// Spec defines the options to rollback generation.
|
||||
optional DeploymentConfigRollbackSpec spec = 3;
|
||||
}
|
||||
|
||||
// DeploymentConfigRollbackSpec represents the options for rollback generation.
|
||||
message DeploymentConfigRollbackSpec {
|
||||
// From points to a ReplicationController which is a deployment.
|
||||
optional k8s.io.api.core.v1.ObjectReference from = 1;
|
||||
|
||||
// Revision to rollback to. If set to 0, rollback to the last revision.
|
||||
optional int64 revision = 2;
|
||||
|
||||
// IncludeTriggers specifies whether to include config Triggers.
|
||||
optional bool includeTriggers = 3;
|
||||
|
||||
// IncludeTemplate specifies whether to include the PodTemplateSpec.
|
||||
optional bool includeTemplate = 4;
|
||||
|
||||
// IncludeReplicationMeta specifies whether to include the replica count and selector.
|
||||
optional bool includeReplicationMeta = 5;
|
||||
|
||||
// IncludeStrategy specifies whether to include the deployment Strategy.
|
||||
optional bool includeStrategy = 6;
|
||||
}
|
||||
|
||||
// DeploymentConfigSpec represents the desired state of the deployment.
|
||||
message DeploymentConfigSpec {
|
||||
// Strategy describes how a deployment is executed.
|
||||
// +optional
|
||||
optional DeploymentStrategy strategy = 1;
|
||||
|
||||
// MinReadySeconds is the minimum number of seconds for which a newly created pod should
|
||||
// be ready without any of its container crashing, for it to be considered available.
|
||||
// Defaults to 0 (pod will be considered available as soon as it is ready)
|
||||
optional int32 minReadySeconds = 9;
|
||||
|
||||
// Triggers determine how updates to a DeploymentConfig result in new deployments. If no triggers
|
||||
// are defined, a new deployment can only occur as a result of an explicit client update to the
|
||||
// DeploymentConfig with a new LatestVersion. If null, defaults to having a config change trigger.
|
||||
// +optional
|
||||
optional DeploymentTriggerPolicies triggers = 2;
|
||||
|
||||
// Replicas is the number of desired replicas.
|
||||
// +optional
|
||||
optional int32 replicas = 3;
|
||||
|
||||
// RevisionHistoryLimit is the number of old ReplicationControllers to retain to allow for rollbacks.
|
||||
// This field is a pointer to allow for differentiation between an explicit zero and not specified.
|
||||
// Defaults to 10. (This only applies to DeploymentConfigs created via the new group API resource, not the legacy resource.)
|
||||
optional int32 revisionHistoryLimit = 4;
|
||||
|
||||
// Test ensures that this deployment config will have zero replicas except while a deployment is running. This allows the
|
||||
// deployment config to be used as a continuous deployment test - triggering on images, running the deployment, and then succeeding
|
||||
// or failing. Post strategy hooks and After actions can be used to integrate successful deployment with an action.
|
||||
// +optional
|
||||
optional bool test = 5;
|
||||
|
||||
// Paused indicates that the deployment config is paused resulting in no new deployments on template
|
||||
// changes or changes in the template caused by other triggers.
|
||||
optional bool paused = 6;
|
||||
|
||||
// Selector is a label query over pods that should match the Replicas count.
|
||||
map<string, string> selector = 7;
|
||||
|
||||
// Template is the object that describes the pod that will be created if
|
||||
// insufficient replicas are detected.
|
||||
optional k8s.io.api.core.v1.PodTemplateSpec template = 8;
|
||||
}
|
||||
|
||||
// DeploymentConfigStatus represents the current deployment state.
|
||||
message DeploymentConfigStatus {
|
||||
// LatestVersion is used to determine whether the current deployment associated with a deployment
|
||||
// config is out of sync.
|
||||
optional int64 latestVersion = 1;
|
||||
|
||||
// ObservedGeneration is the most recent generation observed by the deployment config controller.
|
||||
optional int64 observedGeneration = 2;
|
||||
|
||||
// Replicas is the total number of pods targeted by this deployment config.
|
||||
optional int32 replicas = 3;
|
||||
|
||||
// UpdatedReplicas is the total number of non-terminated pods targeted by this deployment config
|
||||
// that have the desired template spec.
|
||||
optional int32 updatedReplicas = 4;
|
||||
|
||||
// AvailableReplicas is the total number of available pods targeted by this deployment config.
|
||||
optional int32 availableReplicas = 5;
|
||||
|
||||
// UnavailableReplicas is the total number of unavailable pods targeted by this deployment config.
|
||||
optional int32 unavailableReplicas = 6;
|
||||
|
||||
// Details are the reasons for the update to this deployment config.
|
||||
// This could be based on a change made by the user or caused by an automatic trigger
|
||||
optional DeploymentDetails details = 7;
|
||||
|
||||
// Conditions represents the latest available observations of a deployment config's current state.
|
||||
// +patchMergeKey=type
|
||||
// +patchStrategy=merge
|
||||
repeated DeploymentCondition conditions = 8;
|
||||
|
||||
// Total number of ready pods targeted by this deployment.
|
||||
optional int32 readyReplicas = 9;
|
||||
}
|
||||
|
||||
// DeploymentDetails captures information about the causes of a deployment.
|
||||
message DeploymentDetails {
|
||||
// Message is the user specified change message, if this deployment was triggered manually by the user
|
||||
optional string message = 1;
|
||||
|
||||
// Causes are extended data associated with all the causes for creating a new deployment
|
||||
repeated DeploymentCause causes = 2;
|
||||
}
|
||||
|
||||
// DeploymentLog represents the logs for a deployment
|
||||
message DeploymentLog {
|
||||
}
|
||||
|
||||
// DeploymentLogOptions is the REST options for a deployment log
|
||||
message DeploymentLogOptions {
|
||||
// The container for which to stream logs. Defaults to only container if there is one container in the pod.
|
||||
optional string container = 1;
|
||||
|
||||
// Follow if true indicates that the build log should be streamed until
|
||||
// the build terminates.
|
||||
optional bool follow = 2;
|
||||
|
||||
// Return previous deployment logs. Defaults to false.
|
||||
optional bool previous = 3;
|
||||
|
||||
// A relative time in seconds before the current time from which to show logs. If this value
|
||||
// precedes the time a pod was started, only logs since the pod start will be returned.
|
||||
// If this value is in the future, no logs will be returned.
|
||||
// Only one of sinceSeconds or sinceTime may be specified.
|
||||
optional int64 sinceSeconds = 4;
|
||||
|
||||
// An RFC3339 timestamp from which to show logs. If this value
|
||||
// precedes the time a pod was started, only logs since the pod start will be returned.
|
||||
// If this value is in the future, no logs will be returned.
|
||||
// Only one of sinceSeconds or sinceTime may be specified.
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time sinceTime = 5;
|
||||
|
||||
// If true, add an RFC3339 or RFC3339Nano timestamp at the beginning of every line
|
||||
// of log output. Defaults to false.
|
||||
optional bool timestamps = 6;
|
||||
|
||||
// If set, the number of lines from the end of the logs to show. If not specified,
|
||||
// logs are shown from the creation of the container or sinceSeconds or sinceTime
|
||||
optional int64 tailLines = 7;
|
||||
|
||||
// If set, the number of bytes to read from the server before terminating the
|
||||
// log output. This may not display a complete final line of logging, and may return
|
||||
// slightly more or slightly less than the specified limit.
|
||||
optional int64 limitBytes = 8;
|
||||
|
||||
// NoWait if true causes the call to return immediately even if the deployment
|
||||
// is not available yet. Otherwise the server will wait until the deployment has started.
|
||||
// TODO: Fix the tag to 'noWait' in v2
|
||||
optional bool nowait = 9;
|
||||
|
||||
// Version of the deployment for which to view logs.
|
||||
optional int64 version = 10;
|
||||
}
|
||||
|
||||
// DeploymentRequest is a request to a deployment config for a new deployment.
|
||||
message DeploymentRequest {
|
||||
// Name of the deployment config for requesting a new deployment.
|
||||
optional string name = 1;
|
||||
|
||||
// Latest will update the deployment config with the latest state from all triggers.
|
||||
optional bool latest = 2;
|
||||
|
||||
// Force will try to force a new deployment to run. If the deployment config is paused,
|
||||
// then setting this to true will return an Invalid error.
|
||||
optional bool force = 3;
|
||||
|
||||
// ExcludeTriggers instructs the instantiator to avoid processing the specified triggers.
|
||||
// This field overrides the triggers from latest and allows clients to control specific
|
||||
// logic. This field is ignored if not specified.
|
||||
repeated string excludeTriggers = 4;
|
||||
}
|
||||
|
||||
// DeploymentStrategy describes how to perform a deployment.
|
||||
message DeploymentStrategy {
|
||||
// Type is the name of a deployment strategy.
|
||||
optional string type = 1;
|
||||
|
||||
// CustomParams are the input to the Custom deployment strategy, and may also
|
||||
// be specified for the Recreate and Rolling strategies to customize the execution
|
||||
// process that runs the deployment.
|
||||
optional CustomDeploymentStrategyParams customParams = 2;
|
||||
|
||||
// RecreateParams are the input to the Recreate deployment strategy.
|
||||
optional RecreateDeploymentStrategyParams recreateParams = 3;
|
||||
|
||||
// RollingParams are the input to the Rolling deployment strategy.
|
||||
optional RollingDeploymentStrategyParams rollingParams = 4;
|
||||
|
||||
// Resources contains resource requirements to execute the deployment and any hooks.
|
||||
optional k8s.io.api.core.v1.ResourceRequirements resources = 5;
|
||||
|
||||
// Labels is a set of key, value pairs added to custom deployer and lifecycle pre/post hook pods.
|
||||
map<string, string> labels = 6;
|
||||
|
||||
// Annotations is a set of key, value pairs added to custom deployer and lifecycle pre/post hook pods.
|
||||
map<string, string> annotations = 7;
|
||||
|
||||
// ActiveDeadlineSeconds is the duration in seconds that the deployer pods for this deployment
|
||||
// config may be active on a node before the system actively tries to terminate them.
|
||||
optional int64 activeDeadlineSeconds = 8;
|
||||
}
|
||||
|
||||
// DeploymentTriggerImageChangeParams represents the parameters to the ImageChange trigger.
|
||||
message DeploymentTriggerImageChangeParams {
|
||||
// Automatic means that the detection of a new tag value should result in an image update
|
||||
// inside the pod template.
|
||||
optional bool automatic = 1;
|
||||
|
||||
// ContainerNames is used to restrict tag updates to the specified set of container names in a pod.
|
||||
// If multiple triggers point to the same containers, the resulting behavior is undefined. Future
|
||||
// API versions will make this a validation error. If ContainerNames does not point to a valid container,
|
||||
// the trigger will be ignored. Future API versions will make this a validation error.
|
||||
repeated string containerNames = 2;
|
||||
|
||||
// From is a reference to an image stream tag to watch for changes. From.Name is the only
|
||||
// required subfield - if From.Namespace is blank, the namespace of the current deployment
|
||||
// trigger will be used.
|
||||
optional k8s.io.api.core.v1.ObjectReference from = 3;
|
||||
|
||||
// LastTriggeredImage is the last image to be triggered.
|
||||
optional string lastTriggeredImage = 4;
|
||||
}
|
||||
|
||||
// DeploymentTriggerPolicies is a list of policies where nil values and different from empty arrays.
|
||||
// +protobuf.nullable=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
message DeploymentTriggerPolicies {
|
||||
// items, if empty, will result in an empty slice
|
||||
|
||||
repeated DeploymentTriggerPolicy items = 1;
|
||||
}
|
||||
|
||||
// DeploymentTriggerPolicy describes a policy for a single trigger that results in a new deployment.
|
||||
message DeploymentTriggerPolicy {
|
||||
// Type of the trigger
|
||||
optional string type = 1;
|
||||
|
||||
// ImageChangeParams represents the parameters for the ImageChange trigger.
|
||||
optional DeploymentTriggerImageChangeParams imageChangeParams = 2;
|
||||
}
|
||||
|
||||
// ExecNewPodHook is a hook implementation which runs a command in a new pod
|
||||
// based on the specified container which is assumed to be part of the
|
||||
// deployment template.
|
||||
message ExecNewPodHook {
|
||||
// Command is the action command and its arguments.
|
||||
repeated string command = 1;
|
||||
|
||||
// Env is a set of environment variables to supply to the hook pod's container.
|
||||
repeated k8s.io.api.core.v1.EnvVar env = 2;
|
||||
|
||||
// ContainerName is the name of a container in the deployment pod template
|
||||
// whose container image will be used for the hook pod's container.
|
||||
optional string containerName = 3;
|
||||
|
||||
// Volumes is a list of named volumes from the pod template which should be
|
||||
// copied to the hook pod. Volumes names not found in pod spec are ignored.
|
||||
// An empty list means no volumes will be copied.
|
||||
repeated string volumes = 4;
|
||||
}
|
||||
|
||||
// LifecycleHook defines a specific deployment lifecycle action. Only one type of action may be specified at any time.
|
||||
message LifecycleHook {
|
||||
// FailurePolicy specifies what action to take if the hook fails.
|
||||
optional string failurePolicy = 1;
|
||||
|
||||
// ExecNewPod specifies the options for a lifecycle hook backed by a pod.
|
||||
optional ExecNewPodHook execNewPod = 2;
|
||||
|
||||
// TagImages instructs the deployer to tag the current image referenced under a container onto an image stream tag.
|
||||
repeated TagImageHook tagImages = 3;
|
||||
}
|
||||
|
||||
// RecreateDeploymentStrategyParams are the input to the Recreate deployment
|
||||
// strategy.
|
||||
message RecreateDeploymentStrategyParams {
|
||||
// TimeoutSeconds is the time to wait for updates before giving up. If the
|
||||
// value is nil, a default will be used.
|
||||
optional int64 timeoutSeconds = 1;
|
||||
|
||||
// Pre is a lifecycle hook which is executed before the strategy manipulates
|
||||
// the deployment. All LifecycleHookFailurePolicy values are supported.
|
||||
optional LifecycleHook pre = 2;
|
||||
|
||||
// Mid is a lifecycle hook which is executed while the deployment is scaled down to zero before the first new
|
||||
// pod is created. All LifecycleHookFailurePolicy values are supported.
|
||||
optional LifecycleHook mid = 3;
|
||||
|
||||
// Post is a lifecycle hook which is executed after the strategy has
|
||||
// finished all deployment logic. All LifecycleHookFailurePolicy values are supported.
|
||||
optional LifecycleHook post = 4;
|
||||
}
|
||||
|
||||
// RollingDeploymentStrategyParams are the input to the Rolling deployment
|
||||
// strategy.
|
||||
message RollingDeploymentStrategyParams {
|
||||
// UpdatePeriodSeconds is the time to wait between individual pod updates.
|
||||
// If the value is nil, a default will be used.
|
||||
optional int64 updatePeriodSeconds = 1;
|
||||
|
||||
// IntervalSeconds is the time to wait between polling deployment status
|
||||
// after update. If the value is nil, a default will be used.
|
||||
optional int64 intervalSeconds = 2;
|
||||
|
||||
// TimeoutSeconds is the time to wait for updates before giving up. If the
|
||||
// value is nil, a default will be used.
|
||||
optional int64 timeoutSeconds = 3;
|
||||
|
||||
// MaxUnavailable is the maximum number of pods that can be unavailable
|
||||
// during the update. Value can be an absolute number (ex: 5) or a
|
||||
// percentage of total pods at the start of update (ex: 10%). Absolute
|
||||
// number is calculated from percentage by rounding down.
|
||||
//
|
||||
// This cannot be 0 if MaxSurge is 0. By default, 25% is used.
|
||||
//
|
||||
// Example: when this is set to 30%, the old RC can be scaled down by 30%
|
||||
// immediately when the rolling update starts. Once new pods are ready, old
|
||||
// RC can be scaled down further, followed by scaling up the new RC,
|
||||
// ensuring that at least 70% of original number of pods are available at
|
||||
// all times during the update.
|
||||
optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 4;
|
||||
|
||||
// MaxSurge is the maximum number of pods that can be scheduled above the
|
||||
// original number of pods. Value can be an absolute number (ex: 5) or a
|
||||
// percentage of total pods at the start of the update (ex: 10%). Absolute
|
||||
// number is calculated from percentage by rounding up.
|
||||
//
|
||||
// This cannot be 0 if MaxUnavailable is 0. By default, 25% is used.
|
||||
//
|
||||
// Example: when this is set to 30%, the new RC can be scaled up by 30%
|
||||
// immediately when the rolling update starts. Once old pods have been
|
||||
// killed, new RC can be scaled up further, ensuring that total number of
|
||||
// pods running at any time during the update is atmost 130% of original
|
||||
// pods.
|
||||
optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxSurge = 5;
|
||||
|
||||
// Pre is a lifecycle hook which is executed before the deployment process
|
||||
// begins. All LifecycleHookFailurePolicy values are supported.
|
||||
optional LifecycleHook pre = 7;
|
||||
|
||||
// Post is a lifecycle hook which is executed after the strategy has
|
||||
// finished all deployment logic. All LifecycleHookFailurePolicy values
|
||||
// are supported.
|
||||
optional LifecycleHook post = 8;
|
||||
}
|
||||
|
||||
// TagImageHook is a request to tag the image in a particular container onto an ImageStreamTag.
|
||||
message TagImageHook {
|
||||
// ContainerName is the name of a container in the deployment config whose image value will be used as the source of the tag. If there is only a single
|
||||
// container this value will be defaulted to the name of that container.
|
||||
optional string containerName = 1;
|
||||
|
||||
// To is the target ImageStreamTag to set the container's image onto.
|
||||
optional k8s.io.api.core.v1.ObjectReference to = 2;
|
||||
}
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
legacyGroupVersion = schema.GroupVersion{Group: "", Version: "v1"}
|
||||
legacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, corev1.AddToScheme, extensionsv1beta1.AddToScheme)
|
||||
DeprecatedInstallWithoutGroup = legacySchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func addLegacyKnownTypes(scheme *runtime.Scheme) error {
|
||||
types := []runtime.Object{
|
||||
&DeploymentConfig{},
|
||||
&DeploymentConfigList{},
|
||||
&DeploymentConfigRollback{},
|
||||
&DeploymentRequest{},
|
||||
&DeploymentLog{},
|
||||
&DeploymentLogOptions{},
|
||||
&extensionsv1beta1.Scale{},
|
||||
}
|
||||
scheme.AddKnownTypes(legacyGroupVersion, types...)
|
||||
return nil
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
GroupName = "apps.openshift.io"
|
||||
GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
|
||||
schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, corev1.AddToScheme, extensionsv1beta1.AddToScheme)
|
||||
// Install is a function which adds this version to a scheme
|
||||
Install = schemeBuilder.AddToScheme
|
||||
|
||||
// SchemeGroupVersion generated code relies on this name
|
||||
// Deprecated
|
||||
SchemeGroupVersion = GroupVersion
|
||||
// AddToScheme exists solely to keep the old generators creating valid code
|
||||
// DEPRECATED
|
||||
AddToScheme = schemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// Resource generated code relies on this being here, but it logically belongs to the group
|
||||
// DEPRECATED
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return schema.GroupResource{Group: GroupName, Resource: resource}
|
||||
}
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(GroupVersion,
|
||||
&DeploymentConfig{},
|
||||
&DeploymentConfigList{},
|
||||
&DeploymentConfigRollback{},
|
||||
&DeploymentRequest{},
|
||||
&DeploymentLog{},
|
||||
&DeploymentLogOptions{},
|
||||
&extensionsv1beta1.Scale{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, GroupVersion)
|
||||
return nil
|
||||
}
|
||||
+493
@@ -0,0 +1,493 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
// +genclient
|
||||
// +genclient:method=Instantiate,verb=create,subresource=instantiate,input=DeploymentRequest
|
||||
// +genclient:method=Rollback,verb=create,subresource=rollback,input=DeploymentConfigRollback
|
||||
// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/api/extensions/v1beta1.Scale
|
||||
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/api/extensions/v1beta1.Scale,result=k8s.io/api/extensions/v1beta1.Scale
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Deployment Configs define the template for a pod and manages deploying new images or configuration changes.
|
||||
// A single deployment configuration is usually analogous to a single micro-service. Can support many different
|
||||
// deployment patterns, including full restart, customizable rolling updates, and fully custom behaviors, as
|
||||
// well as pre- and post- deployment hooks. Each individual deployment is represented as a replication controller.
|
||||
//
|
||||
// A deployment is "triggered" when its configuration is changed or a tag in an Image Stream is changed.
|
||||
// Triggers can be disabled to allow manual control over a deployment. The "strategy" determines how the deployment
|
||||
// is carried out and may be changed at any time. The `latestVersion` field is updated when a new deployment
|
||||
// is triggered by any means.
|
||||
type DeploymentConfig struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Spec represents a desired deployment state and how to deploy to it.
|
||||
Spec DeploymentConfigSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
|
||||
|
||||
// Status represents the current deployment state.
|
||||
// +optional
|
||||
Status DeploymentConfigStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
}
|
||||
|
||||
// DeploymentConfigSpec represents the desired state of the deployment.
|
||||
type DeploymentConfigSpec struct {
|
||||
// Strategy describes how a deployment is executed.
|
||||
// +optional
|
||||
Strategy DeploymentStrategy `json:"strategy" protobuf:"bytes,1,opt,name=strategy"`
|
||||
|
||||
// MinReadySeconds is the minimum number of seconds for which a newly created pod should
|
||||
// be ready without any of its container crashing, for it to be considered available.
|
||||
// Defaults to 0 (pod will be considered available as soon as it is ready)
|
||||
MinReadySeconds int32 `json:"minReadySeconds,omitempty" protobuf:"varint,9,opt,name=minReadySeconds"`
|
||||
|
||||
// Triggers determine how updates to a DeploymentConfig result in new deployments. If no triggers
|
||||
// are defined, a new deployment can only occur as a result of an explicit client update to the
|
||||
// DeploymentConfig with a new LatestVersion. If null, defaults to having a config change trigger.
|
||||
// +optional
|
||||
Triggers DeploymentTriggerPolicies `json:"triggers" protobuf:"bytes,2,rep,name=triggers"`
|
||||
|
||||
// Replicas is the number of desired replicas.
|
||||
// +optional
|
||||
Replicas int32 `json:"replicas" protobuf:"varint,3,opt,name=replicas"`
|
||||
|
||||
// RevisionHistoryLimit is the number of old ReplicationControllers to retain to allow for rollbacks.
|
||||
// This field is a pointer to allow for differentiation between an explicit zero and not specified.
|
||||
// Defaults to 10. (This only applies to DeploymentConfigs created via the new group API resource, not the legacy resource.)
|
||||
RevisionHistoryLimit *int32 `json:"revisionHistoryLimit,omitempty" protobuf:"varint,4,opt,name=revisionHistoryLimit"`
|
||||
|
||||
// Test ensures that this deployment config will have zero replicas except while a deployment is running. This allows the
|
||||
// deployment config to be used as a continuous deployment test - triggering on images, running the deployment, and then succeeding
|
||||
// or failing. Post strategy hooks and After actions can be used to integrate successful deployment with an action.
|
||||
// +optional
|
||||
Test bool `json:"test" protobuf:"varint,5,opt,name=test"`
|
||||
|
||||
// Paused indicates that the deployment config is paused resulting in no new deployments on template
|
||||
// changes or changes in the template caused by other triggers.
|
||||
Paused bool `json:"paused,omitempty" protobuf:"varint,6,opt,name=paused"`
|
||||
|
||||
// Selector is a label query over pods that should match the Replicas count.
|
||||
Selector map[string]string `json:"selector,omitempty" protobuf:"bytes,7,rep,name=selector"`
|
||||
|
||||
// Template is the object that describes the pod that will be created if
|
||||
// insufficient replicas are detected.
|
||||
Template *corev1.PodTemplateSpec `json:"template,omitempty" protobuf:"bytes,8,opt,name=template"`
|
||||
}
|
||||
|
||||
// DeploymentStrategy describes how to perform a deployment.
|
||||
type DeploymentStrategy struct {
|
||||
// Type is the name of a deployment strategy.
|
||||
Type DeploymentStrategyType `json:"type,omitempty" protobuf:"bytes,1,opt,name=type,casttype=DeploymentStrategyType"`
|
||||
|
||||
// CustomParams are the input to the Custom deployment strategy, and may also
|
||||
// be specified for the Recreate and Rolling strategies to customize the execution
|
||||
// process that runs the deployment.
|
||||
CustomParams *CustomDeploymentStrategyParams `json:"customParams,omitempty" protobuf:"bytes,2,opt,name=customParams"`
|
||||
// RecreateParams are the input to the Recreate deployment strategy.
|
||||
RecreateParams *RecreateDeploymentStrategyParams `json:"recreateParams,omitempty" protobuf:"bytes,3,opt,name=recreateParams"`
|
||||
// RollingParams are the input to the Rolling deployment strategy.
|
||||
RollingParams *RollingDeploymentStrategyParams `json:"rollingParams,omitempty" protobuf:"bytes,4,opt,name=rollingParams"`
|
||||
|
||||
// Resources contains resource requirements to execute the deployment and any hooks.
|
||||
Resources corev1.ResourceRequirements `json:"resources,omitempty" protobuf:"bytes,5,opt,name=resources"`
|
||||
// Labels is a set of key, value pairs added to custom deployer and lifecycle pre/post hook pods.
|
||||
Labels map[string]string `json:"labels,omitempty" protobuf:"bytes,6,rep,name=labels"`
|
||||
// Annotations is a set of key, value pairs added to custom deployer and lifecycle pre/post hook pods.
|
||||
Annotations map[string]string `json:"annotations,omitempty" protobuf:"bytes,7,rep,name=annotations"`
|
||||
|
||||
// ActiveDeadlineSeconds is the duration in seconds that the deployer pods for this deployment
|
||||
// config may be active on a node before the system actively tries to terminate them.
|
||||
ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty" protobuf:"varint,8,opt,name=activeDeadlineSeconds"`
|
||||
}
|
||||
|
||||
// DeploymentStrategyType refers to a specific DeploymentStrategy implementation.
|
||||
type DeploymentStrategyType string
|
||||
|
||||
const (
|
||||
// DeploymentStrategyTypeRecreate is a simple strategy suitable as a default.
|
||||
DeploymentStrategyTypeRecreate DeploymentStrategyType = "Recreate"
|
||||
// DeploymentStrategyTypeCustom is a user defined strategy.
|
||||
DeploymentStrategyTypeCustom DeploymentStrategyType = "Custom"
|
||||
// DeploymentStrategyTypeRolling uses the Kubernetes RollingUpdater.
|
||||
DeploymentStrategyTypeRolling DeploymentStrategyType = "Rolling"
|
||||
)
|
||||
|
||||
// CustomDeploymentStrategyParams are the input to the Custom deployment strategy.
|
||||
type CustomDeploymentStrategyParams struct {
|
||||
// Image specifies a container image which can carry out a deployment.
|
||||
Image string `json:"image,omitempty" protobuf:"bytes,1,opt,name=image"`
|
||||
// Environment holds the environment which will be given to the container for Image.
|
||||
Environment []corev1.EnvVar `json:"environment,omitempty" protobuf:"bytes,2,rep,name=environment"`
|
||||
// Command is optional and overrides CMD in the container Image.
|
||||
Command []string `json:"command,omitempty" protobuf:"bytes,3,rep,name=command"`
|
||||
}
|
||||
|
||||
// RecreateDeploymentStrategyParams are the input to the Recreate deployment
|
||||
// strategy.
|
||||
type RecreateDeploymentStrategyParams struct {
|
||||
// TimeoutSeconds is the time to wait for updates before giving up. If the
|
||||
// value is nil, a default will be used.
|
||||
TimeoutSeconds *int64 `json:"timeoutSeconds,omitempty" protobuf:"varint,1,opt,name=timeoutSeconds"`
|
||||
// Pre is a lifecycle hook which is executed before the strategy manipulates
|
||||
// the deployment. All LifecycleHookFailurePolicy values are supported.
|
||||
Pre *LifecycleHook `json:"pre,omitempty" protobuf:"bytes,2,opt,name=pre"`
|
||||
// Mid is a lifecycle hook which is executed while the deployment is scaled down to zero before the first new
|
||||
// pod is created. All LifecycleHookFailurePolicy values are supported.
|
||||
Mid *LifecycleHook `json:"mid,omitempty" protobuf:"bytes,3,opt,name=mid"`
|
||||
// Post is a lifecycle hook which is executed after the strategy has
|
||||
// finished all deployment logic. All LifecycleHookFailurePolicy values are supported.
|
||||
Post *LifecycleHook `json:"post,omitempty" protobuf:"bytes,4,opt,name=post"`
|
||||
}
|
||||
|
||||
// RollingDeploymentStrategyParams are the input to the Rolling deployment
|
||||
// strategy.
|
||||
type RollingDeploymentStrategyParams struct {
|
||||
// UpdatePeriodSeconds is the time to wait between individual pod updates.
|
||||
// If the value is nil, a default will be used.
|
||||
UpdatePeriodSeconds *int64 `json:"updatePeriodSeconds,omitempty" protobuf:"varint,1,opt,name=updatePeriodSeconds"`
|
||||
// IntervalSeconds is the time to wait between polling deployment status
|
||||
// after update. If the value is nil, a default will be used.
|
||||
IntervalSeconds *int64 `json:"intervalSeconds,omitempty" protobuf:"varint,2,opt,name=intervalSeconds"`
|
||||
// TimeoutSeconds is the time to wait for updates before giving up. If the
|
||||
// value is nil, a default will be used.
|
||||
TimeoutSeconds *int64 `json:"timeoutSeconds,omitempty" protobuf:"varint,3,opt,name=timeoutSeconds"`
|
||||
// MaxUnavailable is the maximum number of pods that can be unavailable
|
||||
// during the update. Value can be an absolute number (ex: 5) or a
|
||||
// percentage of total pods at the start of update (ex: 10%). Absolute
|
||||
// number is calculated from percentage by rounding down.
|
||||
//
|
||||
// This cannot be 0 if MaxSurge is 0. By default, 25% is used.
|
||||
//
|
||||
// Example: when this is set to 30%, the old RC can be scaled down by 30%
|
||||
// immediately when the rolling update starts. Once new pods are ready, old
|
||||
// RC can be scaled down further, followed by scaling up the new RC,
|
||||
// ensuring that at least 70% of original number of pods are available at
|
||||
// all times during the update.
|
||||
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty" protobuf:"bytes,4,opt,name=maxUnavailable"`
|
||||
// MaxSurge is the maximum number of pods that can be scheduled above the
|
||||
// original number of pods. Value can be an absolute number (ex: 5) or a
|
||||
// percentage of total pods at the start of the update (ex: 10%). Absolute
|
||||
// number is calculated from percentage by rounding up.
|
||||
//
|
||||
// This cannot be 0 if MaxUnavailable is 0. By default, 25% is used.
|
||||
//
|
||||
// Example: when this is set to 30%, the new RC can be scaled up by 30%
|
||||
// immediately when the rolling update starts. Once old pods have been
|
||||
// killed, new RC can be scaled up further, ensuring that total number of
|
||||
// pods running at any time during the update is atmost 130% of original
|
||||
// pods.
|
||||
MaxSurge *intstr.IntOrString `json:"maxSurge,omitempty" protobuf:"bytes,5,opt,name=maxSurge"`
|
||||
// Pre is a lifecycle hook which is executed before the deployment process
|
||||
// begins. All LifecycleHookFailurePolicy values are supported.
|
||||
Pre *LifecycleHook `json:"pre,omitempty" protobuf:"bytes,7,opt,name=pre"`
|
||||
// Post is a lifecycle hook which is executed after the strategy has
|
||||
// finished all deployment logic. All LifecycleHookFailurePolicy values
|
||||
// are supported.
|
||||
Post *LifecycleHook `json:"post,omitempty" protobuf:"bytes,8,opt,name=post"`
|
||||
}
|
||||
|
||||
// LifecycleHook defines a specific deployment lifecycle action. Only one type of action may be specified at any time.
|
||||
type LifecycleHook struct {
|
||||
// FailurePolicy specifies what action to take if the hook fails.
|
||||
FailurePolicy LifecycleHookFailurePolicy `json:"failurePolicy" protobuf:"bytes,1,opt,name=failurePolicy,casttype=LifecycleHookFailurePolicy"`
|
||||
|
||||
// ExecNewPod specifies the options for a lifecycle hook backed by a pod.
|
||||
ExecNewPod *ExecNewPodHook `json:"execNewPod,omitempty" protobuf:"bytes,2,opt,name=execNewPod"`
|
||||
|
||||
// TagImages instructs the deployer to tag the current image referenced under a container onto an image stream tag.
|
||||
TagImages []TagImageHook `json:"tagImages,omitempty" protobuf:"bytes,3,rep,name=tagImages"`
|
||||
}
|
||||
|
||||
// LifecycleHookFailurePolicy describes possibles actions to take if a hook fails.
|
||||
type LifecycleHookFailurePolicy string
|
||||
|
||||
const (
|
||||
// LifecycleHookFailurePolicyRetry means retry the hook until it succeeds.
|
||||
LifecycleHookFailurePolicyRetry LifecycleHookFailurePolicy = "Retry"
|
||||
// LifecycleHookFailurePolicyAbort means abort the deployment.
|
||||
LifecycleHookFailurePolicyAbort LifecycleHookFailurePolicy = "Abort"
|
||||
// LifecycleHookFailurePolicyIgnore means ignore failure and continue the deployment.
|
||||
LifecycleHookFailurePolicyIgnore LifecycleHookFailurePolicy = "Ignore"
|
||||
)
|
||||
|
||||
// ExecNewPodHook is a hook implementation which runs a command in a new pod
|
||||
// based on the specified container which is assumed to be part of the
|
||||
// deployment template.
|
||||
type ExecNewPodHook struct {
|
||||
// Command is the action command and its arguments.
|
||||
Command []string `json:"command" protobuf:"bytes,1,rep,name=command"`
|
||||
// Env is a set of environment variables to supply to the hook pod's container.
|
||||
Env []corev1.EnvVar `json:"env,omitempty" protobuf:"bytes,2,rep,name=env"`
|
||||
// ContainerName is the name of a container in the deployment pod template
|
||||
// whose container image will be used for the hook pod's container.
|
||||
ContainerName string `json:"containerName" protobuf:"bytes,3,opt,name=containerName"`
|
||||
// Volumes is a list of named volumes from the pod template which should be
|
||||
// copied to the hook pod. Volumes names not found in pod spec are ignored.
|
||||
// An empty list means no volumes will be copied.
|
||||
Volumes []string `json:"volumes,omitempty" protobuf:"bytes,4,rep,name=volumes"`
|
||||
}
|
||||
|
||||
// TagImageHook is a request to tag the image in a particular container onto an ImageStreamTag.
|
||||
type TagImageHook struct {
|
||||
// ContainerName is the name of a container in the deployment config whose image value will be used as the source of the tag. If there is only a single
|
||||
// container this value will be defaulted to the name of that container.
|
||||
ContainerName string `json:"containerName" protobuf:"bytes,1,opt,name=containerName"`
|
||||
// To is the target ImageStreamTag to set the container's image onto.
|
||||
To corev1.ObjectReference `json:"to" protobuf:"bytes,2,opt,name=to"`
|
||||
}
|
||||
|
||||
// DeploymentTriggerPolicies is a list of policies where nil values and different from empty arrays.
|
||||
// +protobuf.nullable=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type DeploymentTriggerPolicies []DeploymentTriggerPolicy
|
||||
|
||||
func (t DeploymentTriggerPolicies) String() string {
|
||||
return fmt.Sprintf("%v", []DeploymentTriggerPolicy(t))
|
||||
}
|
||||
|
||||
// DeploymentTriggerPolicy describes a policy for a single trigger that results in a new deployment.
|
||||
type DeploymentTriggerPolicy struct {
|
||||
// Type of the trigger
|
||||
Type DeploymentTriggerType `json:"type,omitempty" protobuf:"bytes,1,opt,name=type,casttype=DeploymentTriggerType"`
|
||||
// ImageChangeParams represents the parameters for the ImageChange trigger.
|
||||
ImageChangeParams *DeploymentTriggerImageChangeParams `json:"imageChangeParams,omitempty" protobuf:"bytes,2,opt,name=imageChangeParams"`
|
||||
}
|
||||
|
||||
// DeploymentTriggerType refers to a specific DeploymentTriggerPolicy implementation.
|
||||
type DeploymentTriggerType string
|
||||
|
||||
const (
|
||||
// DeploymentTriggerOnImageChange will create new deployments in response to updated tags from
|
||||
// a container image repository.
|
||||
DeploymentTriggerOnImageChange DeploymentTriggerType = "ImageChange"
|
||||
// DeploymentTriggerOnConfigChange will create new deployments in response to changes to
|
||||
// the ControllerTemplate of a DeploymentConfig.
|
||||
DeploymentTriggerOnConfigChange DeploymentTriggerType = "ConfigChange"
|
||||
)
|
||||
|
||||
// DeploymentTriggerImageChangeParams represents the parameters to the ImageChange trigger.
|
||||
type DeploymentTriggerImageChangeParams struct {
|
||||
// Automatic means that the detection of a new tag value should result in an image update
|
||||
// inside the pod template.
|
||||
Automatic bool `json:"automatic,omitempty" protobuf:"varint,1,opt,name=automatic"`
|
||||
// ContainerNames is used to restrict tag updates to the specified set of container names in a pod.
|
||||
// If multiple triggers point to the same containers, the resulting behavior is undefined. Future
|
||||
// API versions will make this a validation error. If ContainerNames does not point to a valid container,
|
||||
// the trigger will be ignored. Future API versions will make this a validation error.
|
||||
ContainerNames []string `json:"containerNames,omitempty" protobuf:"bytes,2,rep,name=containerNames"`
|
||||
// From is a reference to an image stream tag to watch for changes. From.Name is the only
|
||||
// required subfield - if From.Namespace is blank, the namespace of the current deployment
|
||||
// trigger will be used.
|
||||
From corev1.ObjectReference `json:"from" protobuf:"bytes,3,opt,name=from"`
|
||||
// LastTriggeredImage is the last image to be triggered.
|
||||
LastTriggeredImage string `json:"lastTriggeredImage,omitempty" protobuf:"bytes,4,opt,name=lastTriggeredImage"`
|
||||
}
|
||||
|
||||
// DeploymentConfigStatus represents the current deployment state.
|
||||
type DeploymentConfigStatus struct {
|
||||
// LatestVersion is used to determine whether the current deployment associated with a deployment
|
||||
// config is out of sync.
|
||||
LatestVersion int64 `json:"latestVersion" protobuf:"varint,1,opt,name=latestVersion"`
|
||||
// ObservedGeneration is the most recent generation observed by the deployment config controller.
|
||||
ObservedGeneration int64 `json:"observedGeneration" protobuf:"varint,2,opt,name=observedGeneration"`
|
||||
// Replicas is the total number of pods targeted by this deployment config.
|
||||
Replicas int32 `json:"replicas" protobuf:"varint,3,opt,name=replicas"`
|
||||
// UpdatedReplicas is the total number of non-terminated pods targeted by this deployment config
|
||||
// that have the desired template spec.
|
||||
UpdatedReplicas int32 `json:"updatedReplicas" protobuf:"varint,4,opt,name=updatedReplicas"`
|
||||
// AvailableReplicas is the total number of available pods targeted by this deployment config.
|
||||
AvailableReplicas int32 `json:"availableReplicas" protobuf:"varint,5,opt,name=availableReplicas"`
|
||||
// UnavailableReplicas is the total number of unavailable pods targeted by this deployment config.
|
||||
UnavailableReplicas int32 `json:"unavailableReplicas" protobuf:"varint,6,opt,name=unavailableReplicas"`
|
||||
// Details are the reasons for the update to this deployment config.
|
||||
// This could be based on a change made by the user or caused by an automatic trigger
|
||||
Details *DeploymentDetails `json:"details,omitempty" protobuf:"bytes,7,opt,name=details"`
|
||||
// Conditions represents the latest available observations of a deployment config's current state.
|
||||
// +patchMergeKey=type
|
||||
// +patchStrategy=merge
|
||||
Conditions []DeploymentCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,8,rep,name=conditions"`
|
||||
// Total number of ready pods targeted by this deployment.
|
||||
ReadyReplicas int32 `json:"readyReplicas,omitempty" protobuf:"varint,9,opt,name=readyReplicas"`
|
||||
}
|
||||
|
||||
// DeploymentDetails captures information about the causes of a deployment.
|
||||
type DeploymentDetails struct {
|
||||
// Message is the user specified change message, if this deployment was triggered manually by the user
|
||||
Message string `json:"message,omitempty" protobuf:"bytes,1,opt,name=message"`
|
||||
// Causes are extended data associated with all the causes for creating a new deployment
|
||||
Causes []DeploymentCause `json:"causes" protobuf:"bytes,2,rep,name=causes"`
|
||||
}
|
||||
|
||||
// DeploymentCause captures information about a particular cause of a deployment.
|
||||
type DeploymentCause struct {
|
||||
// Type of the trigger that resulted in the creation of a new deployment
|
||||
Type DeploymentTriggerType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=DeploymentTriggerType"`
|
||||
// ImageTrigger contains the image trigger details, if this trigger was fired based on an image change
|
||||
ImageTrigger *DeploymentCauseImageTrigger `json:"imageTrigger,omitempty" protobuf:"bytes,2,opt,name=imageTrigger"`
|
||||
}
|
||||
|
||||
// DeploymentCauseImageTrigger represents details about the cause of a deployment originating
|
||||
// from an image change trigger
|
||||
type DeploymentCauseImageTrigger struct {
|
||||
// From is a reference to the changed object which triggered a deployment. The field may have
|
||||
// the kinds DockerImage, ImageStreamTag, or ImageStreamImage.
|
||||
From corev1.ObjectReference `json:"from" protobuf:"bytes,1,opt,name=from"`
|
||||
}
|
||||
|
||||
type DeploymentConditionType string
|
||||
|
||||
// These are valid conditions of a DeploymentConfig.
|
||||
const (
|
||||
// DeploymentAvailable means the DeploymentConfig is available, ie. at least the minimum available
|
||||
// replicas required (dc.spec.replicas in case the DeploymentConfig is of Recreate type,
|
||||
// dc.spec.replicas - dc.spec.strategy.rollingParams.maxUnavailable in case it's Rolling) are up and
|
||||
// running for at least dc.spec.minReadySeconds.
|
||||
DeploymentAvailable DeploymentConditionType = "Available"
|
||||
// DeploymentProgressing is:
|
||||
// * True: the DeploymentConfig has been successfully deployed or is amidst getting deployed.
|
||||
// The two different states can be determined by looking at the Reason of the Condition.
|
||||
// For example, a complete DC will have {Status: True, Reason: NewReplicationControllerAvailable}
|
||||
// and a DC in the middle of a rollout {Status: True, Reason: ReplicationControllerUpdated}.
|
||||
// TODO: Represent a successfully deployed DC by using something else for Status like Unknown?
|
||||
// * False: the DeploymentConfig has failed to deploy its latest version.
|
||||
//
|
||||
// This condition is purely informational and depends on the dc.spec.strategy.*params.timeoutSeconds
|
||||
// field, which is responsible for the time in seconds to wait for a rollout before deciding that
|
||||
// no progress can be made, thus the rollout is aborted.
|
||||
//
|
||||
// Progress for a DeploymentConfig is considered when new pods scale up or old pods scale down.
|
||||
DeploymentProgressing DeploymentConditionType = "Progressing"
|
||||
// DeploymentReplicaFailure is added in a deployment config when one of its pods
|
||||
// fails to be created or deleted.
|
||||
DeploymentReplicaFailure DeploymentConditionType = "ReplicaFailure"
|
||||
)
|
||||
|
||||
// DeploymentCondition describes the state of a deployment config at a certain point.
|
||||
type DeploymentCondition struct {
|
||||
// Type of deployment condition.
|
||||
Type DeploymentConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=DeploymentConditionType"`
|
||||
// Status of the condition, one of True, False, Unknown.
|
||||
Status corev1.ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=k8s.io/kubernetes/pkg/api/v1.ConditionStatus"`
|
||||
// The last time this condition was updated.
|
||||
LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty" protobuf:"bytes,6,opt,name=lastUpdateTime"`
|
||||
// The last time the condition transitioned from one status to another.
|
||||
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,3,opt,name=lastTransitionTime"`
|
||||
// The reason for the condition's last transition.
|
||||
Reason string `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason"`
|
||||
// A human readable message indicating details about the transition.
|
||||
Message string `json:"message,omitempty" protobuf:"bytes,5,opt,name=message"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// DeploymentConfigList is a collection of deployment configs.
|
||||
type DeploymentConfigList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Items is a list of deployment configs
|
||||
Items []DeploymentConfig `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// DeploymentConfigRollback provides the input to rollback generation.
|
||||
type DeploymentConfigRollback struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// Name of the deployment config that will be rolled back.
|
||||
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
|
||||
// UpdatedAnnotations is a set of new annotations that will be added in the deployment config.
|
||||
UpdatedAnnotations map[string]string `json:"updatedAnnotations,omitempty" protobuf:"bytes,2,rep,name=updatedAnnotations"`
|
||||
// Spec defines the options to rollback generation.
|
||||
Spec DeploymentConfigRollbackSpec `json:"spec" protobuf:"bytes,3,opt,name=spec"`
|
||||
}
|
||||
|
||||
// DeploymentConfigRollbackSpec represents the options for rollback generation.
|
||||
type DeploymentConfigRollbackSpec struct {
|
||||
// From points to a ReplicationController which is a deployment.
|
||||
From corev1.ObjectReference `json:"from" protobuf:"bytes,1,opt,name=from"`
|
||||
// Revision to rollback to. If set to 0, rollback to the last revision.
|
||||
Revision int64 `json:"revision,omitempty" protobuf:"varint,2,opt,name=revision"`
|
||||
// IncludeTriggers specifies whether to include config Triggers.
|
||||
IncludeTriggers bool `json:"includeTriggers" protobuf:"varint,3,opt,name=includeTriggers"`
|
||||
// IncludeTemplate specifies whether to include the PodTemplateSpec.
|
||||
IncludeTemplate bool `json:"includeTemplate" protobuf:"varint,4,opt,name=includeTemplate"`
|
||||
// IncludeReplicationMeta specifies whether to include the replica count and selector.
|
||||
IncludeReplicationMeta bool `json:"includeReplicationMeta" protobuf:"varint,5,opt,name=includeReplicationMeta"`
|
||||
// IncludeStrategy specifies whether to include the deployment Strategy.
|
||||
IncludeStrategy bool `json:"includeStrategy" protobuf:"varint,6,opt,name=includeStrategy"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// DeploymentRequest is a request to a deployment config for a new deployment.
|
||||
type DeploymentRequest struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// Name of the deployment config for requesting a new deployment.
|
||||
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
|
||||
// Latest will update the deployment config with the latest state from all triggers.
|
||||
Latest bool `json:"latest" protobuf:"varint,2,opt,name=latest"`
|
||||
// Force will try to force a new deployment to run. If the deployment config is paused,
|
||||
// then setting this to true will return an Invalid error.
|
||||
Force bool `json:"force" protobuf:"varint,3,opt,name=force"`
|
||||
// ExcludeTriggers instructs the instantiator to avoid processing the specified triggers.
|
||||
// This field overrides the triggers from latest and allows clients to control specific
|
||||
// logic. This field is ignored if not specified.
|
||||
ExcludeTriggers []DeploymentTriggerType `json:"excludeTriggers,omitempty" protobuf:"bytes,4,rep,name=excludeTriggers,casttype=DeploymentTriggerType"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// DeploymentLog represents the logs for a deployment
|
||||
type DeploymentLog struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// DeploymentLogOptions is the REST options for a deployment log
|
||||
type DeploymentLogOptions struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// The container for which to stream logs. Defaults to only container if there is one container in the pod.
|
||||
Container string `json:"container,omitempty" protobuf:"bytes,1,opt,name=container"`
|
||||
// Follow if true indicates that the build log should be streamed until
|
||||
// the build terminates.
|
||||
Follow bool `json:"follow,omitempty" protobuf:"varint,2,opt,name=follow"`
|
||||
// Return previous deployment logs. Defaults to false.
|
||||
Previous bool `json:"previous,omitempty" protobuf:"varint,3,opt,name=previous"`
|
||||
// A relative time in seconds before the current time from which to show logs. If this value
|
||||
// precedes the time a pod was started, only logs since the pod start will be returned.
|
||||
// If this value is in the future, no logs will be returned.
|
||||
// Only one of sinceSeconds or sinceTime may be specified.
|
||||
SinceSeconds *int64 `json:"sinceSeconds,omitempty" protobuf:"varint,4,opt,name=sinceSeconds"`
|
||||
// An RFC3339 timestamp from which to show logs. If this value
|
||||
// precedes the time a pod was started, only logs since the pod start will be returned.
|
||||
// If this value is in the future, no logs will be returned.
|
||||
// Only one of sinceSeconds or sinceTime may be specified.
|
||||
SinceTime *metav1.Time `json:"sinceTime,omitempty" protobuf:"bytes,5,opt,name=sinceTime"`
|
||||
// If true, add an RFC3339 or RFC3339Nano timestamp at the beginning of every line
|
||||
// of log output. Defaults to false.
|
||||
Timestamps bool `json:"timestamps,omitempty" protobuf:"varint,6,opt,name=timestamps"`
|
||||
// If set, the number of lines from the end of the logs to show. If not specified,
|
||||
// logs are shown from the creation of the container or sinceSeconds or sinceTime
|
||||
TailLines *int64 `json:"tailLines,omitempty" protobuf:"varint,7,opt,name=tailLines"`
|
||||
// If set, the number of bytes to read from the server before terminating the
|
||||
// log output. This may not display a complete final line of logging, and may return
|
||||
// slightly more or slightly less than the specified limit.
|
||||
LimitBytes *int64 `json:"limitBytes,omitempty" protobuf:"varint,8,opt,name=limitBytes"`
|
||||
|
||||
// NoWait if true causes the call to return immediately even if the deployment
|
||||
// is not available yet. Otherwise the server will wait until the deployment has started.
|
||||
// TODO: Fix the tag to 'noWait' in v2
|
||||
NoWait bool `json:"nowait,omitempty" protobuf:"varint,9,opt,name=nowait"`
|
||||
|
||||
// Version of the deployment for which to view logs.
|
||||
Version *int64 `json:"version,omitempty" protobuf:"varint,10,opt,name=version"`
|
||||
}
|
||||
+681
@@ -0,0 +1,681 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
intstr "k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomDeploymentStrategyParams) DeepCopyInto(out *CustomDeploymentStrategyParams) {
|
||||
*out = *in
|
||||
if in.Environment != nil {
|
||||
in, out := &in.Environment, &out.Environment
|
||||
*out = make([]corev1.EnvVar, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Command != nil {
|
||||
in, out := &in.Command, &out.Command
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomDeploymentStrategyParams.
|
||||
func (in *CustomDeploymentStrategyParams) DeepCopy() *CustomDeploymentStrategyParams {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomDeploymentStrategyParams)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentCause) DeepCopyInto(out *DeploymentCause) {
|
||||
*out = *in
|
||||
if in.ImageTrigger != nil {
|
||||
in, out := &in.ImageTrigger, &out.ImageTrigger
|
||||
*out = new(DeploymentCauseImageTrigger)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentCause.
|
||||
func (in *DeploymentCause) DeepCopy() *DeploymentCause {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentCause)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentCauseImageTrigger) DeepCopyInto(out *DeploymentCauseImageTrigger) {
|
||||
*out = *in
|
||||
out.From = in.From
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentCauseImageTrigger.
|
||||
func (in *DeploymentCauseImageTrigger) DeepCopy() *DeploymentCauseImageTrigger {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentCauseImageTrigger)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentCondition) DeepCopyInto(out *DeploymentCondition) {
|
||||
*out = *in
|
||||
in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime)
|
||||
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentCondition.
|
||||
func (in *DeploymentCondition) DeepCopy() *DeploymentCondition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentCondition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentConfig) DeepCopyInto(out *DeploymentConfig) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentConfig.
|
||||
func (in *DeploymentConfig) DeepCopy() *DeploymentConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *DeploymentConfig) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentConfigList) DeepCopyInto(out *DeploymentConfigList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]DeploymentConfig, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentConfigList.
|
||||
func (in *DeploymentConfigList) DeepCopy() *DeploymentConfigList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentConfigList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *DeploymentConfigList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentConfigRollback) DeepCopyInto(out *DeploymentConfigRollback) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.UpdatedAnnotations != nil {
|
||||
in, out := &in.UpdatedAnnotations, &out.UpdatedAnnotations
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
out.Spec = in.Spec
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentConfigRollback.
|
||||
func (in *DeploymentConfigRollback) DeepCopy() *DeploymentConfigRollback {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentConfigRollback)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *DeploymentConfigRollback) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentConfigRollbackSpec) DeepCopyInto(out *DeploymentConfigRollbackSpec) {
|
||||
*out = *in
|
||||
out.From = in.From
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentConfigRollbackSpec.
|
||||
func (in *DeploymentConfigRollbackSpec) DeepCopy() *DeploymentConfigRollbackSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentConfigRollbackSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentConfigSpec) DeepCopyInto(out *DeploymentConfigSpec) {
|
||||
*out = *in
|
||||
in.Strategy.DeepCopyInto(&out.Strategy)
|
||||
if in.Triggers != nil {
|
||||
in, out := &in.Triggers, &out.Triggers
|
||||
*out = make(DeploymentTriggerPolicies, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.RevisionHistoryLimit != nil {
|
||||
in, out := &in.RevisionHistoryLimit, &out.RevisionHistoryLimit
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
if in.Selector != nil {
|
||||
in, out := &in.Selector, &out.Selector
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Template != nil {
|
||||
in, out := &in.Template, &out.Template
|
||||
*out = new(corev1.PodTemplateSpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentConfigSpec.
|
||||
func (in *DeploymentConfigSpec) DeepCopy() *DeploymentConfigSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentConfigSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentConfigStatus) DeepCopyInto(out *DeploymentConfigStatus) {
|
||||
*out = *in
|
||||
if in.Details != nil {
|
||||
in, out := &in.Details, &out.Details
|
||||
*out = new(DeploymentDetails)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]DeploymentCondition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentConfigStatus.
|
||||
func (in *DeploymentConfigStatus) DeepCopy() *DeploymentConfigStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentConfigStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentDetails) DeepCopyInto(out *DeploymentDetails) {
|
||||
*out = *in
|
||||
if in.Causes != nil {
|
||||
in, out := &in.Causes, &out.Causes
|
||||
*out = make([]DeploymentCause, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentDetails.
|
||||
func (in *DeploymentDetails) DeepCopy() *DeploymentDetails {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentDetails)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentLog) DeepCopyInto(out *DeploymentLog) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentLog.
|
||||
func (in *DeploymentLog) DeepCopy() *DeploymentLog {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentLog)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *DeploymentLog) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentLogOptions) DeepCopyInto(out *DeploymentLogOptions) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.SinceSeconds != nil {
|
||||
in, out := &in.SinceSeconds, &out.SinceSeconds
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
if in.SinceTime != nil {
|
||||
in, out := &in.SinceTime, &out.SinceTime
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
if in.TailLines != nil {
|
||||
in, out := &in.TailLines, &out.TailLines
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
if in.LimitBytes != nil {
|
||||
in, out := &in.LimitBytes, &out.LimitBytes
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
if in.Version != nil {
|
||||
in, out := &in.Version, &out.Version
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentLogOptions.
|
||||
func (in *DeploymentLogOptions) DeepCopy() *DeploymentLogOptions {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentLogOptions)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *DeploymentLogOptions) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentRequest) DeepCopyInto(out *DeploymentRequest) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.ExcludeTriggers != nil {
|
||||
in, out := &in.ExcludeTriggers, &out.ExcludeTriggers
|
||||
*out = make([]DeploymentTriggerType, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentRequest.
|
||||
func (in *DeploymentRequest) DeepCopy() *DeploymentRequest {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentRequest)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *DeploymentRequest) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentStrategy) DeepCopyInto(out *DeploymentStrategy) {
|
||||
*out = *in
|
||||
if in.CustomParams != nil {
|
||||
in, out := &in.CustomParams, &out.CustomParams
|
||||
*out = new(CustomDeploymentStrategyParams)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.RecreateParams != nil {
|
||||
in, out := &in.RecreateParams, &out.RecreateParams
|
||||
*out = new(RecreateDeploymentStrategyParams)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.RollingParams != nil {
|
||||
in, out := &in.RollingParams, &out.RollingParams
|
||||
*out = new(RollingDeploymentStrategyParams)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
in.Resources.DeepCopyInto(&out.Resources)
|
||||
if in.Labels != nil {
|
||||
in, out := &in.Labels, &out.Labels
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Annotations != nil {
|
||||
in, out := &in.Annotations, &out.Annotations
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.ActiveDeadlineSeconds != nil {
|
||||
in, out := &in.ActiveDeadlineSeconds, &out.ActiveDeadlineSeconds
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentStrategy.
|
||||
func (in *DeploymentStrategy) DeepCopy() *DeploymentStrategy {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentStrategy)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentTriggerImageChangeParams) DeepCopyInto(out *DeploymentTriggerImageChangeParams) {
|
||||
*out = *in
|
||||
if in.ContainerNames != nil {
|
||||
in, out := &in.ContainerNames, &out.ContainerNames
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.From = in.From
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentTriggerImageChangeParams.
|
||||
func (in *DeploymentTriggerImageChangeParams) DeepCopy() *DeploymentTriggerImageChangeParams {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentTriggerImageChangeParams)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in DeploymentTriggerPolicies) DeepCopyInto(out *DeploymentTriggerPolicies) {
|
||||
{
|
||||
in := &in
|
||||
*out = make(DeploymentTriggerPolicies, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentTriggerPolicies.
|
||||
func (in DeploymentTriggerPolicies) DeepCopy() DeploymentTriggerPolicies {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentTriggerPolicies)
|
||||
in.DeepCopyInto(out)
|
||||
return *out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentTriggerPolicy) DeepCopyInto(out *DeploymentTriggerPolicy) {
|
||||
*out = *in
|
||||
if in.ImageChangeParams != nil {
|
||||
in, out := &in.ImageChangeParams, &out.ImageChangeParams
|
||||
*out = new(DeploymentTriggerImageChangeParams)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentTriggerPolicy.
|
||||
func (in *DeploymentTriggerPolicy) DeepCopy() *DeploymentTriggerPolicy {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeploymentTriggerPolicy)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExecNewPodHook) DeepCopyInto(out *ExecNewPodHook) {
|
||||
*out = *in
|
||||
if in.Command != nil {
|
||||
in, out := &in.Command, &out.Command
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Env != nil {
|
||||
in, out := &in.Env, &out.Env
|
||||
*out = make([]corev1.EnvVar, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Volumes != nil {
|
||||
in, out := &in.Volumes, &out.Volumes
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecNewPodHook.
|
||||
func (in *ExecNewPodHook) DeepCopy() *ExecNewPodHook {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExecNewPodHook)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LifecycleHook) DeepCopyInto(out *LifecycleHook) {
|
||||
*out = *in
|
||||
if in.ExecNewPod != nil {
|
||||
in, out := &in.ExecNewPod, &out.ExecNewPod
|
||||
*out = new(ExecNewPodHook)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.TagImages != nil {
|
||||
in, out := &in.TagImages, &out.TagImages
|
||||
*out = make([]TagImageHook, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LifecycleHook.
|
||||
func (in *LifecycleHook) DeepCopy() *LifecycleHook {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(LifecycleHook)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RecreateDeploymentStrategyParams) DeepCopyInto(out *RecreateDeploymentStrategyParams) {
|
||||
*out = *in
|
||||
if in.TimeoutSeconds != nil {
|
||||
in, out := &in.TimeoutSeconds, &out.TimeoutSeconds
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
if in.Pre != nil {
|
||||
in, out := &in.Pre, &out.Pre
|
||||
*out = new(LifecycleHook)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Mid != nil {
|
||||
in, out := &in.Mid, &out.Mid
|
||||
*out = new(LifecycleHook)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Post != nil {
|
||||
in, out := &in.Post, &out.Post
|
||||
*out = new(LifecycleHook)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RecreateDeploymentStrategyParams.
|
||||
func (in *RecreateDeploymentStrategyParams) DeepCopy() *RecreateDeploymentStrategyParams {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RecreateDeploymentStrategyParams)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RollingDeploymentStrategyParams) DeepCopyInto(out *RollingDeploymentStrategyParams) {
|
||||
*out = *in
|
||||
if in.UpdatePeriodSeconds != nil {
|
||||
in, out := &in.UpdatePeriodSeconds, &out.UpdatePeriodSeconds
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
if in.IntervalSeconds != nil {
|
||||
in, out := &in.IntervalSeconds, &out.IntervalSeconds
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
if in.TimeoutSeconds != nil {
|
||||
in, out := &in.TimeoutSeconds, &out.TimeoutSeconds
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
if in.MaxUnavailable != nil {
|
||||
in, out := &in.MaxUnavailable, &out.MaxUnavailable
|
||||
*out = new(intstr.IntOrString)
|
||||
**out = **in
|
||||
}
|
||||
if in.MaxSurge != nil {
|
||||
in, out := &in.MaxSurge, &out.MaxSurge
|
||||
*out = new(intstr.IntOrString)
|
||||
**out = **in
|
||||
}
|
||||
if in.Pre != nil {
|
||||
in, out := &in.Pre, &out.Pre
|
||||
*out = new(LifecycleHook)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Post != nil {
|
||||
in, out := &in.Post, &out.Post
|
||||
*out = new(LifecycleHook)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollingDeploymentStrategyParams.
|
||||
func (in *RollingDeploymentStrategyParams) DeepCopy() *RollingDeploymentStrategyParams {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RollingDeploymentStrategyParams)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TagImageHook) DeepCopyInto(out *TagImageHook) {
|
||||
*out = *in
|
||||
out.To = in.To
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TagImageHook.
|
||||
func (in *TagImageHook) DeepCopy() *TagImageHook {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TagImageHook)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
package v1
|
||||
|
||||
// This file contains a collection of methods that can be used from go-restful to
|
||||
// generate Swagger API documentation for its models. Please read this PR for more
|
||||
// information on the implementation: https://github.com/emicklei/go-restful/pull/215
|
||||
//
|
||||
// TODOs are ignored from the parser (e.g. TODO(andronat):... || TODO:...) if and only if
|
||||
// they are on one line! For multiple line or blocks that you want to ignore use ---.
|
||||
// Any context after a --- is ignored.
|
||||
//
|
||||
// Those methods can be generated by using hack/update-swagger-docs.sh
|
||||
|
||||
// AUTO-GENERATED FUNCTIONS START HERE
|
||||
var map_CustomDeploymentStrategyParams = map[string]string{
|
||||
"": "CustomDeploymentStrategyParams are the input to the Custom deployment strategy.",
|
||||
"image": "Image specifies a container image which can carry out a deployment.",
|
||||
"environment": "Environment holds the environment which will be given to the container for Image.",
|
||||
"command": "Command is optional and overrides CMD in the container Image.",
|
||||
}
|
||||
|
||||
func (CustomDeploymentStrategyParams) SwaggerDoc() map[string]string {
|
||||
return map_CustomDeploymentStrategyParams
|
||||
}
|
||||
|
||||
var map_DeploymentCause = map[string]string{
|
||||
"": "DeploymentCause captures information about a particular cause of a deployment.",
|
||||
"type": "Type of the trigger that resulted in the creation of a new deployment",
|
||||
"imageTrigger": "ImageTrigger contains the image trigger details, if this trigger was fired based on an image change",
|
||||
}
|
||||
|
||||
func (DeploymentCause) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentCause
|
||||
}
|
||||
|
||||
var map_DeploymentCauseImageTrigger = map[string]string{
|
||||
"": "DeploymentCauseImageTrigger represents details about the cause of a deployment originating from an image change trigger",
|
||||
"from": "From is a reference to the changed object which triggered a deployment. The field may have the kinds DockerImage, ImageStreamTag, or ImageStreamImage.",
|
||||
}
|
||||
|
||||
func (DeploymentCauseImageTrigger) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentCauseImageTrigger
|
||||
}
|
||||
|
||||
var map_DeploymentCondition = map[string]string{
|
||||
"": "DeploymentCondition describes the state of a deployment config at a certain point.",
|
||||
"type": "Type of deployment condition.",
|
||||
"status": "Status of the condition, one of True, False, Unknown.",
|
||||
"lastUpdateTime": "The last time this condition was updated.",
|
||||
"lastTransitionTime": "The last time the condition transitioned from one status to another.",
|
||||
"reason": "The reason for the condition's last transition.",
|
||||
"message": "A human readable message indicating details about the transition.",
|
||||
}
|
||||
|
||||
func (DeploymentCondition) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentCondition
|
||||
}
|
||||
|
||||
var map_DeploymentConfig = map[string]string{
|
||||
"": "Deployment Configs define the template for a pod and manages deploying new images or configuration changes. A single deployment configuration is usually analogous to a single micro-service. Can support many different deployment patterns, including full restart, customizable rolling updates, and fully custom behaviors, as well as pre- and post- deployment hooks. Each individual deployment is represented as a replication controller.\n\nA deployment is \"triggered\" when its configuration is changed or a tag in an Image Stream is changed. Triggers can be disabled to allow manual control over a deployment. The \"strategy\" determines how the deployment is carried out and may be changed at any time. The `latestVersion` field is updated when a new deployment is triggered by any means.",
|
||||
"spec": "Spec represents a desired deployment state and how to deploy to it.",
|
||||
"status": "Status represents the current deployment state.",
|
||||
}
|
||||
|
||||
func (DeploymentConfig) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentConfig
|
||||
}
|
||||
|
||||
var map_DeploymentConfigList = map[string]string{
|
||||
"": "DeploymentConfigList is a collection of deployment configs.",
|
||||
"items": "Items is a list of deployment configs",
|
||||
}
|
||||
|
||||
func (DeploymentConfigList) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentConfigList
|
||||
}
|
||||
|
||||
var map_DeploymentConfigRollback = map[string]string{
|
||||
"": "DeploymentConfigRollback provides the input to rollback generation.",
|
||||
"name": "Name of the deployment config that will be rolled back.",
|
||||
"updatedAnnotations": "UpdatedAnnotations is a set of new annotations that will be added in the deployment config.",
|
||||
"spec": "Spec defines the options to rollback generation.",
|
||||
}
|
||||
|
||||
func (DeploymentConfigRollback) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentConfigRollback
|
||||
}
|
||||
|
||||
var map_DeploymentConfigRollbackSpec = map[string]string{
|
||||
"": "DeploymentConfigRollbackSpec represents the options for rollback generation.",
|
||||
"from": "From points to a ReplicationController which is a deployment.",
|
||||
"revision": "Revision to rollback to. If set to 0, rollback to the last revision.",
|
||||
"includeTriggers": "IncludeTriggers specifies whether to include config Triggers.",
|
||||
"includeTemplate": "IncludeTemplate specifies whether to include the PodTemplateSpec.",
|
||||
"includeReplicationMeta": "IncludeReplicationMeta specifies whether to include the replica count and selector.",
|
||||
"includeStrategy": "IncludeStrategy specifies whether to include the deployment Strategy.",
|
||||
}
|
||||
|
||||
func (DeploymentConfigRollbackSpec) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentConfigRollbackSpec
|
||||
}
|
||||
|
||||
var map_DeploymentConfigSpec = map[string]string{
|
||||
"": "DeploymentConfigSpec represents the desired state of the deployment.",
|
||||
"strategy": "Strategy describes how a deployment is executed.",
|
||||
"minReadySeconds": "MinReadySeconds is the minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready)",
|
||||
"triggers": "Triggers determine how updates to a DeploymentConfig result in new deployments. If no triggers are defined, a new deployment can only occur as a result of an explicit client update to the DeploymentConfig with a new LatestVersion. If null, defaults to having a config change trigger.",
|
||||
"replicas": "Replicas is the number of desired replicas.",
|
||||
"revisionHistoryLimit": "RevisionHistoryLimit is the number of old ReplicationControllers to retain to allow for rollbacks. This field is a pointer to allow for differentiation between an explicit zero and not specified. Defaults to 10. (This only applies to DeploymentConfigs created via the new group API resource, not the legacy resource.)",
|
||||
"test": "Test ensures that this deployment config will have zero replicas except while a deployment is running. This allows the deployment config to be used as a continuous deployment test - triggering on images, running the deployment, and then succeeding or failing. Post strategy hooks and After actions can be used to integrate successful deployment with an action.",
|
||||
"paused": "Paused indicates that the deployment config is paused resulting in no new deployments on template changes or changes in the template caused by other triggers.",
|
||||
"selector": "Selector is a label query over pods that should match the Replicas count.",
|
||||
"template": "Template is the object that describes the pod that will be created if insufficient replicas are detected.",
|
||||
}
|
||||
|
||||
func (DeploymentConfigSpec) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentConfigSpec
|
||||
}
|
||||
|
||||
var map_DeploymentConfigStatus = map[string]string{
|
||||
"": "DeploymentConfigStatus represents the current deployment state.",
|
||||
"latestVersion": "LatestVersion is used to determine whether the current deployment associated with a deployment config is out of sync.",
|
||||
"observedGeneration": "ObservedGeneration is the most recent generation observed by the deployment config controller.",
|
||||
"replicas": "Replicas is the total number of pods targeted by this deployment config.",
|
||||
"updatedReplicas": "UpdatedReplicas is the total number of non-terminated pods targeted by this deployment config that have the desired template spec.",
|
||||
"availableReplicas": "AvailableReplicas is the total number of available pods targeted by this deployment config.",
|
||||
"unavailableReplicas": "UnavailableReplicas is the total number of unavailable pods targeted by this deployment config.",
|
||||
"details": "Details are the reasons for the update to this deployment config. This could be based on a change made by the user or caused by an automatic trigger",
|
||||
"conditions": "Conditions represents the latest available observations of a deployment config's current state.",
|
||||
"readyReplicas": "Total number of ready pods targeted by this deployment.",
|
||||
}
|
||||
|
||||
func (DeploymentConfigStatus) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentConfigStatus
|
||||
}
|
||||
|
||||
var map_DeploymentDetails = map[string]string{
|
||||
"": "DeploymentDetails captures information about the causes of a deployment.",
|
||||
"message": "Message is the user specified change message, if this deployment was triggered manually by the user",
|
||||
"causes": "Causes are extended data associated with all the causes for creating a new deployment",
|
||||
}
|
||||
|
||||
func (DeploymentDetails) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentDetails
|
||||
}
|
||||
|
||||
var map_DeploymentLog = map[string]string{
|
||||
"": "DeploymentLog represents the logs for a deployment",
|
||||
}
|
||||
|
||||
func (DeploymentLog) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentLog
|
||||
}
|
||||
|
||||
var map_DeploymentLogOptions = map[string]string{
|
||||
"": "DeploymentLogOptions is the REST options for a deployment log",
|
||||
"container": "The container for which to stream logs. Defaults to only container if there is one container in the pod.",
|
||||
"follow": "Follow if true indicates that the build log should be streamed until the build terminates.",
|
||||
"previous": "Return previous deployment logs. Defaults to false.",
|
||||
"sinceSeconds": "A relative time in seconds before the current time from which to show logs. If this value precedes the time a pod was started, only logs since the pod start will be returned. If this value is in the future, no logs will be returned. Only one of sinceSeconds or sinceTime may be specified.",
|
||||
"sinceTime": "An RFC3339 timestamp from which to show logs. If this value precedes the time a pod was started, only logs since the pod start will be returned. If this value is in the future, no logs will be returned. Only one of sinceSeconds or sinceTime may be specified.",
|
||||
"timestamps": "If true, add an RFC3339 or RFC3339Nano timestamp at the beginning of every line of log output. Defaults to false.",
|
||||
"tailLines": "If set, the number of lines from the end of the logs to show. If not specified, logs are shown from the creation of the container or sinceSeconds or sinceTime",
|
||||
"limitBytes": "If set, the number of bytes to read from the server before terminating the log output. This may not display a complete final line of logging, and may return slightly more or slightly less than the specified limit.",
|
||||
"nowait": "NoWait if true causes the call to return immediately even if the deployment is not available yet. Otherwise the server will wait until the deployment has started.",
|
||||
"version": "Version of the deployment for which to view logs.",
|
||||
}
|
||||
|
||||
func (DeploymentLogOptions) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentLogOptions
|
||||
}
|
||||
|
||||
var map_DeploymentRequest = map[string]string{
|
||||
"": "DeploymentRequest is a request to a deployment config for a new deployment.",
|
||||
"name": "Name of the deployment config for requesting a new deployment.",
|
||||
"latest": "Latest will update the deployment config with the latest state from all triggers.",
|
||||
"force": "Force will try to force a new deployment to run. If the deployment config is paused, then setting this to true will return an Invalid error.",
|
||||
"excludeTriggers": "ExcludeTriggers instructs the instantiator to avoid processing the specified triggers. This field overrides the triggers from latest and allows clients to control specific logic. This field is ignored if not specified.",
|
||||
}
|
||||
|
||||
func (DeploymentRequest) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentRequest
|
||||
}
|
||||
|
||||
var map_DeploymentStrategy = map[string]string{
|
||||
"": "DeploymentStrategy describes how to perform a deployment.",
|
||||
"type": "Type is the name of a deployment strategy.",
|
||||
"customParams": "CustomParams are the input to the Custom deployment strategy, and may also be specified for the Recreate and Rolling strategies to customize the execution process that runs the deployment.",
|
||||
"recreateParams": "RecreateParams are the input to the Recreate deployment strategy.",
|
||||
"rollingParams": "RollingParams are the input to the Rolling deployment strategy.",
|
||||
"resources": "Resources contains resource requirements to execute the deployment and any hooks.",
|
||||
"labels": "Labels is a set of key, value pairs added to custom deployer and lifecycle pre/post hook pods.",
|
||||
"annotations": "Annotations is a set of key, value pairs added to custom deployer and lifecycle pre/post hook pods.",
|
||||
"activeDeadlineSeconds": "ActiveDeadlineSeconds is the duration in seconds that the deployer pods for this deployment config may be active on a node before the system actively tries to terminate them.",
|
||||
}
|
||||
|
||||
func (DeploymentStrategy) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentStrategy
|
||||
}
|
||||
|
||||
var map_DeploymentTriggerImageChangeParams = map[string]string{
|
||||
"": "DeploymentTriggerImageChangeParams represents the parameters to the ImageChange trigger.",
|
||||
"automatic": "Automatic means that the detection of a new tag value should result in an image update inside the pod template.",
|
||||
"containerNames": "ContainerNames is used to restrict tag updates to the specified set of container names in a pod. If multiple triggers point to the same containers, the resulting behavior is undefined. Future API versions will make this a validation error. If ContainerNames does not point to a valid container, the trigger will be ignored. Future API versions will make this a validation error.",
|
||||
"from": "From is a reference to an image stream tag to watch for changes. From.Name is the only required subfield - if From.Namespace is blank, the namespace of the current deployment trigger will be used.",
|
||||
"lastTriggeredImage": "LastTriggeredImage is the last image to be triggered.",
|
||||
}
|
||||
|
||||
func (DeploymentTriggerImageChangeParams) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentTriggerImageChangeParams
|
||||
}
|
||||
|
||||
var map_DeploymentTriggerPolicy = map[string]string{
|
||||
"": "DeploymentTriggerPolicy describes a policy for a single trigger that results in a new deployment.",
|
||||
"type": "Type of the trigger",
|
||||
"imageChangeParams": "ImageChangeParams represents the parameters for the ImageChange trigger.",
|
||||
}
|
||||
|
||||
func (DeploymentTriggerPolicy) SwaggerDoc() map[string]string {
|
||||
return map_DeploymentTriggerPolicy
|
||||
}
|
||||
|
||||
var map_ExecNewPodHook = map[string]string{
|
||||
"": "ExecNewPodHook is a hook implementation which runs a command in a new pod based on the specified container which is assumed to be part of the deployment template.",
|
||||
"command": "Command is the action command and its arguments.",
|
||||
"env": "Env is a set of environment variables to supply to the hook pod's container.",
|
||||
"containerName": "ContainerName is the name of a container in the deployment pod template whose container image will be used for the hook pod's container.",
|
||||
"volumes": "Volumes is a list of named volumes from the pod template which should be copied to the hook pod. Volumes names not found in pod spec are ignored. An empty list means no volumes will be copied.",
|
||||
}
|
||||
|
||||
func (ExecNewPodHook) SwaggerDoc() map[string]string {
|
||||
return map_ExecNewPodHook
|
||||
}
|
||||
|
||||
var map_LifecycleHook = map[string]string{
|
||||
"": "LifecycleHook defines a specific deployment lifecycle action. Only one type of action may be specified at any time.",
|
||||
"failurePolicy": "FailurePolicy specifies what action to take if the hook fails.",
|
||||
"execNewPod": "ExecNewPod specifies the options for a lifecycle hook backed by a pod.",
|
||||
"tagImages": "TagImages instructs the deployer to tag the current image referenced under a container onto an image stream tag.",
|
||||
}
|
||||
|
||||
func (LifecycleHook) SwaggerDoc() map[string]string {
|
||||
return map_LifecycleHook
|
||||
}
|
||||
|
||||
var map_RecreateDeploymentStrategyParams = map[string]string{
|
||||
"": "RecreateDeploymentStrategyParams are the input to the Recreate deployment strategy.",
|
||||
"timeoutSeconds": "TimeoutSeconds is the time to wait for updates before giving up. If the value is nil, a default will be used.",
|
||||
"pre": "Pre is a lifecycle hook which is executed before the strategy manipulates the deployment. All LifecycleHookFailurePolicy values are supported.",
|
||||
"mid": "Mid is a lifecycle hook which is executed while the deployment is scaled down to zero before the first new pod is created. All LifecycleHookFailurePolicy values are supported.",
|
||||
"post": "Post is a lifecycle hook which is executed after the strategy has finished all deployment logic. All LifecycleHookFailurePolicy values are supported.",
|
||||
}
|
||||
|
||||
func (RecreateDeploymentStrategyParams) SwaggerDoc() map[string]string {
|
||||
return map_RecreateDeploymentStrategyParams
|
||||
}
|
||||
|
||||
var map_RollingDeploymentStrategyParams = map[string]string{
|
||||
"": "RollingDeploymentStrategyParams are the input to the Rolling deployment strategy.",
|
||||
"updatePeriodSeconds": "UpdatePeriodSeconds is the time to wait between individual pod updates. If the value is nil, a default will be used.",
|
||||
"intervalSeconds": "IntervalSeconds is the time to wait between polling deployment status after update. If the value is nil, a default will be used.",
|
||||
"timeoutSeconds": "TimeoutSeconds is the time to wait for updates before giving up. If the value is nil, a default will be used.",
|
||||
"maxUnavailable": "MaxUnavailable is the maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of total pods at the start of update (ex: 10%). Absolute number is calculated from percentage by rounding down.\n\nThis cannot be 0 if MaxSurge is 0. By default, 25% is used.\n\nExample: when this is set to 30%, the old RC can be scaled down by 30% immediately when the rolling update starts. Once new pods are ready, old RC can be scaled down further, followed by scaling up the new RC, ensuring that at least 70% of original number of pods are available at all times during the update.",
|
||||
"maxSurge": "MaxSurge is the maximum number of pods that can be scheduled above the original number of pods. Value can be an absolute number (ex: 5) or a percentage of total pods at the start of the update (ex: 10%). Absolute number is calculated from percentage by rounding up.\n\nThis cannot be 0 if MaxUnavailable is 0. By default, 25% is used.\n\nExample: when this is set to 30%, the new RC can be scaled up by 30% immediately when the rolling update starts. Once old pods have been killed, new RC can be scaled up further, ensuring that total number of pods running at any time during the update is atmost 130% of original pods.",
|
||||
"pre": "Pre is a lifecycle hook which is executed before the deployment process begins. All LifecycleHookFailurePolicy values are supported.",
|
||||
"post": "Post is a lifecycle hook which is executed after the strategy has finished all deployment logic. All LifecycleHookFailurePolicy values are supported.",
|
||||
}
|
||||
|
||||
func (RollingDeploymentStrategyParams) SwaggerDoc() map[string]string {
|
||||
return map_RollingDeploymentStrategyParams
|
||||
}
|
||||
|
||||
var map_TagImageHook = map[string]string{
|
||||
"": "TagImageHook is a request to tag the image in a particular container onto an ImageStreamTag.",
|
||||
"containerName": "ContainerName is the name of a container in the deployment config whose image value will be used as the source of the tag. If there is only a single container this value will be defaulted to the name of that container.",
|
||||
"to": "To is the target ImageStreamTag to set the container's image onto.",
|
||||
}
|
||||
|
||||
func (TagImageHook) SwaggerDoc() map[string]string {
|
||||
return map_TagImageHook
|
||||
}
|
||||
|
||||
// AUTO-GENERATED FUNCTIONS END HERE
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package authorization
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
authorizationv1 "github.com/openshift/api/authorization/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
GroupName = "authorization.openshift.io"
|
||||
)
|
||||
|
||||
var (
|
||||
schemeBuilder = runtime.NewSchemeBuilder(authorizationv1.Install)
|
||||
// Install is a function which adds every version of this group to a scheme
|
||||
Install = schemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return schema.GroupResource{Group: GroupName, Resource: resource}
|
||||
}
|
||||
|
||||
func Kind(kind string) schema.GroupKind {
|
||||
return schema.GroupKind{Group: GroupName, Kind: kind}
|
||||
}
|
||||
Generated
Vendored
+205
@@ -0,0 +1,205 @@
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: rolebindingrestrictions.authorization.openshift.io
|
||||
spec:
|
||||
group: authorization.openshift.io
|
||||
names:
|
||||
kind: RoleBindingRestriction
|
||||
listKind: RoleBindingRestrictionList
|
||||
plural: rolebindingrestrictions
|
||||
singular: rolebindingrestriction
|
||||
scope: Namespaced
|
||||
preserveUnknownFields: false
|
||||
versions:
|
||||
- name: v1
|
||||
served: true
|
||||
storage: true
|
||||
"validation":
|
||||
"openAPIV3Schema":
|
||||
description: RoleBindingRestriction is an object that can be matched against
|
||||
a subject (user, group, or service account) to determine whether rolebindings
|
||||
on that subject are allowed in the namespace to which the RoleBindingRestriction
|
||||
belongs. If any one of those RoleBindingRestriction objects matches a subject,
|
||||
rolebindings on that subject in the namespace are allowed.
|
||||
type: object
|
||||
properties:
|
||||
apiVersion:
|
||||
description: '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: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: '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: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec defines the matcher.
|
||||
type: object
|
||||
properties:
|
||||
grouprestriction:
|
||||
description: GroupRestriction matches against group subjects.
|
||||
type: object
|
||||
properties:
|
||||
groups:
|
||||
description: Groups is a list of groups used to match against an
|
||||
individual user's groups. If the user is a member of one of the
|
||||
whitelisted groups, the user is allowed to be bound to a role.
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
labels:
|
||||
description: Selectors specifies a list of label selectors over
|
||||
group labels.
|
||||
type: array
|
||||
items:
|
||||
description: A label selector is a label query over a set of resources.
|
||||
The result of matchLabels and matchExpressions are ANDed. An
|
||||
empty label selector matches all objects. A null label selector
|
||||
matches no objects.
|
||||
type: object
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label selector
|
||||
requirements. The requirements are ANDed.
|
||||
type: array
|
||||
items:
|
||||
description: A label selector requirement is a selector
|
||||
that contains values, a key, and an operator that relates
|
||||
the key and values.
|
||||
type: object
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the selector
|
||||
applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are In, NotIn,
|
||||
Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string values. If
|
||||
the operator is In or NotIn, the values array must
|
||||
be non-empty. If the operator is Exists or DoesNotExist,
|
||||
the values array must be empty. This array is replaced
|
||||
during a strategic merge patch.
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
matchLabels:
|
||||
description: matchLabels is a map of {key,value} pairs. A
|
||||
single {key,value} in the matchLabels map is equivalent
|
||||
to an element of matchExpressions, whose key field is "key",
|
||||
the operator is "In", and the values array contains only
|
||||
"value". The requirements are ANDed.
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: string
|
||||
nullable: true
|
||||
nullable: true
|
||||
serviceaccountrestriction:
|
||||
description: ServiceAccountRestriction matches against service-account
|
||||
subjects.
|
||||
type: object
|
||||
properties:
|
||||
namespaces:
|
||||
description: Namespaces specifies a list of literal namespace names.
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
serviceaccounts:
|
||||
description: ServiceAccounts specifies a list of literal service-account
|
||||
names.
|
||||
type: array
|
||||
items:
|
||||
description: ServiceAccountReference specifies a service account
|
||||
and namespace by their names.
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: Name is the name of the service account.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the namespace of the service account. Service
|
||||
accounts from inside the whitelisted namespaces are allowed
|
||||
to be bound to roles. If Namespace is empty, then the namespace
|
||||
of the RoleBindingRestriction in which the ServiceAccountReference
|
||||
is embedded is used.
|
||||
type: string
|
||||
nullable: true
|
||||
userrestriction:
|
||||
description: UserRestriction matches against user subjects.
|
||||
type: object
|
||||
properties:
|
||||
groups:
|
||||
description: Groups specifies a list of literal group names.
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
labels:
|
||||
description: Selectors specifies a list of label selectors over
|
||||
user labels.
|
||||
type: array
|
||||
items:
|
||||
description: A label selector is a label query over a set of resources.
|
||||
The result of matchLabels and matchExpressions are ANDed. An
|
||||
empty label selector matches all objects. A null label selector
|
||||
matches no objects.
|
||||
type: object
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label selector
|
||||
requirements. The requirements are ANDed.
|
||||
type: array
|
||||
items:
|
||||
description: A label selector requirement is a selector
|
||||
that contains values, a key, and an operator that relates
|
||||
the key and values.
|
||||
type: object
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the selector
|
||||
applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are In, NotIn,
|
||||
Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string values. If
|
||||
the operator is In or NotIn, the values array must
|
||||
be non-empty. If the operator is Exists or DoesNotExist,
|
||||
the values array must be empty. This array is replaced
|
||||
during a strategic merge patch.
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
matchLabels:
|
||||
description: matchLabels is a map of {key,value} pairs. A
|
||||
single {key,value} in the matchLabels map is equivalent
|
||||
to an element of matchExpressions, whose key field is "key",
|
||||
the operator is "In", and the values array contains only
|
||||
"value". The requirements are ANDed.
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: string
|
||||
nullable: true
|
||||
users:
|
||||
description: Users specifies a list of literal user names.
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/openshift/api/pkg/serialization"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var _ runtime.NestedObjectDecoder = &PolicyRule{}
|
||||
var _ runtime.NestedObjectEncoder = &PolicyRule{}
|
||||
|
||||
func (c *PolicyRule) DecodeNestedObjects(d runtime.Decoder) error {
|
||||
// decoding failures result in a runtime.Unknown object being created in Object and passed
|
||||
// to conversion
|
||||
serialization.DecodeNestedRawExtensionOrUnknown(d, &c.AttributeRestrictions)
|
||||
return nil
|
||||
}
|
||||
func (c *PolicyRule) EncodeNestedObjects(e runtime.Encoder) error {
|
||||
return serialization.EncodeNestedRawExtension(e, &c.AttributeRestrictions)
|
||||
}
|
||||
|
||||
var _ runtime.NestedObjectDecoder = &SelfSubjectRulesReview{}
|
||||
var _ runtime.NestedObjectEncoder = &SelfSubjectRulesReview{}
|
||||
|
||||
func (c *SelfSubjectRulesReview) DecodeNestedObjects(d runtime.Decoder) error {
|
||||
// decoding failures result in a runtime.Unknown object being created in Object and passed
|
||||
// to conversion
|
||||
for i := range c.Status.Rules {
|
||||
c.Status.Rules[i].DecodeNestedObjects(d)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (c *SelfSubjectRulesReview) EncodeNestedObjects(e runtime.Encoder) error {
|
||||
for i := range c.Status.Rules {
|
||||
if err := c.Status.Rules[i].EncodeNestedObjects(e); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ runtime.NestedObjectDecoder = &SubjectRulesReview{}
|
||||
var _ runtime.NestedObjectEncoder = &SubjectRulesReview{}
|
||||
|
||||
func (c *SubjectRulesReview) DecodeNestedObjects(d runtime.Decoder) error {
|
||||
// decoding failures result in a runtime.Unknown object being created in Object and passed
|
||||
// to conversion
|
||||
for i := range c.Status.Rules {
|
||||
c.Status.Rules[i].DecodeNestedObjects(d)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (c *SubjectRulesReview) EncodeNestedObjects(e runtime.Encoder) error {
|
||||
for i := range c.Status.Rules {
|
||||
if err := c.Status.Rules[i].EncodeNestedObjects(e); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ runtime.NestedObjectDecoder = &ClusterRole{}
|
||||
var _ runtime.NestedObjectEncoder = &ClusterRole{}
|
||||
|
||||
func (c *ClusterRole) DecodeNestedObjects(d runtime.Decoder) error {
|
||||
// decoding failures result in a runtime.Unknown object being created in Object and passed
|
||||
// to conversion
|
||||
for i := range c.Rules {
|
||||
c.Rules[i].DecodeNestedObjects(d)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (c *ClusterRole) EncodeNestedObjects(e runtime.Encoder) error {
|
||||
for i := range c.Rules {
|
||||
if err := c.Rules[i].EncodeNestedObjects(e); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ runtime.NestedObjectDecoder = &Role{}
|
||||
var _ runtime.NestedObjectEncoder = &Role{}
|
||||
|
||||
func (c *Role) DecodeNestedObjects(d runtime.Decoder) error {
|
||||
// decoding failures result in a runtime.Unknown object being created in Object and passed
|
||||
// to conversion
|
||||
for i := range c.Rules {
|
||||
c.Rules[i].DecodeNestedObjects(d)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (c *Role) EncodeNestedObjects(e runtime.Encoder) error {
|
||||
for i := range c.Rules {
|
||||
if err := c.Rules[i].EncodeNestedObjects(e); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ runtime.NestedObjectDecoder = &ClusterRoleList{}
|
||||
var _ runtime.NestedObjectEncoder = &ClusterRoleList{}
|
||||
|
||||
func (c *ClusterRoleList) DecodeNestedObjects(d runtime.Decoder) error {
|
||||
// decoding failures result in a runtime.Unknown object being created in Object and passed
|
||||
// to conversion
|
||||
for i := range c.Items {
|
||||
c.Items[i].DecodeNestedObjects(d)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (c *ClusterRoleList) EncodeNestedObjects(e runtime.Encoder) error {
|
||||
for i := range c.Items {
|
||||
if err := c.Items[i].EncodeNestedObjects(e); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ runtime.NestedObjectDecoder = &RoleList{}
|
||||
var _ runtime.NestedObjectEncoder = &RoleList{}
|
||||
|
||||
func (c *RoleList) DecodeNestedObjects(d runtime.Decoder) error {
|
||||
// decoding failures result in a runtime.Unknown object being created in Object and passed
|
||||
// to conversion
|
||||
for i := range c.Items {
|
||||
c.Items[i].DecodeNestedObjects(d)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (c *RoleList) EncodeNestedObjects(e runtime.Encoder) error {
|
||||
for i := range c.Items {
|
||||
if err := c.Items[i].EncodeNestedObjects(e); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
// +k8s:conversion-gen=github.com/openshift/origin/pkg/authorization/apis/authorization
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +k8s:openapi-gen=true
|
||||
|
||||
// +kubebuilder:validation:Optional
|
||||
// +groupName=authorization.openshift.io
|
||||
// Package v1 is the v1 version of the API.
|
||||
package v1
|
||||
+8917
File diff suppressed because it is too large
Load Diff
+478
@@ -0,0 +1,478 @@
|
||||
|
||||
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
|
||||
|
||||
syntax = 'proto2';
|
||||
|
||||
package github.com.openshift.api.authorization.v1;
|
||||
|
||||
import "k8s.io/api/core/v1/generated.proto";
|
||||
import "k8s.io/api/rbac/v1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
|
||||
|
||||
// Package-wide variables from generator "generated".
|
||||
option go_package = "v1";
|
||||
|
||||
// Action describes a request to the API server
|
||||
message Action {
|
||||
// Namespace is the namespace of the action being requested. Currently, there is no distinction between no namespace and all namespaces
|
||||
optional string namespace = 1;
|
||||
|
||||
// Verb is one of: get, list, watch, create, update, delete
|
||||
optional string verb = 2;
|
||||
|
||||
// Group is the API group of the resource
|
||||
// Serialized as resourceAPIGroup to avoid confusion with the 'groups' field when inlined
|
||||
optional string resourceAPIGroup = 3;
|
||||
|
||||
// Version is the API version of the resource
|
||||
// Serialized as resourceAPIVersion to avoid confusion with TypeMeta.apiVersion and ObjectMeta.resourceVersion when inlined
|
||||
optional string resourceAPIVersion = 4;
|
||||
|
||||
// Resource is one of the existing resource types
|
||||
optional string resource = 5;
|
||||
|
||||
// ResourceName is the name of the resource being requested for a "get" or deleted for a "delete"
|
||||
optional string resourceName = 6;
|
||||
|
||||
// Path is the path of a non resource URL
|
||||
optional string path = 8;
|
||||
|
||||
// IsNonResourceURL is true if this is a request for a non-resource URL (outside of the resource hierarchy)
|
||||
optional bool isNonResourceURL = 9;
|
||||
|
||||
// Content is the actual content of the request for create and update
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
optional k8s.io.apimachinery.pkg.runtime.RawExtension content = 7;
|
||||
}
|
||||
|
||||
// ClusterRole is a logical grouping of PolicyRules that can be referenced as a unit by ClusterRoleBindings.
|
||||
message ClusterRole {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||
|
||||
// Rules holds all the PolicyRules for this ClusterRole
|
||||
repeated PolicyRule rules = 2;
|
||||
|
||||
// AggregationRule is an optional field that describes how to build the Rules for this ClusterRole.
|
||||
// If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be
|
||||
// stomped by the controller.
|
||||
optional k8s.io.api.rbac.v1.AggregationRule aggregationRule = 3;
|
||||
}
|
||||
|
||||
// ClusterRoleBinding references a ClusterRole, but not contain it. It can reference any ClusterRole in the same namespace or in the global namespace.
|
||||
// It adds who information via (Users and Groups) OR Subjects and namespace information by which namespace it exists in.
|
||||
// ClusterRoleBindings in a given namespace only have effect in that namespace (excepting the master namespace which has power in all namespaces).
|
||||
message ClusterRoleBinding {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||
|
||||
// UserNames holds all the usernames directly bound to the role.
|
||||
// This field should only be specified when supporting legacy clients and servers.
|
||||
// See Subjects for further details.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
optional OptionalNames userNames = 2;
|
||||
|
||||
// GroupNames holds all the groups directly bound to the role.
|
||||
// This field should only be specified when supporting legacy clients and servers.
|
||||
// See Subjects for further details.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
optional OptionalNames groupNames = 3;
|
||||
|
||||
// Subjects hold object references to authorize with this rule.
|
||||
// This field is ignored if UserNames or GroupNames are specified to support legacy clients and servers.
|
||||
// Thus newer clients that do not need to support backwards compatibility should send
|
||||
// only fully qualified Subjects and should omit the UserNames and GroupNames fields.
|
||||
// Clients that need to support backwards compatibility can use this field to build the UserNames and GroupNames.
|
||||
repeated k8s.io.api.core.v1.ObjectReference subjects = 4;
|
||||
|
||||
// RoleRef can only reference the current namespace and the global namespace.
|
||||
// If the ClusterRoleRef cannot be resolved, the Authorizer must return an error.
|
||||
// Since Policy is a singleton, this is sufficient knowledge to locate a role.
|
||||
optional k8s.io.api.core.v1.ObjectReference roleRef = 5;
|
||||
}
|
||||
|
||||
// ClusterRoleBindingList is a collection of ClusterRoleBindings
|
||||
message ClusterRoleBindingList {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1;
|
||||
|
||||
// Items is a list of ClusterRoleBindings
|
||||
repeated ClusterRoleBinding items = 2;
|
||||
}
|
||||
|
||||
// ClusterRoleList is a collection of ClusterRoles
|
||||
message ClusterRoleList {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1;
|
||||
|
||||
// Items is a list of ClusterRoles
|
||||
repeated ClusterRole items = 2;
|
||||
}
|
||||
|
||||
// GroupRestriction matches a group either by a string match on the group name
|
||||
// or a label selector applied to group labels.
|
||||
message GroupRestriction {
|
||||
// Groups is a list of groups used to match against an individual user's
|
||||
// groups. If the user is a member of one of the whitelisted groups, the user
|
||||
// is allowed to be bound to a role.
|
||||
// +nullable
|
||||
repeated string groups = 1;
|
||||
|
||||
// Selectors specifies a list of label selectors over group labels.
|
||||
// +nullable
|
||||
repeated k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector labels = 2;
|
||||
}
|
||||
|
||||
// IsPersonalSubjectAccessReview is a marker for PolicyRule.AttributeRestrictions that denotes that subjectaccessreviews on self should be allowed
|
||||
message IsPersonalSubjectAccessReview {
|
||||
}
|
||||
|
||||
// LocalResourceAccessReview is a means to request a list of which users and groups are authorized to perform the action specified by spec in a particular namespace
|
||||
message LocalResourceAccessReview {
|
||||
// Action describes the action being tested. The Namespace element is FORCED to the current namespace.
|
||||
optional Action Action = 1;
|
||||
}
|
||||
|
||||
// LocalSubjectAccessReview is an object for requesting information about whether a user or group can perform an action in a particular namespace
|
||||
message LocalSubjectAccessReview {
|
||||
// Action describes the action being tested. The Namespace element is FORCED to the current namespace.
|
||||
optional Action Action = 1;
|
||||
|
||||
// User is optional. If both User and Groups are empty, the current authenticated user is used.
|
||||
optional string user = 2;
|
||||
|
||||
// Groups is optional. Groups is the list of groups to which the User belongs.
|
||||
// +k8s:conversion-gen=false
|
||||
repeated string groups = 3;
|
||||
|
||||
// Scopes to use for the evaluation. Empty means "use the unscoped (full) permissions of the user/groups".
|
||||
// Nil for a self-SAR, means "use the scopes on this request".
|
||||
// Nil for a regular SAR, means the same as empty.
|
||||
// +k8s:conversion-gen=false
|
||||
optional OptionalScopes scopes = 4;
|
||||
}
|
||||
|
||||
// NamedClusterRole relates a name with a cluster role
|
||||
message NamedClusterRole {
|
||||
// Name is the name of the cluster role
|
||||
optional string name = 1;
|
||||
|
||||
// Role is the cluster role being named
|
||||
optional ClusterRole role = 2;
|
||||
}
|
||||
|
||||
// NamedClusterRoleBinding relates a name with a cluster role binding
|
||||
message NamedClusterRoleBinding {
|
||||
// Name is the name of the cluster role binding
|
||||
optional string name = 1;
|
||||
|
||||
// RoleBinding is the cluster role binding being named
|
||||
optional ClusterRoleBinding roleBinding = 2;
|
||||
}
|
||||
|
||||
// NamedRole relates a Role with a name
|
||||
message NamedRole {
|
||||
// Name is the name of the role
|
||||
optional string name = 1;
|
||||
|
||||
// Role is the role being named
|
||||
optional Role role = 2;
|
||||
}
|
||||
|
||||
// NamedRoleBinding relates a role binding with a name
|
||||
message NamedRoleBinding {
|
||||
// Name is the name of the role binding
|
||||
optional string name = 1;
|
||||
|
||||
// RoleBinding is the role binding being named
|
||||
optional RoleBinding roleBinding = 2;
|
||||
}
|
||||
|
||||
// OptionalNames is an array that may also be left nil to distinguish between set and unset.
|
||||
// +protobuf.nullable=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
message OptionalNames {
|
||||
// items, if empty, will result in an empty slice
|
||||
|
||||
repeated string items = 1;
|
||||
}
|
||||
|
||||
// OptionalScopes is an array that may also be left nil to distinguish between set and unset.
|
||||
// +protobuf.nullable=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
message OptionalScopes {
|
||||
// items, if empty, will result in an empty slice
|
||||
|
||||
repeated string items = 1;
|
||||
}
|
||||
|
||||
// PolicyRule holds information that describes a policy rule, but does not contain information
|
||||
// about who the rule applies to or which namespace the rule applies to.
|
||||
message PolicyRule {
|
||||
// Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule. VerbAll represents all kinds.
|
||||
repeated string verbs = 1;
|
||||
|
||||
// AttributeRestrictions will vary depending on what the Authorizer/AuthorizationAttributeBuilder pair supports.
|
||||
// If the Authorizer does not recognize how to handle the AttributeRestrictions, the Authorizer should report an error.
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
optional k8s.io.apimachinery.pkg.runtime.RawExtension attributeRestrictions = 2;
|
||||
|
||||
// APIGroups is the name of the APIGroup that contains the resources. If this field is empty, then both kubernetes and origin API groups are assumed.
|
||||
// That means that if an action is requested against one of the enumerated resources in either the kubernetes or the origin API group, the request
|
||||
// will be allowed
|
||||
repeated string apiGroups = 3;
|
||||
|
||||
// Resources is a list of resources this rule applies to. ResourceAll represents all resources.
|
||||
repeated string resources = 4;
|
||||
|
||||
// ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.
|
||||
repeated string resourceNames = 5;
|
||||
|
||||
// NonResourceURLsSlice is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path
|
||||
// This name is intentionally different than the internal type so that the DefaultConvert works nicely and because the ordering may be different.
|
||||
repeated string nonResourceURLs = 6;
|
||||
}
|
||||
|
||||
// ResourceAccessReview is a means to request a list of which users and groups are authorized to perform the
|
||||
// action specified by spec
|
||||
message ResourceAccessReview {
|
||||
// Action describes the action being tested.
|
||||
optional Action Action = 1;
|
||||
}
|
||||
|
||||
// ResourceAccessReviewResponse describes who can perform the action
|
||||
message ResourceAccessReviewResponse {
|
||||
// Namespace is the namespace used for the access review
|
||||
optional string namespace = 1;
|
||||
|
||||
// UsersSlice is the list of users who can perform the action
|
||||
// +k8s:conversion-gen=false
|
||||
repeated string users = 2;
|
||||
|
||||
// GroupsSlice is the list of groups who can perform the action
|
||||
// +k8s:conversion-gen=false
|
||||
repeated string groups = 3;
|
||||
|
||||
// EvaluationError is an indication that some error occurred during resolution, but partial results can still be returned.
|
||||
// It is entirely possible to get an error and be able to continue determine authorization status in spite of it. This is
|
||||
// most common when a bound role is missing, but enough roles are still present and bound to reason about the request.
|
||||
optional string evalutionError = 4;
|
||||
}
|
||||
|
||||
// Role is a logical grouping of PolicyRules that can be referenced as a unit by RoleBindings.
|
||||
message Role {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||
|
||||
// Rules holds all the PolicyRules for this Role
|
||||
repeated PolicyRule rules = 2;
|
||||
}
|
||||
|
||||
// RoleBinding references a Role, but not contain it. It can reference any Role in the same namespace or in the global namespace.
|
||||
// It adds who information via (Users and Groups) OR Subjects and namespace information by which namespace it exists in.
|
||||
// RoleBindings in a given namespace only have effect in that namespace (excepting the master namespace which has power in all namespaces).
|
||||
message RoleBinding {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||
|
||||
// UserNames holds all the usernames directly bound to the role.
|
||||
// This field should only be specified when supporting legacy clients and servers.
|
||||
// See Subjects for further details.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
optional OptionalNames userNames = 2;
|
||||
|
||||
// GroupNames holds all the groups directly bound to the role.
|
||||
// This field should only be specified when supporting legacy clients and servers.
|
||||
// See Subjects for further details.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
optional OptionalNames groupNames = 3;
|
||||
|
||||
// Subjects hold object references to authorize with this rule.
|
||||
// This field is ignored if UserNames or GroupNames are specified to support legacy clients and servers.
|
||||
// Thus newer clients that do not need to support backwards compatibility should send
|
||||
// only fully qualified Subjects and should omit the UserNames and GroupNames fields.
|
||||
// Clients that need to support backwards compatibility can use this field to build the UserNames and GroupNames.
|
||||
repeated k8s.io.api.core.v1.ObjectReference subjects = 4;
|
||||
|
||||
// RoleRef can only reference the current namespace and the global namespace.
|
||||
// If the RoleRef cannot be resolved, the Authorizer must return an error.
|
||||
// Since Policy is a singleton, this is sufficient knowledge to locate a role.
|
||||
optional k8s.io.api.core.v1.ObjectReference roleRef = 5;
|
||||
}
|
||||
|
||||
// RoleBindingList is a collection of RoleBindings
|
||||
message RoleBindingList {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1;
|
||||
|
||||
// Items is a list of RoleBindings
|
||||
repeated RoleBinding items = 2;
|
||||
}
|
||||
|
||||
// RoleBindingRestriction is an object that can be matched against a subject
|
||||
// (user, group, or service account) to determine whether rolebindings on that
|
||||
// subject are allowed in the namespace to which the RoleBindingRestriction
|
||||
// belongs. If any one of those RoleBindingRestriction objects matches
|
||||
// a subject, rolebindings on that subject in the namespace are allowed.
|
||||
message RoleBindingRestriction {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||
|
||||
// Spec defines the matcher.
|
||||
optional RoleBindingRestrictionSpec spec = 2;
|
||||
}
|
||||
|
||||
// RoleBindingRestrictionList is a collection of RoleBindingRestriction objects.
|
||||
message RoleBindingRestrictionList {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1;
|
||||
|
||||
// Items is a list of RoleBindingRestriction objects.
|
||||
repeated RoleBindingRestriction items = 2;
|
||||
}
|
||||
|
||||
// RoleBindingRestrictionSpec defines a rolebinding restriction. Exactly one
|
||||
// field must be non-nil.
|
||||
message RoleBindingRestrictionSpec {
|
||||
// UserRestriction matches against user subjects.
|
||||
// +nullable
|
||||
optional UserRestriction userrestriction = 1;
|
||||
|
||||
// GroupRestriction matches against group subjects.
|
||||
// +nullable
|
||||
optional GroupRestriction grouprestriction = 2;
|
||||
|
||||
// ServiceAccountRestriction matches against service-account subjects.
|
||||
// +nullable
|
||||
optional ServiceAccountRestriction serviceaccountrestriction = 3;
|
||||
}
|
||||
|
||||
// RoleList is a collection of Roles
|
||||
message RoleList {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1;
|
||||
|
||||
// Items is a list of Roles
|
||||
repeated Role items = 2;
|
||||
}
|
||||
|
||||
// SelfSubjectRulesReview is a resource you can create to determine which actions you can perform in a namespace
|
||||
message SelfSubjectRulesReview {
|
||||
// Spec adds information about how to conduct the check
|
||||
optional SelfSubjectRulesReviewSpec spec = 1;
|
||||
|
||||
// Status is completed by the server to tell which permissions you have
|
||||
optional SubjectRulesReviewStatus status = 2;
|
||||
}
|
||||
|
||||
// SelfSubjectRulesReviewSpec adds information about how to conduct the check
|
||||
message SelfSubjectRulesReviewSpec {
|
||||
// Scopes to use for the evaluation. Empty means "use the unscoped (full) permissions of the user/groups".
|
||||
// Nil means "use the scopes on this request".
|
||||
// +k8s:conversion-gen=false
|
||||
optional OptionalScopes scopes = 1;
|
||||
}
|
||||
|
||||
// ServiceAccountReference specifies a service account and namespace by their
|
||||
// names.
|
||||
message ServiceAccountReference {
|
||||
// Name is the name of the service account.
|
||||
optional string name = 1;
|
||||
|
||||
// Namespace is the namespace of the service account. Service accounts from
|
||||
// inside the whitelisted namespaces are allowed to be bound to roles. If
|
||||
// Namespace is empty, then the namespace of the RoleBindingRestriction in
|
||||
// which the ServiceAccountReference is embedded is used.
|
||||
optional string namespace = 2;
|
||||
}
|
||||
|
||||
// ServiceAccountRestriction matches a service account by a string match on
|
||||
// either the service-account name or the name of the service account's
|
||||
// namespace.
|
||||
message ServiceAccountRestriction {
|
||||
// ServiceAccounts specifies a list of literal service-account names.
|
||||
repeated ServiceAccountReference serviceaccounts = 1;
|
||||
|
||||
// Namespaces specifies a list of literal namespace names.
|
||||
repeated string namespaces = 2;
|
||||
}
|
||||
|
||||
// SubjectAccessReview is an object for requesting information about whether a user or group can perform an action
|
||||
message SubjectAccessReview {
|
||||
// Action describes the action being tested.
|
||||
optional Action Action = 1;
|
||||
|
||||
// User is optional. If both User and Groups are empty, the current authenticated user is used.
|
||||
optional string user = 2;
|
||||
|
||||
// GroupsSlice is optional. Groups is the list of groups to which the User belongs.
|
||||
// +k8s:conversion-gen=false
|
||||
repeated string groups = 3;
|
||||
|
||||
// Scopes to use for the evaluation. Empty means "use the unscoped (full) permissions of the user/groups".
|
||||
// Nil for a self-SAR, means "use the scopes on this request".
|
||||
// Nil for a regular SAR, means the same as empty.
|
||||
// +k8s:conversion-gen=false
|
||||
optional OptionalScopes scopes = 4;
|
||||
}
|
||||
|
||||
// SubjectAccessReviewResponse describes whether or not a user or group can perform an action
|
||||
message SubjectAccessReviewResponse {
|
||||
// Namespace is the namespace used for the access review
|
||||
optional string namespace = 1;
|
||||
|
||||
// Allowed is required. True if the action would be allowed, false otherwise.
|
||||
optional bool allowed = 2;
|
||||
|
||||
// Reason is optional. It indicates why a request was allowed or denied.
|
||||
optional string reason = 3;
|
||||
|
||||
// EvaluationError is an indication that some error occurred during the authorization check.
|
||||
// It is entirely possible to get an error and be able to continue determine authorization status in spite of it. This is
|
||||
// most common when a bound role is missing, but enough roles are still present and bound to reason about the request.
|
||||
optional string evaluationError = 4;
|
||||
}
|
||||
|
||||
// SubjectRulesReview is a resource you can create to determine which actions another user can perform in a namespace
|
||||
message SubjectRulesReview {
|
||||
// Spec adds information about how to conduct the check
|
||||
optional SubjectRulesReviewSpec spec = 1;
|
||||
|
||||
// Status is completed by the server to tell which permissions you have
|
||||
optional SubjectRulesReviewStatus status = 2;
|
||||
}
|
||||
|
||||
// SubjectRulesReviewSpec adds information about how to conduct the check
|
||||
message SubjectRulesReviewSpec {
|
||||
// User is optional. At least one of User and Groups must be specified.
|
||||
optional string user = 1;
|
||||
|
||||
// Groups is optional. Groups is the list of groups to which the User belongs. At least one of User and Groups must be specified.
|
||||
repeated string groups = 2;
|
||||
|
||||
// Scopes to use for the evaluation. Empty means "use the unscoped (full) permissions of the user/groups".
|
||||
optional OptionalScopes scopes = 3;
|
||||
}
|
||||
|
||||
// SubjectRulesReviewStatus is contains the result of a rules check
|
||||
message SubjectRulesReviewStatus {
|
||||
// Rules is the list of rules (no particular sort) that are allowed for the subject
|
||||
repeated PolicyRule rules = 1;
|
||||
|
||||
// EvaluationError can appear in combination with Rules. It means some error happened during evaluation
|
||||
// that may have prevented additional rules from being populated.
|
||||
optional string evaluationError = 2;
|
||||
}
|
||||
|
||||
// UserRestriction matches a user either by a string match on the user name,
|
||||
// a string match on the name of a group to which the user belongs, or a label
|
||||
// selector applied to the user labels.
|
||||
message UserRestriction {
|
||||
// Users specifies a list of literal user names.
|
||||
repeated string users = 1;
|
||||
|
||||
// Groups specifies a list of literal group names.
|
||||
// +nullable
|
||||
repeated string groups = 2;
|
||||
|
||||
// Selectors specifies a list of label selectors over user labels.
|
||||
// +nullable
|
||||
repeated k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector labels = 3;
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
legacyGroupVersion = schema.GroupVersion{Group: "", Version: "v1"}
|
||||
legacySchemeBuilder = runtime.NewSchemeBuilder(addLegacyKnownTypes, corev1.AddToScheme, rbacv1.AddToScheme)
|
||||
DeprecatedInstallWithoutGroup = legacySchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func addLegacyKnownTypes(scheme *runtime.Scheme) error {
|
||||
types := []runtime.Object{
|
||||
&Role{},
|
||||
&RoleBinding{},
|
||||
&RoleBindingList{},
|
||||
&RoleList{},
|
||||
|
||||
&SelfSubjectRulesReview{},
|
||||
&SubjectRulesReview{},
|
||||
&ResourceAccessReview{},
|
||||
&SubjectAccessReview{},
|
||||
&LocalResourceAccessReview{},
|
||||
&LocalSubjectAccessReview{},
|
||||
&ResourceAccessReviewResponse{},
|
||||
&SubjectAccessReviewResponse{},
|
||||
&IsPersonalSubjectAccessReview{},
|
||||
|
||||
&ClusterRole{},
|
||||
&ClusterRoleBinding{},
|
||||
&ClusterRoleBindingList{},
|
||||
&ClusterRoleList{},
|
||||
|
||||
&RoleBindingRestriction{},
|
||||
&RoleBindingRestrictionList{},
|
||||
}
|
||||
scheme.AddKnownTypes(legacyGroupVersion, types...)
|
||||
return nil
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
GroupName = "authorization.openshift.io"
|
||||
GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
|
||||
schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, corev1.AddToScheme, rbacv1.AddToScheme)
|
||||
// Install is a function which adds this version to a scheme
|
||||
Install = schemeBuilder.AddToScheme
|
||||
|
||||
// SchemeGroupVersion generated code relies on this name
|
||||
// Deprecated
|
||||
SchemeGroupVersion = GroupVersion
|
||||
// AddToScheme exists solely to keep the old generators creating valid code
|
||||
// DEPRECATED
|
||||
AddToScheme = schemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// Resource generated code relies on this being here, but it logically belongs to the group
|
||||
// DEPRECATED
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return schema.GroupResource{Group: GroupName, Resource: resource}
|
||||
}
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(GroupVersion,
|
||||
&Role{},
|
||||
&RoleBinding{},
|
||||
&RoleBindingList{},
|
||||
&RoleList{},
|
||||
|
||||
&SelfSubjectRulesReview{},
|
||||
&SubjectRulesReview{},
|
||||
&ResourceAccessReview{},
|
||||
&SubjectAccessReview{},
|
||||
&LocalResourceAccessReview{},
|
||||
&LocalSubjectAccessReview{},
|
||||
&ResourceAccessReviewResponse{},
|
||||
&SubjectAccessReviewResponse{},
|
||||
&IsPersonalSubjectAccessReview{},
|
||||
|
||||
&ClusterRole{},
|
||||
&ClusterRoleBinding{},
|
||||
&ClusterRoleBindingList{},
|
||||
&ClusterRoleList{},
|
||||
|
||||
&RoleBindingRestriction{},
|
||||
&RoleBindingRestrictionList{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, GroupVersion)
|
||||
return nil
|
||||
}
|
||||
+543
@@ -0,0 +1,543 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kruntime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Authorization is calculated against
|
||||
// 1. all deny RoleBinding PolicyRules in the master namespace - short circuit on match
|
||||
// 2. all allow RoleBinding PolicyRules in the master namespace - short circuit on match
|
||||
// 3. all deny RoleBinding PolicyRules in the namespace - short circuit on match
|
||||
// 4. all allow RoleBinding PolicyRules in the namespace - short circuit on match
|
||||
// 5. deny by default
|
||||
|
||||
const (
|
||||
// GroupKind is string representation of kind used in role binding subjects that represents the "group".
|
||||
GroupKind = "Group"
|
||||
// UserKind is string representation of kind used in role binding subjects that represents the "user".
|
||||
UserKind = "User"
|
||||
|
||||
ScopesKey = "scopes.authorization.openshift.io"
|
||||
)
|
||||
|
||||
// PolicyRule holds information that describes a policy rule, but does not contain information
|
||||
// about who the rule applies to or which namespace the rule applies to.
|
||||
type PolicyRule struct {
|
||||
// Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule. VerbAll represents all kinds.
|
||||
Verbs []string `json:"verbs" protobuf:"bytes,1,rep,name=verbs"`
|
||||
// AttributeRestrictions will vary depending on what the Authorizer/AuthorizationAttributeBuilder pair supports.
|
||||
// If the Authorizer does not recognize how to handle the AttributeRestrictions, the Authorizer should report an error.
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
AttributeRestrictions kruntime.RawExtension `json:"attributeRestrictions,omitempty" protobuf:"bytes,2,opt,name=attributeRestrictions"`
|
||||
// APIGroups is the name of the APIGroup that contains the resources. If this field is empty, then both kubernetes and origin API groups are assumed.
|
||||
// That means that if an action is requested against one of the enumerated resources in either the kubernetes or the origin API group, the request
|
||||
// will be allowed
|
||||
APIGroups []string `json:"apiGroups" protobuf:"bytes,3,rep,name=apiGroups"`
|
||||
// Resources is a list of resources this rule applies to. ResourceAll represents all resources.
|
||||
Resources []string `json:"resources" protobuf:"bytes,4,rep,name=resources"`
|
||||
// ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.
|
||||
ResourceNames []string `json:"resourceNames,omitempty" protobuf:"bytes,5,rep,name=resourceNames"`
|
||||
// NonResourceURLsSlice is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path
|
||||
// This name is intentionally different than the internal type so that the DefaultConvert works nicely and because the ordering may be different.
|
||||
NonResourceURLsSlice []string `json:"nonResourceURLs,omitempty" protobuf:"bytes,6,rep,name=nonResourceURLs"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// IsPersonalSubjectAccessReview is a marker for PolicyRule.AttributeRestrictions that denotes that subjectaccessreviews on self should be allowed
|
||||
type IsPersonalSubjectAccessReview struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Role is a logical grouping of PolicyRules that can be referenced as a unit by RoleBindings.
|
||||
type Role struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Rules holds all the PolicyRules for this Role
|
||||
Rules []PolicyRule `json:"rules" protobuf:"bytes,2,rep,name=rules"`
|
||||
}
|
||||
|
||||
// OptionalNames is an array that may also be left nil to distinguish between set and unset.
|
||||
// +protobuf.nullable=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type OptionalNames []string
|
||||
|
||||
func (t OptionalNames) String() string {
|
||||
return fmt.Sprintf("%v", []string(t))
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// RoleBinding references a Role, but not contain it. It can reference any Role in the same namespace or in the global namespace.
|
||||
// It adds who information via (Users and Groups) OR Subjects and namespace information by which namespace it exists in.
|
||||
// RoleBindings in a given namespace only have effect in that namespace (excepting the master namespace which has power in all namespaces).
|
||||
type RoleBinding struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// UserNames holds all the usernames directly bound to the role.
|
||||
// This field should only be specified when supporting legacy clients and servers.
|
||||
// See Subjects for further details.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
UserNames OptionalNames `json:"userNames" protobuf:"bytes,2,rep,name=userNames"`
|
||||
// GroupNames holds all the groups directly bound to the role.
|
||||
// This field should only be specified when supporting legacy clients and servers.
|
||||
// See Subjects for further details.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
GroupNames OptionalNames `json:"groupNames" protobuf:"bytes,3,rep,name=groupNames"`
|
||||
// Subjects hold object references to authorize with this rule.
|
||||
// This field is ignored if UserNames or GroupNames are specified to support legacy clients and servers.
|
||||
// Thus newer clients that do not need to support backwards compatibility should send
|
||||
// only fully qualified Subjects and should omit the UserNames and GroupNames fields.
|
||||
// Clients that need to support backwards compatibility can use this field to build the UserNames and GroupNames.
|
||||
Subjects []corev1.ObjectReference `json:"subjects" protobuf:"bytes,4,rep,name=subjects"`
|
||||
|
||||
// RoleRef can only reference the current namespace and the global namespace.
|
||||
// If the RoleRef cannot be resolved, the Authorizer must return an error.
|
||||
// Since Policy is a singleton, this is sufficient knowledge to locate a role.
|
||||
RoleRef corev1.ObjectReference `json:"roleRef" protobuf:"bytes,5,opt,name=roleRef"`
|
||||
}
|
||||
|
||||
// NamedRole relates a Role with a name
|
||||
type NamedRole struct {
|
||||
// Name is the name of the role
|
||||
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
|
||||
// Role is the role being named
|
||||
Role Role `json:"role" protobuf:"bytes,2,opt,name=role"`
|
||||
}
|
||||
|
||||
// NamedRoleBinding relates a role binding with a name
|
||||
type NamedRoleBinding struct {
|
||||
// Name is the name of the role binding
|
||||
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
|
||||
// RoleBinding is the role binding being named
|
||||
RoleBinding RoleBinding `json:"roleBinding" protobuf:"bytes,2,opt,name=roleBinding"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:onlyVerbs=create
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// SelfSubjectRulesReview is a resource you can create to determine which actions you can perform in a namespace
|
||||
type SelfSubjectRulesReview struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Spec adds information about how to conduct the check
|
||||
Spec SelfSubjectRulesReviewSpec `json:"spec" protobuf:"bytes,1,opt,name=spec"`
|
||||
|
||||
// Status is completed by the server to tell which permissions you have
|
||||
Status SubjectRulesReviewStatus `json:"status,omitempty" protobuf:"bytes,2,opt,name=status"`
|
||||
}
|
||||
|
||||
// SelfSubjectRulesReviewSpec adds information about how to conduct the check
|
||||
type SelfSubjectRulesReviewSpec struct {
|
||||
// Scopes to use for the evaluation. Empty means "use the unscoped (full) permissions of the user/groups".
|
||||
// Nil means "use the scopes on this request".
|
||||
// +k8s:conversion-gen=false
|
||||
Scopes OptionalScopes `json:"scopes" protobuf:"bytes,1,rep,name=scopes"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:onlyVerbs=create
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// SubjectRulesReview is a resource you can create to determine which actions another user can perform in a namespace
|
||||
type SubjectRulesReview struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Spec adds information about how to conduct the check
|
||||
Spec SubjectRulesReviewSpec `json:"spec" protobuf:"bytes,1,opt,name=spec"`
|
||||
|
||||
// Status is completed by the server to tell which permissions you have
|
||||
Status SubjectRulesReviewStatus `json:"status,omitempty" protobuf:"bytes,2,opt,name=status"`
|
||||
}
|
||||
|
||||
// SubjectRulesReviewSpec adds information about how to conduct the check
|
||||
type SubjectRulesReviewSpec struct {
|
||||
// User is optional. At least one of User and Groups must be specified.
|
||||
User string `json:"user" protobuf:"bytes,1,opt,name=user"`
|
||||
// Groups is optional. Groups is the list of groups to which the User belongs. At least one of User and Groups must be specified.
|
||||
Groups []string `json:"groups" protobuf:"bytes,2,rep,name=groups"`
|
||||
// Scopes to use for the evaluation. Empty means "use the unscoped (full) permissions of the user/groups".
|
||||
Scopes OptionalScopes `json:"scopes" protobuf:"bytes,3,opt,name=scopes"`
|
||||
}
|
||||
|
||||
// SubjectRulesReviewStatus is contains the result of a rules check
|
||||
type SubjectRulesReviewStatus struct {
|
||||
// Rules is the list of rules (no particular sort) that are allowed for the subject
|
||||
Rules []PolicyRule `json:"rules" protobuf:"bytes,1,rep,name=rules"`
|
||||
// EvaluationError can appear in combination with Rules. It means some error happened during evaluation
|
||||
// that may have prevented additional rules from being populated.
|
||||
EvaluationError string `json:"evaluationError,omitempty" protobuf:"bytes,2,opt,name=evaluationError"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// ResourceAccessReviewResponse describes who can perform the action
|
||||
type ResourceAccessReviewResponse struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Namespace is the namespace used for the access review
|
||||
Namespace string `json:"namespace,omitempty" protobuf:"bytes,1,opt,name=namespace"`
|
||||
// UsersSlice is the list of users who can perform the action
|
||||
// +k8s:conversion-gen=false
|
||||
UsersSlice []string `json:"users" protobuf:"bytes,2,rep,name=users"`
|
||||
// GroupsSlice is the list of groups who can perform the action
|
||||
// +k8s:conversion-gen=false
|
||||
GroupsSlice []string `json:"groups" protobuf:"bytes,3,rep,name=groups"`
|
||||
|
||||
// EvaluationError is an indication that some error occurred during resolution, but partial results can still be returned.
|
||||
// It is entirely possible to get an error and be able to continue determine authorization status in spite of it. This is
|
||||
// most common when a bound role is missing, but enough roles are still present and bound to reason about the request.
|
||||
EvaluationError string `json:"evalutionError" protobuf:"bytes,4,opt,name=evalutionError"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:nonNamespaced
|
||||
// +genclient:skipVerbs=get,list,create,update,patch,delete,deleteCollection,watch
|
||||
// +genclient:method=Create,verb=create,result=ResourceAccessReviewResponse
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// ResourceAccessReview is a means to request a list of which users and groups are authorized to perform the
|
||||
// action specified by spec
|
||||
type ResourceAccessReview struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Action describes the action being tested.
|
||||
Action `json:",inline" protobuf:"bytes,1,opt,name=Action"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// SubjectAccessReviewResponse describes whether or not a user or group can perform an action
|
||||
type SubjectAccessReviewResponse struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Namespace is the namespace used for the access review
|
||||
Namespace string `json:"namespace,omitempty" protobuf:"bytes,1,opt,name=namespace"`
|
||||
// Allowed is required. True if the action would be allowed, false otherwise.
|
||||
Allowed bool `json:"allowed" protobuf:"varint,2,opt,name=allowed"`
|
||||
// Reason is optional. It indicates why a request was allowed or denied.
|
||||
Reason string `json:"reason,omitempty" protobuf:"bytes,3,opt,name=reason"`
|
||||
// EvaluationError is an indication that some error occurred during the authorization check.
|
||||
// It is entirely possible to get an error and be able to continue determine authorization status in spite of it. This is
|
||||
// most common when a bound role is missing, but enough roles are still present and bound to reason about the request.
|
||||
EvaluationError string `json:"evaluationError,omitempty" protobuf:"bytes,4,opt,name=evaluationError"`
|
||||
}
|
||||
|
||||
// OptionalScopes is an array that may also be left nil to distinguish between set and unset.
|
||||
// +protobuf.nullable=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type OptionalScopes []string
|
||||
|
||||
func (t OptionalScopes) String() string {
|
||||
return fmt.Sprintf("%v", []string(t))
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:nonNamespaced
|
||||
// +genclient:skipVerbs=get,list,create,update,patch,delete,deleteCollection,watch
|
||||
// +genclient:method=Create,verb=create,result=SubjectAccessReviewResponse
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// SubjectAccessReview is an object for requesting information about whether a user or group can perform an action
|
||||
type SubjectAccessReview struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Action describes the action being tested.
|
||||
Action `json:",inline" protobuf:"bytes,1,opt,name=Action"`
|
||||
// User is optional. If both User and Groups are empty, the current authenticated user is used.
|
||||
User string `json:"user" protobuf:"bytes,2,opt,name=user"`
|
||||
// GroupsSlice is optional. Groups is the list of groups to which the User belongs.
|
||||
// +k8s:conversion-gen=false
|
||||
GroupsSlice []string `json:"groups" protobuf:"bytes,3,rep,name=groups"`
|
||||
// Scopes to use for the evaluation. Empty means "use the unscoped (full) permissions of the user/groups".
|
||||
// Nil for a self-SAR, means "use the scopes on this request".
|
||||
// Nil for a regular SAR, means the same as empty.
|
||||
// +k8s:conversion-gen=false
|
||||
Scopes OptionalScopes `json:"scopes" protobuf:"bytes,4,rep,name=scopes"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:skipVerbs=get,list,create,update,patch,delete,deleteCollection,watch
|
||||
// +genclient:method=Create,verb=create,result=ResourceAccessReviewResponse
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// LocalResourceAccessReview is a means to request a list of which users and groups are authorized to perform the action specified by spec in a particular namespace
|
||||
type LocalResourceAccessReview struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Action describes the action being tested. The Namespace element is FORCED to the current namespace.
|
||||
Action `json:",inline" protobuf:"bytes,1,opt,name=Action"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:skipVerbs=get,list,create,update,patch,delete,deleteCollection,watch
|
||||
// +genclient:method=Create,verb=create,result=SubjectAccessReviewResponse
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// LocalSubjectAccessReview is an object for requesting information about whether a user or group can perform an action in a particular namespace
|
||||
type LocalSubjectAccessReview struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Action describes the action being tested. The Namespace element is FORCED to the current namespace.
|
||||
Action `json:",inline" protobuf:"bytes,1,opt,name=Action"`
|
||||
// User is optional. If both User and Groups are empty, the current authenticated user is used.
|
||||
User string `json:"user" protobuf:"bytes,2,opt,name=user"`
|
||||
// Groups is optional. Groups is the list of groups to which the User belongs.
|
||||
// +k8s:conversion-gen=false
|
||||
GroupsSlice []string `json:"groups" protobuf:"bytes,3,rep,name=groups"`
|
||||
// Scopes to use for the evaluation. Empty means "use the unscoped (full) permissions of the user/groups".
|
||||
// Nil for a self-SAR, means "use the scopes on this request".
|
||||
// Nil for a regular SAR, means the same as empty.
|
||||
// +k8s:conversion-gen=false
|
||||
Scopes OptionalScopes `json:"scopes" protobuf:"bytes,4,rep,name=scopes"`
|
||||
}
|
||||
|
||||
// Action describes a request to the API server
|
||||
type Action struct {
|
||||
// Namespace is the namespace of the action being requested. Currently, there is no distinction between no namespace and all namespaces
|
||||
Namespace string `json:"namespace" protobuf:"bytes,1,opt,name=namespace"`
|
||||
// Verb is one of: get, list, watch, create, update, delete
|
||||
Verb string `json:"verb" protobuf:"bytes,2,opt,name=verb"`
|
||||
// Group is the API group of the resource
|
||||
// Serialized as resourceAPIGroup to avoid confusion with the 'groups' field when inlined
|
||||
Group string `json:"resourceAPIGroup" protobuf:"bytes,3,opt,name=resourceAPIGroup"`
|
||||
// Version is the API version of the resource
|
||||
// Serialized as resourceAPIVersion to avoid confusion with TypeMeta.apiVersion and ObjectMeta.resourceVersion when inlined
|
||||
Version string `json:"resourceAPIVersion" protobuf:"bytes,4,opt,name=resourceAPIVersion"`
|
||||
// Resource is one of the existing resource types
|
||||
Resource string `json:"resource" protobuf:"bytes,5,opt,name=resource"`
|
||||
// ResourceName is the name of the resource being requested for a "get" or deleted for a "delete"
|
||||
ResourceName string `json:"resourceName" protobuf:"bytes,6,opt,name=resourceName"`
|
||||
// Path is the path of a non resource URL
|
||||
Path string `json:"path" protobuf:"bytes,8,opt,name=path"`
|
||||
// IsNonResourceURL is true if this is a request for a non-resource URL (outside of the resource hierarchy)
|
||||
IsNonResourceURL bool `json:"isNonResourceURL" protobuf:"varint,9,opt,name=isNonResourceURL"`
|
||||
// Content is the actual content of the request for create and update
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
Content kruntime.RawExtension `json:"content,omitempty" protobuf:"bytes,7,opt,name=content"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// RoleBindingList is a collection of RoleBindings
|
||||
type RoleBindingList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Items is a list of RoleBindings
|
||||
Items []RoleBinding `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// RoleList is a collection of Roles
|
||||
type RoleList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Items is a list of Roles
|
||||
Items []Role `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:nonNamespaced
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// ClusterRole is a logical grouping of PolicyRules that can be referenced as a unit by ClusterRoleBindings.
|
||||
type ClusterRole struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Rules holds all the PolicyRules for this ClusterRole
|
||||
Rules []PolicyRule `json:"rules" protobuf:"bytes,2,rep,name=rules"`
|
||||
|
||||
// AggregationRule is an optional field that describes how to build the Rules for this ClusterRole.
|
||||
// If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be
|
||||
// stomped by the controller.
|
||||
AggregationRule *rbacv1.AggregationRule `json:"aggregationRule,omitempty" protobuf:"bytes,3,opt,name=aggregationRule"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:nonNamespaced
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// ClusterRoleBinding references a ClusterRole, but not contain it. It can reference any ClusterRole in the same namespace or in the global namespace.
|
||||
// It adds who information via (Users and Groups) OR Subjects and namespace information by which namespace it exists in.
|
||||
// ClusterRoleBindings in a given namespace only have effect in that namespace (excepting the master namespace which has power in all namespaces).
|
||||
type ClusterRoleBinding struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// UserNames holds all the usernames directly bound to the role.
|
||||
// This field should only be specified when supporting legacy clients and servers.
|
||||
// See Subjects for further details.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
UserNames OptionalNames `json:"userNames" protobuf:"bytes,2,rep,name=userNames"`
|
||||
// GroupNames holds all the groups directly bound to the role.
|
||||
// This field should only be specified when supporting legacy clients and servers.
|
||||
// See Subjects for further details.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
GroupNames OptionalNames `json:"groupNames" protobuf:"bytes,3,rep,name=groupNames"`
|
||||
// Subjects hold object references to authorize with this rule.
|
||||
// This field is ignored if UserNames or GroupNames are specified to support legacy clients and servers.
|
||||
// Thus newer clients that do not need to support backwards compatibility should send
|
||||
// only fully qualified Subjects and should omit the UserNames and GroupNames fields.
|
||||
// Clients that need to support backwards compatibility can use this field to build the UserNames and GroupNames.
|
||||
Subjects []corev1.ObjectReference `json:"subjects" protobuf:"bytes,4,rep,name=subjects"`
|
||||
|
||||
// RoleRef can only reference the current namespace and the global namespace.
|
||||
// If the ClusterRoleRef cannot be resolved, the Authorizer must return an error.
|
||||
// Since Policy is a singleton, this is sufficient knowledge to locate a role.
|
||||
RoleRef corev1.ObjectReference `json:"roleRef" protobuf:"bytes,5,opt,name=roleRef"`
|
||||
}
|
||||
|
||||
// NamedClusterRole relates a name with a cluster role
|
||||
type NamedClusterRole struct {
|
||||
// Name is the name of the cluster role
|
||||
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
|
||||
// Role is the cluster role being named
|
||||
Role ClusterRole `json:"role" protobuf:"bytes,2,opt,name=role"`
|
||||
}
|
||||
|
||||
// NamedClusterRoleBinding relates a name with a cluster role binding
|
||||
type NamedClusterRoleBinding struct {
|
||||
// Name is the name of the cluster role binding
|
||||
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
|
||||
// RoleBinding is the cluster role binding being named
|
||||
RoleBinding ClusterRoleBinding `json:"roleBinding" protobuf:"bytes,2,opt,name=roleBinding"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// ClusterRoleBindingList is a collection of ClusterRoleBindings
|
||||
type ClusterRoleBindingList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Items is a list of ClusterRoleBindings
|
||||
Items []ClusterRoleBinding `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// ClusterRoleList is a collection of ClusterRoles
|
||||
type ClusterRoleList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Items is a list of ClusterRoles
|
||||
Items []ClusterRole `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// RoleBindingRestriction is an object that can be matched against a subject
|
||||
// (user, group, or service account) to determine whether rolebindings on that
|
||||
// subject are allowed in the namespace to which the RoleBindingRestriction
|
||||
// belongs. If any one of those RoleBindingRestriction objects matches
|
||||
// a subject, rolebindings on that subject in the namespace are allowed.
|
||||
type RoleBindingRestriction struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Spec defines the matcher.
|
||||
Spec RoleBindingRestrictionSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
|
||||
}
|
||||
|
||||
// RoleBindingRestrictionSpec defines a rolebinding restriction. Exactly one
|
||||
// field must be non-nil.
|
||||
type RoleBindingRestrictionSpec struct {
|
||||
// UserRestriction matches against user subjects.
|
||||
// +nullable
|
||||
UserRestriction *UserRestriction `json:"userrestriction" protobuf:"bytes,1,opt,name=userrestriction"`
|
||||
|
||||
// GroupRestriction matches against group subjects.
|
||||
// +nullable
|
||||
GroupRestriction *GroupRestriction `json:"grouprestriction" protobuf:"bytes,2,opt,name=grouprestriction"`
|
||||
|
||||
// ServiceAccountRestriction matches against service-account subjects.
|
||||
// +nullable
|
||||
ServiceAccountRestriction *ServiceAccountRestriction `json:"serviceaccountrestriction" protobuf:"bytes,3,opt,name=serviceaccountrestriction"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// RoleBindingRestrictionList is a collection of RoleBindingRestriction objects.
|
||||
type RoleBindingRestrictionList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Items is a list of RoleBindingRestriction objects.
|
||||
Items []RoleBindingRestriction `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// UserRestriction matches a user either by a string match on the user name,
|
||||
// a string match on the name of a group to which the user belongs, or a label
|
||||
// selector applied to the user labels.
|
||||
type UserRestriction struct {
|
||||
// Users specifies a list of literal user names.
|
||||
Users []string `json:"users" protobuf:"bytes,1,rep,name=users"`
|
||||
|
||||
// Groups specifies a list of literal group names.
|
||||
// +nullable
|
||||
Groups []string `json:"groups" protobuf:"bytes,2,rep,name=groups"`
|
||||
|
||||
// Selectors specifies a list of label selectors over user labels.
|
||||
// +nullable
|
||||
Selectors []metav1.LabelSelector `json:"labels" protobuf:"bytes,3,rep,name=labels"`
|
||||
}
|
||||
|
||||
// GroupRestriction matches a group either by a string match on the group name
|
||||
// or a label selector applied to group labels.
|
||||
type GroupRestriction struct {
|
||||
// Groups is a list of groups used to match against an individual user's
|
||||
// groups. If the user is a member of one of the whitelisted groups, the user
|
||||
// is allowed to be bound to a role.
|
||||
// +nullable
|
||||
Groups []string `json:"groups" protobuf:"bytes,1,rep,name=groups"`
|
||||
|
||||
// Selectors specifies a list of label selectors over group labels.
|
||||
// +nullable
|
||||
Selectors []metav1.LabelSelector `json:"labels" protobuf:"bytes,2,rep,name=labels"`
|
||||
}
|
||||
|
||||
// ServiceAccountRestriction matches a service account by a string match on
|
||||
// either the service-account name or the name of the service account's
|
||||
// namespace.
|
||||
type ServiceAccountRestriction struct {
|
||||
// ServiceAccounts specifies a list of literal service-account names.
|
||||
ServiceAccounts []ServiceAccountReference `json:"serviceaccounts" protobuf:"bytes,1,rep,name=serviceaccounts"`
|
||||
|
||||
// Namespaces specifies a list of literal namespace names.
|
||||
Namespaces []string `json:"namespaces" protobuf:"bytes,2,rep,name=namespaces"`
|
||||
}
|
||||
|
||||
// ServiceAccountReference specifies a service account and namespace by their
|
||||
// names.
|
||||
type ServiceAccountReference struct {
|
||||
// Name is the name of the service account.
|
||||
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
|
||||
|
||||
// Namespace is the namespace of the service account. Service accounts from
|
||||
// inside the whitelisted namespaces are allowed to be bound to roles. If
|
||||
// Namespace is empty, then the namespace of the RoleBindingRestriction in
|
||||
// which the ServiceAccountReference is embedded is used.
|
||||
Namespace string `json:"namespace" protobuf:"bytes,2,opt,name=namespace"`
|
||||
}
|
||||
+993
@@ -0,0 +1,993 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Action) DeepCopyInto(out *Action) {
|
||||
*out = *in
|
||||
in.Content.DeepCopyInto(&out.Content)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Action.
|
||||
func (in *Action) DeepCopy() *Action {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Action)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClusterRole) DeepCopyInto(out *ClusterRole) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]PolicyRule, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.AggregationRule != nil {
|
||||
in, out := &in.AggregationRule, &out.AggregationRule
|
||||
*out = new(rbacv1.AggregationRule)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRole.
|
||||
func (in *ClusterRole) DeepCopy() *ClusterRole {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClusterRole)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ClusterRole) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClusterRoleBinding) DeepCopyInto(out *ClusterRoleBinding) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
if in.UserNames != nil {
|
||||
in, out := &in.UserNames, &out.UserNames
|
||||
*out = make(OptionalNames, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.GroupNames != nil {
|
||||
in, out := &in.GroupNames, &out.GroupNames
|
||||
*out = make(OptionalNames, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Subjects != nil {
|
||||
in, out := &in.Subjects, &out.Subjects
|
||||
*out = make([]corev1.ObjectReference, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.RoleRef = in.RoleRef
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRoleBinding.
|
||||
func (in *ClusterRoleBinding) DeepCopy() *ClusterRoleBinding {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClusterRoleBinding)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ClusterRoleBinding) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClusterRoleBindingList) DeepCopyInto(out *ClusterRoleBindingList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ClusterRoleBinding, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRoleBindingList.
|
||||
func (in *ClusterRoleBindingList) DeepCopy() *ClusterRoleBindingList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClusterRoleBindingList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ClusterRoleBindingList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClusterRoleList) DeepCopyInto(out *ClusterRoleList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ClusterRole, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRoleList.
|
||||
func (in *ClusterRoleList) DeepCopy() *ClusterRoleList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClusterRoleList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ClusterRoleList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *GroupRestriction) DeepCopyInto(out *GroupRestriction) {
|
||||
*out = *in
|
||||
if in.Groups != nil {
|
||||
in, out := &in.Groups, &out.Groups
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Selectors != nil {
|
||||
in, out := &in.Selectors, &out.Selectors
|
||||
*out = make([]metav1.LabelSelector, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupRestriction.
|
||||
func (in *GroupRestriction) DeepCopy() *GroupRestriction {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(GroupRestriction)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *IsPersonalSubjectAccessReview) DeepCopyInto(out *IsPersonalSubjectAccessReview) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IsPersonalSubjectAccessReview.
|
||||
func (in *IsPersonalSubjectAccessReview) DeepCopy() *IsPersonalSubjectAccessReview {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(IsPersonalSubjectAccessReview)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *IsPersonalSubjectAccessReview) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LocalResourceAccessReview) DeepCopyInto(out *LocalResourceAccessReview) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.Action.DeepCopyInto(&out.Action)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalResourceAccessReview.
|
||||
func (in *LocalResourceAccessReview) DeepCopy() *LocalResourceAccessReview {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(LocalResourceAccessReview)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *LocalResourceAccessReview) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LocalSubjectAccessReview) DeepCopyInto(out *LocalSubjectAccessReview) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.Action.DeepCopyInto(&out.Action)
|
||||
if in.GroupsSlice != nil {
|
||||
in, out := &in.GroupsSlice, &out.GroupsSlice
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Scopes != nil {
|
||||
in, out := &in.Scopes, &out.Scopes
|
||||
*out = make(OptionalScopes, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalSubjectAccessReview.
|
||||
func (in *LocalSubjectAccessReview) DeepCopy() *LocalSubjectAccessReview {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(LocalSubjectAccessReview)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *LocalSubjectAccessReview) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NamedClusterRole) DeepCopyInto(out *NamedClusterRole) {
|
||||
*out = *in
|
||||
in.Role.DeepCopyInto(&out.Role)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamedClusterRole.
|
||||
func (in *NamedClusterRole) DeepCopy() *NamedClusterRole {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NamedClusterRole)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NamedClusterRoleBinding) DeepCopyInto(out *NamedClusterRoleBinding) {
|
||||
*out = *in
|
||||
in.RoleBinding.DeepCopyInto(&out.RoleBinding)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamedClusterRoleBinding.
|
||||
func (in *NamedClusterRoleBinding) DeepCopy() *NamedClusterRoleBinding {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NamedClusterRoleBinding)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NamedRole) DeepCopyInto(out *NamedRole) {
|
||||
*out = *in
|
||||
in.Role.DeepCopyInto(&out.Role)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamedRole.
|
||||
func (in *NamedRole) DeepCopy() *NamedRole {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NamedRole)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NamedRoleBinding) DeepCopyInto(out *NamedRoleBinding) {
|
||||
*out = *in
|
||||
in.RoleBinding.DeepCopyInto(&out.RoleBinding)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamedRoleBinding.
|
||||
func (in *NamedRoleBinding) DeepCopy() *NamedRoleBinding {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NamedRoleBinding)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in OptionalNames) DeepCopyInto(out *OptionalNames) {
|
||||
{
|
||||
in := &in
|
||||
*out = make(OptionalNames, len(*in))
|
||||
copy(*out, *in)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OptionalNames.
|
||||
func (in OptionalNames) DeepCopy() OptionalNames {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(OptionalNames)
|
||||
in.DeepCopyInto(out)
|
||||
return *out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in OptionalScopes) DeepCopyInto(out *OptionalScopes) {
|
||||
{
|
||||
in := &in
|
||||
*out = make(OptionalScopes, len(*in))
|
||||
copy(*out, *in)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OptionalScopes.
|
||||
func (in OptionalScopes) DeepCopy() OptionalScopes {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(OptionalScopes)
|
||||
in.DeepCopyInto(out)
|
||||
return *out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *PolicyRule) DeepCopyInto(out *PolicyRule) {
|
||||
*out = *in
|
||||
if in.Verbs != nil {
|
||||
in, out := &in.Verbs, &out.Verbs
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
in.AttributeRestrictions.DeepCopyInto(&out.AttributeRestrictions)
|
||||
if in.APIGroups != nil {
|
||||
in, out := &in.APIGroups, &out.APIGroups
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Resources != nil {
|
||||
in, out := &in.Resources, &out.Resources
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.ResourceNames != nil {
|
||||
in, out := &in.ResourceNames, &out.ResourceNames
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.NonResourceURLsSlice != nil {
|
||||
in, out := &in.NonResourceURLsSlice, &out.NonResourceURLsSlice
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyRule.
|
||||
func (in *PolicyRule) DeepCopy() *PolicyRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(PolicyRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResourceAccessReview) DeepCopyInto(out *ResourceAccessReview) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.Action.DeepCopyInto(&out.Action)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceAccessReview.
|
||||
func (in *ResourceAccessReview) DeepCopy() *ResourceAccessReview {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ResourceAccessReview)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ResourceAccessReview) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResourceAccessReviewResponse) DeepCopyInto(out *ResourceAccessReviewResponse) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.UsersSlice != nil {
|
||||
in, out := &in.UsersSlice, &out.UsersSlice
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.GroupsSlice != nil {
|
||||
in, out := &in.GroupsSlice, &out.GroupsSlice
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceAccessReviewResponse.
|
||||
func (in *ResourceAccessReviewResponse) DeepCopy() *ResourceAccessReviewResponse {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ResourceAccessReviewResponse)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ResourceAccessReviewResponse) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Role) DeepCopyInto(out *Role) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]PolicyRule, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Role.
|
||||
func (in *Role) DeepCopy() *Role {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Role)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Role) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RoleBinding) DeepCopyInto(out *RoleBinding) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
if in.UserNames != nil {
|
||||
in, out := &in.UserNames, &out.UserNames
|
||||
*out = make(OptionalNames, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.GroupNames != nil {
|
||||
in, out := &in.GroupNames, &out.GroupNames
|
||||
*out = make(OptionalNames, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Subjects != nil {
|
||||
in, out := &in.Subjects, &out.Subjects
|
||||
*out = make([]corev1.ObjectReference, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.RoleRef = in.RoleRef
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleBinding.
|
||||
func (in *RoleBinding) DeepCopy() *RoleBinding {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RoleBinding)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *RoleBinding) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RoleBindingList) DeepCopyInto(out *RoleBindingList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]RoleBinding, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleBindingList.
|
||||
func (in *RoleBindingList) DeepCopy() *RoleBindingList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RoleBindingList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *RoleBindingList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RoleBindingRestriction) DeepCopyInto(out *RoleBindingRestriction) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleBindingRestriction.
|
||||
func (in *RoleBindingRestriction) DeepCopy() *RoleBindingRestriction {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RoleBindingRestriction)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *RoleBindingRestriction) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RoleBindingRestrictionList) DeepCopyInto(out *RoleBindingRestrictionList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]RoleBindingRestriction, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleBindingRestrictionList.
|
||||
func (in *RoleBindingRestrictionList) DeepCopy() *RoleBindingRestrictionList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RoleBindingRestrictionList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *RoleBindingRestrictionList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RoleBindingRestrictionSpec) DeepCopyInto(out *RoleBindingRestrictionSpec) {
|
||||
*out = *in
|
||||
if in.UserRestriction != nil {
|
||||
in, out := &in.UserRestriction, &out.UserRestriction
|
||||
*out = new(UserRestriction)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.GroupRestriction != nil {
|
||||
in, out := &in.GroupRestriction, &out.GroupRestriction
|
||||
*out = new(GroupRestriction)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ServiceAccountRestriction != nil {
|
||||
in, out := &in.ServiceAccountRestriction, &out.ServiceAccountRestriction
|
||||
*out = new(ServiceAccountRestriction)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleBindingRestrictionSpec.
|
||||
func (in *RoleBindingRestrictionSpec) DeepCopy() *RoleBindingRestrictionSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RoleBindingRestrictionSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RoleList) DeepCopyInto(out *RoleList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Role, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleList.
|
||||
func (in *RoleList) DeepCopy() *RoleList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RoleList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *RoleList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SelfSubjectRulesReview) DeepCopyInto(out *SelfSubjectRulesReview) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SelfSubjectRulesReview.
|
||||
func (in *SelfSubjectRulesReview) DeepCopy() *SelfSubjectRulesReview {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SelfSubjectRulesReview)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *SelfSubjectRulesReview) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SelfSubjectRulesReviewSpec) DeepCopyInto(out *SelfSubjectRulesReviewSpec) {
|
||||
*out = *in
|
||||
if in.Scopes != nil {
|
||||
in, out := &in.Scopes, &out.Scopes
|
||||
*out = make(OptionalScopes, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SelfSubjectRulesReviewSpec.
|
||||
func (in *SelfSubjectRulesReviewSpec) DeepCopy() *SelfSubjectRulesReviewSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SelfSubjectRulesReviewSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServiceAccountReference) DeepCopyInto(out *ServiceAccountReference) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccountReference.
|
||||
func (in *ServiceAccountReference) DeepCopy() *ServiceAccountReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServiceAccountReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServiceAccountRestriction) DeepCopyInto(out *ServiceAccountRestriction) {
|
||||
*out = *in
|
||||
if in.ServiceAccounts != nil {
|
||||
in, out := &in.ServiceAccounts, &out.ServiceAccounts
|
||||
*out = make([]ServiceAccountReference, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Namespaces != nil {
|
||||
in, out := &in.Namespaces, &out.Namespaces
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccountRestriction.
|
||||
func (in *ServiceAccountRestriction) DeepCopy() *ServiceAccountRestriction {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServiceAccountRestriction)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SubjectAccessReview) DeepCopyInto(out *SubjectAccessReview) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.Action.DeepCopyInto(&out.Action)
|
||||
if in.GroupsSlice != nil {
|
||||
in, out := &in.GroupsSlice, &out.GroupsSlice
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Scopes != nil {
|
||||
in, out := &in.Scopes, &out.Scopes
|
||||
*out = make(OptionalScopes, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubjectAccessReview.
|
||||
func (in *SubjectAccessReview) DeepCopy() *SubjectAccessReview {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SubjectAccessReview)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *SubjectAccessReview) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SubjectAccessReviewResponse) DeepCopyInto(out *SubjectAccessReviewResponse) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubjectAccessReviewResponse.
|
||||
func (in *SubjectAccessReviewResponse) DeepCopy() *SubjectAccessReviewResponse {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SubjectAccessReviewResponse)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *SubjectAccessReviewResponse) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SubjectRulesReview) DeepCopyInto(out *SubjectRulesReview) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubjectRulesReview.
|
||||
func (in *SubjectRulesReview) DeepCopy() *SubjectRulesReview {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SubjectRulesReview)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *SubjectRulesReview) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SubjectRulesReviewSpec) DeepCopyInto(out *SubjectRulesReviewSpec) {
|
||||
*out = *in
|
||||
if in.Groups != nil {
|
||||
in, out := &in.Groups, &out.Groups
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Scopes != nil {
|
||||
in, out := &in.Scopes, &out.Scopes
|
||||
*out = make(OptionalScopes, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubjectRulesReviewSpec.
|
||||
func (in *SubjectRulesReviewSpec) DeepCopy() *SubjectRulesReviewSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SubjectRulesReviewSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SubjectRulesReviewStatus) DeepCopyInto(out *SubjectRulesReviewStatus) {
|
||||
*out = *in
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]PolicyRule, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubjectRulesReviewStatus.
|
||||
func (in *SubjectRulesReviewStatus) DeepCopy() *SubjectRulesReviewStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SubjectRulesReviewStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UserRestriction) DeepCopyInto(out *UserRestriction) {
|
||||
*out = *in
|
||||
if in.Users != nil {
|
||||
in, out := &in.Users, &out.Users
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Groups != nil {
|
||||
in, out := &in.Groups, &out.Groups
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Selectors != nil {
|
||||
in, out := &in.Selectors, &out.Selectors
|
||||
*out = make([]metav1.LabelSelector, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserRestriction.
|
||||
func (in *UserRestriction) DeepCopy() *UserRestriction {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(UserRestriction)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
Generated
Vendored
+354
@@ -0,0 +1,354 @@
|
||||
package v1
|
||||
|
||||
// This file contains a collection of methods that can be used from go-restful to
|
||||
// generate Swagger API documentation for its models. Please read this PR for more
|
||||
// information on the implementation: https://github.com/emicklei/go-restful/pull/215
|
||||
//
|
||||
// TODOs are ignored from the parser (e.g. TODO(andronat):... || TODO:...) if and only if
|
||||
// they are on one line! For multiple line or blocks that you want to ignore use ---.
|
||||
// Any context after a --- is ignored.
|
||||
//
|
||||
// Those methods can be generated by using hack/update-swagger-docs.sh
|
||||
|
||||
// AUTO-GENERATED FUNCTIONS START HERE
|
||||
var map_Action = map[string]string{
|
||||
"": "Action describes a request to the API server",
|
||||
"namespace": "Namespace is the namespace of the action being requested. Currently, there is no distinction between no namespace and all namespaces",
|
||||
"verb": "Verb is one of: get, list, watch, create, update, delete",
|
||||
"resourceAPIGroup": "Group is the API group of the resource Serialized as resourceAPIGroup to avoid confusion with the 'groups' field when inlined",
|
||||
"resourceAPIVersion": "Version is the API version of the resource Serialized as resourceAPIVersion to avoid confusion with TypeMeta.apiVersion and ObjectMeta.resourceVersion when inlined",
|
||||
"resource": "Resource is one of the existing resource types",
|
||||
"resourceName": "ResourceName is the name of the resource being requested for a \"get\" or deleted for a \"delete\"",
|
||||
"path": "Path is the path of a non resource URL",
|
||||
"isNonResourceURL": "IsNonResourceURL is true if this is a request for a non-resource URL (outside of the resource hierarchy)",
|
||||
"content": "Content is the actual content of the request for create and update",
|
||||
}
|
||||
|
||||
func (Action) SwaggerDoc() map[string]string {
|
||||
return map_Action
|
||||
}
|
||||
|
||||
var map_ClusterRole = map[string]string{
|
||||
"": "ClusterRole is a logical grouping of PolicyRules that can be referenced as a unit by ClusterRoleBindings.",
|
||||
"rules": "Rules holds all the PolicyRules for this ClusterRole",
|
||||
"aggregationRule": "AggregationRule is an optional field that describes how to build the Rules for this ClusterRole. If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be stomped by the controller.",
|
||||
}
|
||||
|
||||
func (ClusterRole) SwaggerDoc() map[string]string {
|
||||
return map_ClusterRole
|
||||
}
|
||||
|
||||
var map_ClusterRoleBinding = map[string]string{
|
||||
"": "ClusterRoleBinding references a ClusterRole, but not contain it. It can reference any ClusterRole in the same namespace or in the global namespace. It adds who information via (Users and Groups) OR Subjects and namespace information by which namespace it exists in. ClusterRoleBindings in a given namespace only have effect in that namespace (excepting the master namespace which has power in all namespaces).",
|
||||
"userNames": "UserNames holds all the usernames directly bound to the role. This field should only be specified when supporting legacy clients and servers. See Subjects for further details.",
|
||||
"groupNames": "GroupNames holds all the groups directly bound to the role. This field should only be specified when supporting legacy clients and servers. See Subjects for further details.",
|
||||
"subjects": "Subjects hold object references to authorize with this rule. This field is ignored if UserNames or GroupNames are specified to support legacy clients and servers. Thus newer clients that do not need to support backwards compatibility should send only fully qualified Subjects and should omit the UserNames and GroupNames fields. Clients that need to support backwards compatibility can use this field to build the UserNames and GroupNames.",
|
||||
"roleRef": "RoleRef can only reference the current namespace and the global namespace. If the ClusterRoleRef cannot be resolved, the Authorizer must return an error. Since Policy is a singleton, this is sufficient knowledge to locate a role.",
|
||||
}
|
||||
|
||||
func (ClusterRoleBinding) SwaggerDoc() map[string]string {
|
||||
return map_ClusterRoleBinding
|
||||
}
|
||||
|
||||
var map_ClusterRoleBindingList = map[string]string{
|
||||
"": "ClusterRoleBindingList is a collection of ClusterRoleBindings",
|
||||
"items": "Items is a list of ClusterRoleBindings",
|
||||
}
|
||||
|
||||
func (ClusterRoleBindingList) SwaggerDoc() map[string]string {
|
||||
return map_ClusterRoleBindingList
|
||||
}
|
||||
|
||||
var map_ClusterRoleList = map[string]string{
|
||||
"": "ClusterRoleList is a collection of ClusterRoles",
|
||||
"items": "Items is a list of ClusterRoles",
|
||||
}
|
||||
|
||||
func (ClusterRoleList) SwaggerDoc() map[string]string {
|
||||
return map_ClusterRoleList
|
||||
}
|
||||
|
||||
var map_GroupRestriction = map[string]string{
|
||||
"": "GroupRestriction matches a group either by a string match on the group name or a label selector applied to group labels.",
|
||||
"groups": "Groups is a list of groups used to match against an individual user's groups. If the user is a member of one of the whitelisted groups, the user is allowed to be bound to a role.",
|
||||
"labels": "Selectors specifies a list of label selectors over group labels.",
|
||||
}
|
||||
|
||||
func (GroupRestriction) SwaggerDoc() map[string]string {
|
||||
return map_GroupRestriction
|
||||
}
|
||||
|
||||
var map_IsPersonalSubjectAccessReview = map[string]string{
|
||||
"": "IsPersonalSubjectAccessReview is a marker for PolicyRule.AttributeRestrictions that denotes that subjectaccessreviews on self should be allowed",
|
||||
}
|
||||
|
||||
func (IsPersonalSubjectAccessReview) SwaggerDoc() map[string]string {
|
||||
return map_IsPersonalSubjectAccessReview
|
||||
}
|
||||
|
||||
var map_LocalResourceAccessReview = map[string]string{
|
||||
"": "LocalResourceAccessReview is a means to request a list of which users and groups are authorized to perform the action specified by spec in a particular namespace",
|
||||
}
|
||||
|
||||
func (LocalResourceAccessReview) SwaggerDoc() map[string]string {
|
||||
return map_LocalResourceAccessReview
|
||||
}
|
||||
|
||||
var map_LocalSubjectAccessReview = map[string]string{
|
||||
"": "LocalSubjectAccessReview is an object for requesting information about whether a user or group can perform an action in a particular namespace",
|
||||
"user": "User is optional. If both User and Groups are empty, the current authenticated user is used.",
|
||||
"groups": "Groups is optional. Groups is the list of groups to which the User belongs.",
|
||||
"scopes": "Scopes to use for the evaluation. Empty means \"use the unscoped (full) permissions of the user/groups\". Nil for a self-SAR, means \"use the scopes on this request\". Nil for a regular SAR, means the same as empty.",
|
||||
}
|
||||
|
||||
func (LocalSubjectAccessReview) SwaggerDoc() map[string]string {
|
||||
return map_LocalSubjectAccessReview
|
||||
}
|
||||
|
||||
var map_NamedClusterRole = map[string]string{
|
||||
"": "NamedClusterRole relates a name with a cluster role",
|
||||
"name": "Name is the name of the cluster role",
|
||||
"role": "Role is the cluster role being named",
|
||||
}
|
||||
|
||||
func (NamedClusterRole) SwaggerDoc() map[string]string {
|
||||
return map_NamedClusterRole
|
||||
}
|
||||
|
||||
var map_NamedClusterRoleBinding = map[string]string{
|
||||
"": "NamedClusterRoleBinding relates a name with a cluster role binding",
|
||||
"name": "Name is the name of the cluster role binding",
|
||||
"roleBinding": "RoleBinding is the cluster role binding being named",
|
||||
}
|
||||
|
||||
func (NamedClusterRoleBinding) SwaggerDoc() map[string]string {
|
||||
return map_NamedClusterRoleBinding
|
||||
}
|
||||
|
||||
var map_NamedRole = map[string]string{
|
||||
"": "NamedRole relates a Role with a name",
|
||||
"name": "Name is the name of the role",
|
||||
"role": "Role is the role being named",
|
||||
}
|
||||
|
||||
func (NamedRole) SwaggerDoc() map[string]string {
|
||||
return map_NamedRole
|
||||
}
|
||||
|
||||
var map_NamedRoleBinding = map[string]string{
|
||||
"": "NamedRoleBinding relates a role binding with a name",
|
||||
"name": "Name is the name of the role binding",
|
||||
"roleBinding": "RoleBinding is the role binding being named",
|
||||
}
|
||||
|
||||
func (NamedRoleBinding) SwaggerDoc() map[string]string {
|
||||
return map_NamedRoleBinding
|
||||
}
|
||||
|
||||
var map_PolicyRule = map[string]string{
|
||||
"": "PolicyRule holds information that describes a policy rule, but does not contain information about who the rule applies to or which namespace the rule applies to.",
|
||||
"verbs": "Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule. VerbAll represents all kinds.",
|
||||
"attributeRestrictions": "AttributeRestrictions will vary depending on what the Authorizer/AuthorizationAttributeBuilder pair supports. If the Authorizer does not recognize how to handle the AttributeRestrictions, the Authorizer should report an error.",
|
||||
"apiGroups": "APIGroups is the name of the APIGroup that contains the resources. If this field is empty, then both kubernetes and origin API groups are assumed. That means that if an action is requested against one of the enumerated resources in either the kubernetes or the origin API group, the request will be allowed",
|
||||
"resources": "Resources is a list of resources this rule applies to. ResourceAll represents all resources.",
|
||||
"resourceNames": "ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.",
|
||||
"nonResourceURLs": "NonResourceURLsSlice is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path This name is intentionally different than the internal type so that the DefaultConvert works nicely and because the ordering may be different.",
|
||||
}
|
||||
|
||||
func (PolicyRule) SwaggerDoc() map[string]string {
|
||||
return map_PolicyRule
|
||||
}
|
||||
|
||||
var map_ResourceAccessReview = map[string]string{
|
||||
"": "ResourceAccessReview is a means to request a list of which users and groups are authorized to perform the action specified by spec",
|
||||
}
|
||||
|
||||
func (ResourceAccessReview) SwaggerDoc() map[string]string {
|
||||
return map_ResourceAccessReview
|
||||
}
|
||||
|
||||
var map_ResourceAccessReviewResponse = map[string]string{
|
||||
"": "ResourceAccessReviewResponse describes who can perform the action",
|
||||
"namespace": "Namespace is the namespace used for the access review",
|
||||
"users": "UsersSlice is the list of users who can perform the action",
|
||||
"groups": "GroupsSlice is the list of groups who can perform the action",
|
||||
"evalutionError": "EvaluationError is an indication that some error occurred during resolution, but partial results can still be returned. It is entirely possible to get an error and be able to continue determine authorization status in spite of it. This is most common when a bound role is missing, but enough roles are still present and bound to reason about the request.",
|
||||
}
|
||||
|
||||
func (ResourceAccessReviewResponse) SwaggerDoc() map[string]string {
|
||||
return map_ResourceAccessReviewResponse
|
||||
}
|
||||
|
||||
var map_Role = map[string]string{
|
||||
"": "Role is a logical grouping of PolicyRules that can be referenced as a unit by RoleBindings.",
|
||||
"rules": "Rules holds all the PolicyRules for this Role",
|
||||
}
|
||||
|
||||
func (Role) SwaggerDoc() map[string]string {
|
||||
return map_Role
|
||||
}
|
||||
|
||||
var map_RoleBinding = map[string]string{
|
||||
"": "RoleBinding references a Role, but not contain it. It can reference any Role in the same namespace or in the global namespace. It adds who information via (Users and Groups) OR Subjects and namespace information by which namespace it exists in. RoleBindings in a given namespace only have effect in that namespace (excepting the master namespace which has power in all namespaces).",
|
||||
"userNames": "UserNames holds all the usernames directly bound to the role. This field should only be specified when supporting legacy clients and servers. See Subjects for further details.",
|
||||
"groupNames": "GroupNames holds all the groups directly bound to the role. This field should only be specified when supporting legacy clients and servers. See Subjects for further details.",
|
||||
"subjects": "Subjects hold object references to authorize with this rule. This field is ignored if UserNames or GroupNames are specified to support legacy clients and servers. Thus newer clients that do not need to support backwards compatibility should send only fully qualified Subjects and should omit the UserNames and GroupNames fields. Clients that need to support backwards compatibility can use this field to build the UserNames and GroupNames.",
|
||||
"roleRef": "RoleRef can only reference the current namespace and the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error. Since Policy is a singleton, this is sufficient knowledge to locate a role.",
|
||||
}
|
||||
|
||||
func (RoleBinding) SwaggerDoc() map[string]string {
|
||||
return map_RoleBinding
|
||||
}
|
||||
|
||||
var map_RoleBindingList = map[string]string{
|
||||
"": "RoleBindingList is a collection of RoleBindings",
|
||||
"items": "Items is a list of RoleBindings",
|
||||
}
|
||||
|
||||
func (RoleBindingList) SwaggerDoc() map[string]string {
|
||||
return map_RoleBindingList
|
||||
}
|
||||
|
||||
var map_RoleBindingRestriction = map[string]string{
|
||||
"": "RoleBindingRestriction is an object that can be matched against a subject (user, group, or service account) to determine whether rolebindings on that subject are allowed in the namespace to which the RoleBindingRestriction belongs. If any one of those RoleBindingRestriction objects matches a subject, rolebindings on that subject in the namespace are allowed.",
|
||||
"spec": "Spec defines the matcher.",
|
||||
}
|
||||
|
||||
func (RoleBindingRestriction) SwaggerDoc() map[string]string {
|
||||
return map_RoleBindingRestriction
|
||||
}
|
||||
|
||||
var map_RoleBindingRestrictionList = map[string]string{
|
||||
"": "RoleBindingRestrictionList is a collection of RoleBindingRestriction objects.",
|
||||
"items": "Items is a list of RoleBindingRestriction objects.",
|
||||
}
|
||||
|
||||
func (RoleBindingRestrictionList) SwaggerDoc() map[string]string {
|
||||
return map_RoleBindingRestrictionList
|
||||
}
|
||||
|
||||
var map_RoleBindingRestrictionSpec = map[string]string{
|
||||
"": "RoleBindingRestrictionSpec defines a rolebinding restriction. Exactly one field must be non-nil.",
|
||||
"userrestriction": "UserRestriction matches against user subjects.",
|
||||
"grouprestriction": "GroupRestriction matches against group subjects.",
|
||||
"serviceaccountrestriction": "ServiceAccountRestriction matches against service-account subjects.",
|
||||
}
|
||||
|
||||
func (RoleBindingRestrictionSpec) SwaggerDoc() map[string]string {
|
||||
return map_RoleBindingRestrictionSpec
|
||||
}
|
||||
|
||||
var map_RoleList = map[string]string{
|
||||
"": "RoleList is a collection of Roles",
|
||||
"items": "Items is a list of Roles",
|
||||
}
|
||||
|
||||
func (RoleList) SwaggerDoc() map[string]string {
|
||||
return map_RoleList
|
||||
}
|
||||
|
||||
var map_SelfSubjectRulesReview = map[string]string{
|
||||
"": "SelfSubjectRulesReview is a resource you can create to determine which actions you can perform in a namespace",
|
||||
"spec": "Spec adds information about how to conduct the check",
|
||||
"status": "Status is completed by the server to tell which permissions you have",
|
||||
}
|
||||
|
||||
func (SelfSubjectRulesReview) SwaggerDoc() map[string]string {
|
||||
return map_SelfSubjectRulesReview
|
||||
}
|
||||
|
||||
var map_SelfSubjectRulesReviewSpec = map[string]string{
|
||||
"": "SelfSubjectRulesReviewSpec adds information about how to conduct the check",
|
||||
"scopes": "Scopes to use for the evaluation. Empty means \"use the unscoped (full) permissions of the user/groups\". Nil means \"use the scopes on this request\".",
|
||||
}
|
||||
|
||||
func (SelfSubjectRulesReviewSpec) SwaggerDoc() map[string]string {
|
||||
return map_SelfSubjectRulesReviewSpec
|
||||
}
|
||||
|
||||
var map_ServiceAccountReference = map[string]string{
|
||||
"": "ServiceAccountReference specifies a service account and namespace by their names.",
|
||||
"name": "Name is the name of the service account.",
|
||||
"namespace": "Namespace is the namespace of the service account. Service accounts from inside the whitelisted namespaces are allowed to be bound to roles. If Namespace is empty, then the namespace of the RoleBindingRestriction in which the ServiceAccountReference is embedded is used.",
|
||||
}
|
||||
|
||||
func (ServiceAccountReference) SwaggerDoc() map[string]string {
|
||||
return map_ServiceAccountReference
|
||||
}
|
||||
|
||||
var map_ServiceAccountRestriction = map[string]string{
|
||||
"": "ServiceAccountRestriction matches a service account by a string match on either the service-account name or the name of the service account's namespace.",
|
||||
"serviceaccounts": "ServiceAccounts specifies a list of literal service-account names.",
|
||||
"namespaces": "Namespaces specifies a list of literal namespace names.",
|
||||
}
|
||||
|
||||
func (ServiceAccountRestriction) SwaggerDoc() map[string]string {
|
||||
return map_ServiceAccountRestriction
|
||||
}
|
||||
|
||||
var map_SubjectAccessReview = map[string]string{
|
||||
"": "SubjectAccessReview is an object for requesting information about whether a user or group can perform an action",
|
||||
"user": "User is optional. If both User and Groups are empty, the current authenticated user is used.",
|
||||
"groups": "GroupsSlice is optional. Groups is the list of groups to which the User belongs.",
|
||||
"scopes": "Scopes to use for the evaluation. Empty means \"use the unscoped (full) permissions of the user/groups\". Nil for a self-SAR, means \"use the scopes on this request\". Nil for a regular SAR, means the same as empty.",
|
||||
}
|
||||
|
||||
func (SubjectAccessReview) SwaggerDoc() map[string]string {
|
||||
return map_SubjectAccessReview
|
||||
}
|
||||
|
||||
var map_SubjectAccessReviewResponse = map[string]string{
|
||||
"": "SubjectAccessReviewResponse describes whether or not a user or group can perform an action",
|
||||
"namespace": "Namespace is the namespace used for the access review",
|
||||
"allowed": "Allowed is required. True if the action would be allowed, false otherwise.",
|
||||
"reason": "Reason is optional. It indicates why a request was allowed or denied.",
|
||||
"evaluationError": "EvaluationError is an indication that some error occurred during the authorization check. It is entirely possible to get an error and be able to continue determine authorization status in spite of it. This is most common when a bound role is missing, but enough roles are still present and bound to reason about the request.",
|
||||
}
|
||||
|
||||
func (SubjectAccessReviewResponse) SwaggerDoc() map[string]string {
|
||||
return map_SubjectAccessReviewResponse
|
||||
}
|
||||
|
||||
var map_SubjectRulesReview = map[string]string{
|
||||
"": "SubjectRulesReview is a resource you can create to determine which actions another user can perform in a namespace",
|
||||
"spec": "Spec adds information about how to conduct the check",
|
||||
"status": "Status is completed by the server to tell which permissions you have",
|
||||
}
|
||||
|
||||
func (SubjectRulesReview) SwaggerDoc() map[string]string {
|
||||
return map_SubjectRulesReview
|
||||
}
|
||||
|
||||
var map_SubjectRulesReviewSpec = map[string]string{
|
||||
"": "SubjectRulesReviewSpec adds information about how to conduct the check",
|
||||
"user": "User is optional. At least one of User and Groups must be specified.",
|
||||
"groups": "Groups is optional. Groups is the list of groups to which the User belongs. At least one of User and Groups must be specified.",
|
||||
"scopes": "Scopes to use for the evaluation. Empty means \"use the unscoped (full) permissions of the user/groups\".",
|
||||
}
|
||||
|
||||
func (SubjectRulesReviewSpec) SwaggerDoc() map[string]string {
|
||||
return map_SubjectRulesReviewSpec
|
||||
}
|
||||
|
||||
var map_SubjectRulesReviewStatus = map[string]string{
|
||||
"": "SubjectRulesReviewStatus is contains the result of a rules check",
|
||||
"rules": "Rules is the list of rules (no particular sort) that are allowed for the subject",
|
||||
"evaluationError": "EvaluationError can appear in combination with Rules. It means some error happened during evaluation that may have prevented additional rules from being populated.",
|
||||
}
|
||||
|
||||
func (SubjectRulesReviewStatus) SwaggerDoc() map[string]string {
|
||||
return map_SubjectRulesReviewStatus
|
||||
}
|
||||
|
||||
var map_UserRestriction = map[string]string{
|
||||
"": "UserRestriction matches a user either by a string match on the user name, a string match on the name of a group to which the user belongs, or a label selector applied to the user labels.",
|
||||
"users": "Users specifies a list of literal user names.",
|
||||
"groups": "Groups specifies a list of literal group names.",
|
||||
"labels": "Selectors specifies a list of label selectors over user labels.",
|
||||
}
|
||||
|
||||
func (UserRestriction) SwaggerDoc() map[string]string {
|
||||
return map_UserRestriction
|
||||
}
|
||||
|
||||
// AUTO-GENERATED FUNCTIONS END HERE
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
reviewers:
|
||||
- bparees
|
||||
- gabemontero
|
||||
- jim-minter
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
buildv1 "github.com/openshift/api/build/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
GroupName = "build.openshift.io"
|
||||
)
|
||||
|
||||
var (
|
||||
schemeBuilder = runtime.NewSchemeBuilder(buildv1.Install)
|
||||
// Install is a function which adds every version of this group to a scheme
|
||||
Install = schemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return schema.GroupResource{Group: GroupName, Resource: resource}
|
||||
}
|
||||
|
||||
func Kind(kind string) schema.GroupKind {
|
||||
return schema.GroupKind{Group: GroupName, Kind: kind}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user