mirror of
https://github.com/rancher/norman.git
synced 2025-09-05 01:00:36 +00:00
Update vendor
This commit is contained in:
10
vendor.conf
10
vendor.conf
@@ -1,8 +1,8 @@
|
||||
# package
|
||||
github.com/rancher/norman
|
||||
|
||||
k8s.io/kubernetes v1.12.1-lite7 https://github.com/ibuildthecloud/k3s.git transitive=true,staging=true
|
||||
github.com/maruel/panicparse c0182c169410cfa80c7e8f046dad208eaef91338
|
||||
bitbucket.org/ww/goautoneg a547fc61f48d567d5b4ec6f8aee5573d8efce11d https://github.com/rancher/goautoneg.git
|
||||
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
|
||||
github.com/gorilla/mux v1.6.1
|
||||
k8s.io/kubernetes v1.12.2-lite1 https://github.com/ibuildthecloud/k3s.git transitive=true,staging=true
|
||||
github.com/maruel/panicparse c0182c169410cfa80c7e8f046dad208eaef91338
|
||||
bitbucket.org/ww/goautoneg a547fc61f48d567d5b4ec6f8aee5573d8efce11d https://github.com/rancher/goautoneg.git
|
||||
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
|
||||
github.com/gorilla/mux v1.6.1
|
||||
|
2
vendor/github.com/ibuildthecloud/kvsql/clientv3/driver/generic.go
generated
vendored
2
vendor/github.com/ibuildthecloud/kvsql/clientv3/driver/generic.go
generated
vendored
@@ -8,8 +8,8 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/ibuildthecloud/kvsql/pkg/broadcast"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rancher/norman/pkg/broadcast"
|
||||
"github.com/sirupsen/logrus"
|
||||
utiltrace "k8s.io/apiserver/pkg/util/trace"
|
||||
)
|
||||
|
5
vendor/github.com/rancher/norman/.dockerignore
generated
vendored
5
vendor/github.com/rancher/norman/.dockerignore
generated
vendored
@@ -1,5 +0,0 @@
|
||||
./bin
|
||||
./.dapper
|
||||
./dist
|
||||
./.trash-cache
|
||||
./.idea
|
9
vendor/github.com/rancher/norman/.drone.yml
generated
vendored
9
vendor/github.com/rancher/norman/.drone.yml
generated
vendored
@@ -1,9 +0,0 @@
|
||||
---
|
||||
pipeline:
|
||||
build:
|
||||
privileged: true
|
||||
image: rancher/dapper:1.11.2
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
commands:
|
||||
- dapper ci
|
7
vendor/github.com/rancher/norman/.gitignore
generated
vendored
7
vendor/github.com/rancher/norman/.gitignore
generated
vendored
@@ -1,7 +0,0 @@
|
||||
/.idea
|
||||
/.dapper
|
||||
/bin
|
||||
/dist
|
||||
*.swp
|
||||
/.trash-cache
|
||||
/trash.lock
|
16
vendor/github.com/rancher/norman/Dockerfile.dapper
generated
vendored
16
vendor/github.com/rancher/norman/Dockerfile.dapper
generated
vendored
@@ -1,16 +0,0 @@
|
||||
FROM golang:1.11-alpine
|
||||
|
||||
RUN apk -U add bash git gcc musl-dev docker
|
||||
RUN go get -d golang.org/x/lint/golint && \
|
||||
git -C /go/src/golang.org/x/lint/golint checkout -b current 06c8688daad7faa9da5a0c2f163a3d14aac986ca && \
|
||||
go install golang.org/x/lint/golint && \
|
||||
rm -rf /go/src /go/pkg
|
||||
|
||||
ENV DAPPER_SOURCE /go/src/github.com/rancher/norman/
|
||||
ENV DAPPER_OUTPUT ./bin ./dist
|
||||
ENV DAPPER_DOCKER_SOCKET true
|
||||
ENV HOME ${DAPPER_SOURCE}
|
||||
WORKDIR ${DAPPER_SOURCE}
|
||||
|
||||
ENTRYPOINT ["./scripts/entry"]
|
||||
CMD ["ci"]
|
177
vendor/github.com/rancher/norman/LICENSE
generated
vendored
177
vendor/github.com/rancher/norman/LICENSE
generated
vendored
@@ -1,177 +0,0 @@
|
||||
|
||||
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
|
15
vendor/github.com/rancher/norman/Makefile
generated
vendored
15
vendor/github.com/rancher/norman/Makefile
generated
vendored
@@ -1,15 +0,0 @@
|
||||
TARGETS := $(shell ls scripts)
|
||||
|
||||
.dapper:
|
||||
@echo Downloading dapper
|
||||
@curl -sL https://releases.rancher.com/dapper/latest/dapper-`uname -s`-`uname -m` > .dapper.tmp
|
||||
@@chmod +x .dapper.tmp
|
||||
@./.dapper.tmp -v
|
||||
@mv .dapper.tmp .dapper
|
||||
|
||||
$(TARGETS): .dapper
|
||||
./.dapper $@
|
||||
|
||||
.DEFAULT_GOAL := ci
|
||||
|
||||
.PHONY: $(TARGETS)
|
78
vendor/github.com/rancher/norman/README.md
generated
vendored
78
vendor/github.com/rancher/norman/README.md
generated
vendored
@@ -1,78 +0,0 @@
|
||||
Norman
|
||||
========
|
||||
|
||||
An API framework for Building [Rancher Style APIs](https://github.com/rancher/api-spec/) backed by K8s CustomResources.
|
||||
|
||||
## Building
|
||||
|
||||
`make`
|
||||
|
||||
## Example
|
||||
|
||||
Refer to `examples/`
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/rancher/norman/generator"
|
||||
"github.com/rancher/norman/server"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
type Foo struct {
|
||||
types.Resource
|
||||
Name string `json:"name"`
|
||||
Foo string `json:"foo"`
|
||||
SubThing Baz `json:"subThing"`
|
||||
}
|
||||
|
||||
type Baz struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
var (
|
||||
version = types.APIVersion{
|
||||
Version: "v1",
|
||||
Group: "io.cattle.core.example",
|
||||
Path: "/example/v1",
|
||||
}
|
||||
|
||||
Schemas = types.NewSchemas()
|
||||
)
|
||||
|
||||
func main() {
|
||||
if _, err := Schemas.Import(&version, Foo{}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
server, err := server.NewAPIServer(context.Background(), os.Getenv("KUBECONFIG"), Schemas)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println("Listening on 0.0.0.0:1234")
|
||||
http.ListenAndServe("0.0.0.0:1234", server)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## License
|
||||
Copyright (c) 2014-2017 [Rancher Labs, Inc.](http://rancher.com)
|
||||
|
||||
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](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.
|
87
vendor/github.com/rancher/norman/api/access/list.go
generated
vendored
87
vendor/github.com/rancher/norman/api/access/list.go
generated
vendored
@@ -1,87 +0,0 @@
|
||||
package access
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/rancher/norman/parse/builder"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
)
|
||||
|
||||
func Create(context *types.APIContext, version *types.APIVersion, typeName string, data map[string]interface{}, into interface{}) error {
|
||||
schema := context.Schemas.Schema(version, typeName)
|
||||
if schema == nil {
|
||||
return fmt.Errorf("failed to find schema " + typeName)
|
||||
}
|
||||
|
||||
item, err := schema.Store.Create(context, schema, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := builder.NewBuilder(context)
|
||||
b.Version = version
|
||||
|
||||
item, err = b.Construct(schema, item, builder.List)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if into == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return convert.ToObj(item, into)
|
||||
}
|
||||
|
||||
func ByID(context *types.APIContext, version *types.APIVersion, typeName string, id string, into interface{}) error {
|
||||
schema := context.Schemas.Schema(version, typeName)
|
||||
if schema == nil {
|
||||
return fmt.Errorf("failed to find schema " + typeName)
|
||||
}
|
||||
|
||||
item, err := schema.Store.ByID(context, schema, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := builder.NewBuilder(context)
|
||||
b.Version = version
|
||||
|
||||
item, err = b.Construct(schema, item, builder.List)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if into == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return convert.ToObj(item, into)
|
||||
}
|
||||
|
||||
func List(context *types.APIContext, version *types.APIVersion, typeName string, opts *types.QueryOptions, into interface{}) error {
|
||||
schema := context.Schemas.Schema(version, typeName)
|
||||
if schema == nil {
|
||||
return fmt.Errorf("failed to find schema " + typeName)
|
||||
}
|
||||
|
||||
data, err := schema.Store.List(context, schema, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := builder.NewBuilder(context)
|
||||
b.Version = version
|
||||
|
||||
var newData []map[string]interface{}
|
||||
for _, item := range data {
|
||||
item, err = b.Construct(schema, item, builder.List)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newData = append(newData, item)
|
||||
}
|
||||
|
||||
return convert.ToObj(newData, into)
|
||||
}
|
81
vendor/github.com/rancher/norman/api/builtin/api_root.go
generated
vendored
81
vendor/github.com/rancher/norman/api/builtin/api_root.go
generated
vendored
@@ -1,81 +0,0 @@
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/store/empty"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
func APIRootFormatter(apiContext *types.APIContext, resource *types.RawResource) {
|
||||
path, _ := resource.Values["path"].(string)
|
||||
if path == "" {
|
||||
return
|
||||
}
|
||||
|
||||
delete(resource.Values, "path")
|
||||
|
||||
resource.Links["root"] = apiContext.URLBuilder.RelativeToRoot(path)
|
||||
|
||||
data, _ := resource.Values["apiVersion"].(map[string]interface{})
|
||||
apiVersion := apiVersionFromMap(apiContext.Schemas, data)
|
||||
|
||||
resource.Links["self"] = apiContext.URLBuilder.Version(apiVersion)
|
||||
|
||||
for _, schema := range apiContext.Schemas.SchemasForVersion(apiVersion) {
|
||||
addCollectionLink(apiContext, schema, resource.Links)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func addCollectionLink(apiContext *types.APIContext, schema *types.Schema, links map[string]string) {
|
||||
collectionLink := getSchemaCollectionLink(apiContext, schema, nil)
|
||||
if collectionLink != "" {
|
||||
links[schema.PluralName] = collectionLink
|
||||
}
|
||||
}
|
||||
|
||||
type APIRootStore struct {
|
||||
empty.Store
|
||||
roots []string
|
||||
}
|
||||
|
||||
func NewAPIRootStore(roots []string) types.Store {
|
||||
return &APIRootStore{roots: roots}
|
||||
}
|
||||
|
||||
func (a *APIRootStore) ByID(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
|
||||
for _, version := range apiContext.Schemas.Versions() {
|
||||
if version.Path == id {
|
||||
return apiVersionToAPIRootMap(version), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (a *APIRootStore) List(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) ([]map[string]interface{}, error) {
|
||||
var roots []map[string]interface{}
|
||||
|
||||
for _, version := range apiContext.Schemas.Versions() {
|
||||
roots = append(roots, apiVersionToAPIRootMap(version))
|
||||
}
|
||||
|
||||
for _, root := range a.roots {
|
||||
roots = append(roots, map[string]interface{}{
|
||||
"path": root,
|
||||
})
|
||||
}
|
||||
|
||||
return roots, nil
|
||||
}
|
||||
|
||||
func apiVersionToAPIRootMap(version types.APIVersion) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"type": "/meta/schemas/apiRoot",
|
||||
"apiVersion": map[string]interface{}{
|
||||
"version": version.Version,
|
||||
"group": version.Group,
|
||||
"path": version.Path,
|
||||
},
|
||||
"path": version.Path,
|
||||
}
|
||||
}
|
136
vendor/github.com/rancher/norman/api/builtin/schema.go
generated
vendored
136
vendor/github.com/rancher/norman/api/builtin/schema.go
generated
vendored
@@ -1,136 +0,0 @@
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/norman/store/schema"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
var (
|
||||
Version = types.APIVersion{
|
||||
Group: "meta.cattle.io",
|
||||
Version: "v1",
|
||||
Path: "/meta",
|
||||
}
|
||||
|
||||
Schema = types.Schema{
|
||||
ID: "schema",
|
||||
PluralName: "schemas",
|
||||
Version: Version,
|
||||
CollectionMethods: []string{"GET"},
|
||||
ResourceMethods: []string{"GET"},
|
||||
ResourceFields: map[string]types.Field{
|
||||
"collectionActions": {Type: "map[json]"},
|
||||
"collectionFields": {Type: "map[json]"},
|
||||
"collectionFilters": {Type: "map[json]"},
|
||||
"collectionMethods": {Type: "array[string]"},
|
||||
"pluralName": {Type: "string"},
|
||||
"resourceActions": {Type: "map[json]"},
|
||||
"resourceFields": {Type: "map[json]"},
|
||||
"resourceMethods": {Type: "array[string]"},
|
||||
"version": {Type: "map[json]"},
|
||||
},
|
||||
Formatter: SchemaFormatter,
|
||||
Store: schema.NewSchemaStore(),
|
||||
}
|
||||
|
||||
Error = types.Schema{
|
||||
ID: "error",
|
||||
Version: Version,
|
||||
ResourceMethods: []string{},
|
||||
CollectionMethods: []string{},
|
||||
ResourceFields: map[string]types.Field{
|
||||
"code": {Type: "string"},
|
||||
"detail": {Type: "string", Nullable: true},
|
||||
"message": {Type: "string", Nullable: true},
|
||||
"fieldName": {Type: "string", Nullable: true},
|
||||
"status": {Type: "int"},
|
||||
},
|
||||
}
|
||||
|
||||
Collection = types.Schema{
|
||||
ID: "collection",
|
||||
Version: Version,
|
||||
ResourceMethods: []string{},
|
||||
CollectionMethods: []string{},
|
||||
ResourceFields: map[string]types.Field{
|
||||
"data": {Type: "array[json]"},
|
||||
"pagination": {Type: "map[json]"},
|
||||
"sort": {Type: "map[json]"},
|
||||
"filters": {Type: "map[json]"},
|
||||
},
|
||||
}
|
||||
|
||||
APIRoot = types.Schema{
|
||||
ID: "apiRoot",
|
||||
Version: Version,
|
||||
CollectionMethods: []string{"GET"},
|
||||
ResourceMethods: []string{"GET"},
|
||||
ResourceFields: map[string]types.Field{
|
||||
"apiVersion": {Type: "map[json]"},
|
||||
"path": {Type: "string"},
|
||||
},
|
||||
Formatter: APIRootFormatter,
|
||||
Store: NewAPIRootStore(nil),
|
||||
}
|
||||
|
||||
Schemas = types.NewSchemas().
|
||||
AddSchema(Schema).
|
||||
AddSchema(Error).
|
||||
AddSchema(Collection).
|
||||
AddSchema(APIRoot)
|
||||
)
|
||||
|
||||
func apiVersionFromMap(schemas *types.Schemas, apiVersion map[string]interface{}) types.APIVersion {
|
||||
path, _ := apiVersion["path"].(string)
|
||||
version, _ := apiVersion["version"].(string)
|
||||
group, _ := apiVersion["group"].(string)
|
||||
|
||||
apiVersionObj := types.APIVersion{
|
||||
Path: path,
|
||||
Version: version,
|
||||
Group: group,
|
||||
}
|
||||
|
||||
for _, testVersion := range schemas.Versions() {
|
||||
if testVersion.Equals(&apiVersionObj) {
|
||||
return testVersion
|
||||
}
|
||||
}
|
||||
|
||||
return apiVersionObj
|
||||
}
|
||||
|
||||
func SchemaFormatter(apiContext *types.APIContext, resource *types.RawResource) {
|
||||
data, _ := resource.Values["version"].(map[string]interface{})
|
||||
apiVersion := apiVersionFromMap(apiContext.Schemas, data)
|
||||
|
||||
schema := apiContext.Schemas.Schema(&apiVersion, resource.ID)
|
||||
if schema == nil {
|
||||
return
|
||||
}
|
||||
|
||||
collectionLink := getSchemaCollectionLink(apiContext, schema, &apiVersion)
|
||||
if collectionLink != "" {
|
||||
resource.Links["collection"] = collectionLink
|
||||
}
|
||||
|
||||
resource.Links["self"] = apiContext.URLBuilder.SchemaLink(schema)
|
||||
}
|
||||
|
||||
func getSchemaCollectionLink(apiContext *types.APIContext, schema *types.Schema, apiVersion *types.APIVersion) string {
|
||||
if schema != nil && contains(schema.CollectionMethods, http.MethodGet) {
|
||||
return apiContext.URLBuilder.Collection(schema, apiVersion)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func contains(list []string, needle string) bool {
|
||||
for _, v := range list {
|
||||
if v == needle {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
30
vendor/github.com/rancher/norman/api/handler/create.go
generated
vendored
30
vendor/github.com/rancher/norman/api/handler/create.go
generated
vendored
@@ -1,30 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
func CreateHandler(apiContext *types.APIContext, next types.RequestHandler) error {
|
||||
var err error
|
||||
|
||||
data, err := ParseAndValidateBody(apiContext, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
store := apiContext.Schema.Store
|
||||
if store == nil {
|
||||
return httperror.NewAPIError(httperror.NotFound, "no store found")
|
||||
}
|
||||
|
||||
data, err = store.Create(apiContext, apiContext.Schema, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
apiContext.WriteResponse(http.StatusCreated, data)
|
||||
return nil
|
||||
}
|
27
vendor/github.com/rancher/norman/api/handler/delete.go
generated
vendored
27
vendor/github.com/rancher/norman/api/handler/delete.go
generated
vendored
@@ -1,27 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
func DeleteHandler(request *types.APIContext, next types.RequestHandler) error {
|
||||
store := request.Schema.Store
|
||||
if store == nil {
|
||||
return httperror.NewAPIError(httperror.NotFound, "no store found")
|
||||
}
|
||||
|
||||
obj, err := store.Delete(request, request.Schema, request.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if obj == nil {
|
||||
request.WriteResponse(http.StatusNoContent, nil)
|
||||
} else {
|
||||
request.WriteResponse(http.StatusOK, obj)
|
||||
}
|
||||
return nil
|
||||
}
|
43
vendor/github.com/rancher/norman/api/handler/list.go
generated
vendored
43
vendor/github.com/rancher/norman/api/handler/list.go
generated
vendored
@@ -1,43 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/parse"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
func ListHandler(request *types.APIContext, next types.RequestHandler) error {
|
||||
var (
|
||||
err error
|
||||
data interface{}
|
||||
)
|
||||
|
||||
store := request.Schema.Store
|
||||
if store == nil {
|
||||
return httperror.NewAPIError(httperror.NotFound, "no store found")
|
||||
}
|
||||
|
||||
if request.ID == "" {
|
||||
opts := parse.QueryOptions(request, request.Schema)
|
||||
// Save the pagination on the context so it's not reset later
|
||||
request.Pagination = opts.Pagination
|
||||
data, err = store.List(request, request.Schema, &opts)
|
||||
} else if request.Link == "" {
|
||||
data, err = store.ByID(request, request.Schema, request.ID)
|
||||
} else {
|
||||
_, err = store.ByID(request, request.Schema, request.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return request.Schema.LinkHandler(request, nil)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
request.WriteResponse(http.StatusOK, data)
|
||||
return nil
|
||||
}
|
121
vendor/github.com/rancher/norman/api/handler/query.go
generated
vendored
121
vendor/github.com/rancher/norman/api/handler/query.go
generated
vendored
@@ -1,121 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
)
|
||||
|
||||
func QueryFilter(opts *types.QueryOptions, schema *types.Schema, data []map[string]interface{}) []map[string]interface{} {
|
||||
return ApplyQueryOptions(opts, schema, data)
|
||||
}
|
||||
|
||||
func ApplyQueryOptions(options *types.QueryOptions, schema *types.Schema, data []map[string]interface{}) []map[string]interface{} {
|
||||
data = ApplyQueryConditions(options.Conditions, schema, data)
|
||||
data = ApplySort(options.Sort, data)
|
||||
return ApplyPagination(options.Pagination, data)
|
||||
}
|
||||
|
||||
func ApplySort(sortOpts types.Sort, data []map[string]interface{}) []map[string]interface{} {
|
||||
name := sortOpts.Name
|
||||
if name == "" {
|
||||
name = "id"
|
||||
}
|
||||
|
||||
sort.Slice(data, func(i, j int) bool {
|
||||
left, right := i, j
|
||||
if sortOpts.Order == types.DESC {
|
||||
left, right = j, i
|
||||
}
|
||||
|
||||
return convert.ToString(data[left][name]) < convert.ToString(data[right][name])
|
||||
})
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func ApplyQueryConditions(conditions []*types.QueryCondition, schema *types.Schema, data []map[string]interface{}) []map[string]interface{} {
|
||||
var result []map[string]interface{}
|
||||
|
||||
outer:
|
||||
for _, item := range data {
|
||||
for _, condition := range conditions {
|
||||
if !condition.Valid(schema, item) {
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, item)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func ApplyPagination(pagination *types.Pagination, data []map[string]interface{}) []map[string]interface{} {
|
||||
if pagination == nil || pagination.Limit == nil {
|
||||
return data
|
||||
}
|
||||
|
||||
limit := *pagination.Limit
|
||||
if limit < 0 {
|
||||
limit = 0
|
||||
}
|
||||
|
||||
total := int64(len(data))
|
||||
|
||||
// Reset fields
|
||||
pagination.Next = ""
|
||||
pagination.Previous = ""
|
||||
pagination.Partial = false
|
||||
pagination.Total = &total
|
||||
pagination.First = ""
|
||||
|
||||
if len(data) == 0 {
|
||||
return data
|
||||
}
|
||||
|
||||
// startIndex is guaranteed to be a valid index
|
||||
startIndex := int64(0)
|
||||
if pagination.Marker != "" {
|
||||
for i, item := range data {
|
||||
id, _ := item["id"].(string)
|
||||
if id == pagination.Marker {
|
||||
startIndex = int64(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
previousIndex := startIndex - limit
|
||||
if previousIndex <= 0 {
|
||||
previousIndex = 0
|
||||
}
|
||||
nextIndex := startIndex + limit
|
||||
if nextIndex > int64(len(data)) {
|
||||
nextIndex = int64(len(data))
|
||||
}
|
||||
|
||||
if previousIndex < startIndex {
|
||||
pagination.Previous, _ = data[previousIndex]["id"].(string)
|
||||
}
|
||||
|
||||
if nextIndex > startIndex && nextIndex < int64(len(data)) {
|
||||
pagination.Next, _ = data[nextIndex]["id"].(string)
|
||||
}
|
||||
|
||||
if startIndex > 0 || nextIndex < int64(len(data)) {
|
||||
pagination.Partial = true
|
||||
}
|
||||
|
||||
if pagination.Partial {
|
||||
pagination.First, _ = data[0]["id"].(string)
|
||||
|
||||
lastIndex := int64(len(data)) - limit
|
||||
if lastIndex > 0 && lastIndex < int64(len(data)) {
|
||||
pagination.Last, _ = data[lastIndex]["id"].(string)
|
||||
}
|
||||
}
|
||||
|
||||
return data[startIndex:nextIndex]
|
||||
}
|
28
vendor/github.com/rancher/norman/api/handler/update.go
generated
vendored
28
vendor/github.com/rancher/norman/api/handler/update.go
generated
vendored
@@ -1,28 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
func UpdateHandler(apiContext *types.APIContext, next types.RequestHandler) error {
|
||||
data, err := ParseAndValidateBody(apiContext, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
store := apiContext.Schema.Store
|
||||
if store == nil {
|
||||
return httperror.NewAPIError(httperror.NotFound, "no store found")
|
||||
}
|
||||
|
||||
data, err = store.Update(apiContext, apiContext.Schema, data, apiContext.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
apiContext.WriteResponse(http.StatusOK, data)
|
||||
return nil
|
||||
}
|
59
vendor/github.com/rancher/norman/api/handler/validate.go
generated
vendored
59
vendor/github.com/rancher/norman/api/handler/validate.go
generated
vendored
@@ -1,59 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/parse"
|
||||
"github.com/rancher/norman/parse/builder"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
func ParseAndValidateBody(apiContext *types.APIContext, create bool) (map[string]interface{}, error) {
|
||||
data, err := parse.Body(apiContext.Request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if create {
|
||||
for key, value := range apiContext.SubContextAttributeProvider.Create(apiContext, apiContext.Schema) {
|
||||
if data == nil {
|
||||
data = map[string]interface{}{}
|
||||
}
|
||||
data[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
b := builder.NewBuilder(apiContext)
|
||||
|
||||
op := builder.Create
|
||||
if !create {
|
||||
op = builder.Update
|
||||
}
|
||||
if apiContext.Schema.InputFormatter != nil {
|
||||
err = apiContext.Schema.InputFormatter(apiContext, apiContext.Schema, data, create)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
data, err = b.Construct(apiContext.Schema, data, op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func ParseAndValidateActionBody(apiContext *types.APIContext, actionInputSchema *types.Schema) (map[string]interface{}, error) {
|
||||
data, err := parse.Body(apiContext.Request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b := builder.NewBuilder(apiContext)
|
||||
|
||||
op := builder.Create
|
||||
data, err = b.Construct(actionInputSchema, data, op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
263
vendor/github.com/rancher/norman/api/server.go
generated
vendored
263
vendor/github.com/rancher/norman/api/server.go
generated
vendored
@@ -1,263 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/rancher/norman/api/access"
|
||||
"github.com/rancher/norman/api/builtin"
|
||||
"github.com/rancher/norman/api/handler"
|
||||
"github.com/rancher/norman/api/writer"
|
||||
"github.com/rancher/norman/authorization"
|
||||
"github.com/rancher/norman/httperror"
|
||||
ehandler "github.com/rancher/norman/httperror/handler"
|
||||
"github.com/rancher/norman/parse"
|
||||
"github.com/rancher/norman/store/wrapper"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
type StoreWrapper func(types.Store) types.Store
|
||||
|
||||
type Parser func(rw http.ResponseWriter, req *http.Request) (*types.APIContext, error)
|
||||
|
||||
type Server struct {
|
||||
initBuiltin sync.Once
|
||||
IgnoreBuiltin bool
|
||||
Parser Parser
|
||||
Resolver parse.ResolverFunc
|
||||
SubContextAttributeProvider types.SubContextAttributeProvider
|
||||
ResponseWriters map[string]ResponseWriter
|
||||
Schemas *types.Schemas
|
||||
QueryFilter types.QueryFilter
|
||||
StoreWrapper StoreWrapper
|
||||
URLParser parse.URLParser
|
||||
Defaults Defaults
|
||||
AccessControl types.AccessControl
|
||||
}
|
||||
|
||||
type Defaults struct {
|
||||
ActionHandler types.ActionHandler
|
||||
ListHandler types.RequestHandler
|
||||
LinkHandler types.RequestHandler
|
||||
CreateHandler types.RequestHandler
|
||||
DeleteHandler types.RequestHandler
|
||||
UpdateHandler types.RequestHandler
|
||||
Store types.Store
|
||||
ErrorHandler types.ErrorHandler
|
||||
}
|
||||
|
||||
func NewAPIServer() *Server {
|
||||
s := &Server{
|
||||
Schemas: types.NewSchemas(),
|
||||
ResponseWriters: map[string]ResponseWriter{
|
||||
"json": &writer.EncodingResponseWriter{
|
||||
ContentType: "application/json",
|
||||
Encoder: types.JSONEncoder,
|
||||
},
|
||||
"html": &writer.HTMLResponseWriter{
|
||||
EncodingResponseWriter: writer.EncodingResponseWriter{
|
||||
Encoder: types.JSONEncoder,
|
||||
ContentType: "application/json",
|
||||
},
|
||||
},
|
||||
"yaml": &writer.EncodingResponseWriter{
|
||||
ContentType: "application/yaml",
|
||||
Encoder: types.YAMLEncoder,
|
||||
},
|
||||
},
|
||||
SubContextAttributeProvider: &parse.DefaultSubContextAttributeProvider{},
|
||||
Resolver: parse.DefaultResolver,
|
||||
AccessControl: &authorization.AllAccess{},
|
||||
Defaults: Defaults{
|
||||
CreateHandler: handler.CreateHandler,
|
||||
DeleteHandler: handler.DeleteHandler,
|
||||
UpdateHandler: handler.UpdateHandler,
|
||||
ListHandler: handler.ListHandler,
|
||||
LinkHandler: func(*types.APIContext, types.RequestHandler) error {
|
||||
return httperror.NewAPIError(httperror.NotFound, "Link not found")
|
||||
},
|
||||
ErrorHandler: ehandler.ErrorHandler,
|
||||
},
|
||||
StoreWrapper: wrapper.Wrap,
|
||||
URLParser: parse.DefaultURLParser,
|
||||
QueryFilter: handler.QueryFilter,
|
||||
}
|
||||
|
||||
s.Schemas.AddHook = s.setupDefaults
|
||||
s.Parser = s.parser
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Server) parser(rw http.ResponseWriter, req *http.Request) (*types.APIContext, error) {
|
||||
ctx, err := parse.Parse(rw, req, s.Schemas, s.URLParser, s.Resolver)
|
||||
ctx.ResponseWriter = s.ResponseWriters[ctx.ResponseFormat]
|
||||
if ctx.ResponseWriter == nil {
|
||||
ctx.ResponseWriter = s.ResponseWriters["json"]
|
||||
}
|
||||
|
||||
if ctx.QueryFilter == nil {
|
||||
ctx.QueryFilter = s.QueryFilter
|
||||
}
|
||||
|
||||
if ctx.SubContextAttributeProvider == nil {
|
||||
ctx.SubContextAttributeProvider = s.SubContextAttributeProvider
|
||||
}
|
||||
|
||||
ctx.AccessControl = s.AccessControl
|
||||
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
func (s *Server) AddSchemas(schemas *types.Schemas) error {
|
||||
if schemas.Err() != nil {
|
||||
return schemas.Err()
|
||||
}
|
||||
|
||||
s.initBuiltin.Do(func() {
|
||||
if s.IgnoreBuiltin {
|
||||
return
|
||||
}
|
||||
for _, schema := range builtin.Schemas.Schemas() {
|
||||
s.Schemas.AddSchema(*schema)
|
||||
}
|
||||
})
|
||||
|
||||
for _, schema := range schemas.Schemas() {
|
||||
s.Schemas.AddSchema(*schema)
|
||||
}
|
||||
|
||||
return s.Schemas.Err()
|
||||
}
|
||||
|
||||
func (s *Server) setupDefaults(schema *types.Schema) {
|
||||
if schema.ActionHandler == nil {
|
||||
schema.ActionHandler = s.Defaults.ActionHandler
|
||||
}
|
||||
|
||||
if schema.Store == nil {
|
||||
schema.Store = s.Defaults.Store
|
||||
}
|
||||
|
||||
if schema.ListHandler == nil {
|
||||
schema.ListHandler = s.Defaults.ListHandler
|
||||
}
|
||||
|
||||
if schema.LinkHandler == nil {
|
||||
schema.LinkHandler = s.Defaults.LinkHandler
|
||||
}
|
||||
|
||||
if schema.CreateHandler == nil {
|
||||
schema.CreateHandler = s.Defaults.CreateHandler
|
||||
}
|
||||
|
||||
if schema.UpdateHandler == nil {
|
||||
schema.UpdateHandler = s.Defaults.UpdateHandler
|
||||
}
|
||||
|
||||
if schema.DeleteHandler == nil {
|
||||
schema.DeleteHandler = s.Defaults.DeleteHandler
|
||||
}
|
||||
|
||||
if schema.ErrorHandler == nil {
|
||||
schema.ErrorHandler = s.Defaults.ErrorHandler
|
||||
}
|
||||
|
||||
if schema.Store != nil && s.StoreWrapper != nil {
|
||||
schema.Store = s.StoreWrapper(schema.Store)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
if apiResponse, err := s.handle(rw, req); err != nil {
|
||||
s.handleError(apiResponse, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) handle(rw http.ResponseWriter, req *http.Request) (*types.APIContext, error) {
|
||||
apiRequest, err := s.Parser(rw, req)
|
||||
if err != nil {
|
||||
return apiRequest, err
|
||||
}
|
||||
|
||||
if err := CheckCSRF(apiRequest); err != nil {
|
||||
return apiRequest, err
|
||||
}
|
||||
|
||||
action, err := ValidateAction(apiRequest)
|
||||
if err != nil {
|
||||
return apiRequest, err
|
||||
}
|
||||
|
||||
if apiRequest.Schema == nil {
|
||||
return apiRequest, nil
|
||||
}
|
||||
|
||||
if action == nil && apiRequest.Type != "" {
|
||||
var handler types.RequestHandler
|
||||
var nextHandler types.RequestHandler
|
||||
if apiRequest.Link == "" {
|
||||
switch apiRequest.Method {
|
||||
case http.MethodGet:
|
||||
if apiRequest.ID == "" {
|
||||
if err := apiRequest.AccessControl.CanList(apiRequest, apiRequest.Schema); err != nil {
|
||||
return apiRequest, err
|
||||
}
|
||||
} else {
|
||||
if err := apiRequest.AccessControl.CanGet(apiRequest, apiRequest.Schema); err != nil {
|
||||
return apiRequest, err
|
||||
}
|
||||
}
|
||||
handler = apiRequest.Schema.ListHandler
|
||||
nextHandler = s.Defaults.ListHandler
|
||||
case http.MethodPost:
|
||||
if err := apiRequest.AccessControl.CanCreate(apiRequest, apiRequest.Schema); err != nil {
|
||||
return apiRequest, err
|
||||
}
|
||||
handler = apiRequest.Schema.CreateHandler
|
||||
nextHandler = s.Defaults.CreateHandler
|
||||
case http.MethodPut:
|
||||
if err := apiRequest.AccessControl.CanUpdate(apiRequest, nil, apiRequest.Schema); err != nil {
|
||||
return apiRequest, err
|
||||
}
|
||||
handler = apiRequest.Schema.UpdateHandler
|
||||
nextHandler = s.Defaults.UpdateHandler
|
||||
case http.MethodDelete:
|
||||
if err := apiRequest.AccessControl.CanDelete(apiRequest, nil, apiRequest.Schema); err != nil {
|
||||
return apiRequest, err
|
||||
}
|
||||
handler = apiRequest.Schema.DeleteHandler
|
||||
nextHandler = s.Defaults.DeleteHandler
|
||||
}
|
||||
} else {
|
||||
handler = apiRequest.Schema.ListHandler
|
||||
nextHandler = s.Defaults.ListHandler
|
||||
}
|
||||
|
||||
if handler == nil {
|
||||
return apiRequest, httperror.NewAPIError(httperror.NotFound, "")
|
||||
}
|
||||
|
||||
return apiRequest, handler(apiRequest, nextHandler)
|
||||
} else if action != nil {
|
||||
return apiRequest, handleAction(action, apiRequest)
|
||||
}
|
||||
|
||||
return apiRequest, nil
|
||||
}
|
||||
|
||||
func handleAction(action *types.Action, context *types.APIContext) error {
|
||||
if context.ID != "" {
|
||||
if err := access.ByID(context, context.Version, context.Type, context.ID, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return context.Schema.ActionHandler(context.Action, action, context)
|
||||
}
|
||||
|
||||
func (s *Server) handleError(apiRequest *types.APIContext, err error) {
|
||||
if apiRequest.Schema == nil {
|
||||
s.Defaults.ErrorHandler(apiRequest, err)
|
||||
} else if apiRequest.Schema.ErrorHandler != nil {
|
||||
apiRequest.Schema.ErrorHandler(apiRequest, err)
|
||||
}
|
||||
}
|
7
vendor/github.com/rancher/norman/api/types.go
generated
vendored
7
vendor/github.com/rancher/norman/api/types.go
generated
vendored
@@ -1,7 +0,0 @@
|
||||
package api
|
||||
|
||||
import "github.com/rancher/norman/types"
|
||||
|
||||
type ResponseWriter interface {
|
||||
Write(apiContext *types.APIContext, code int, obj interface{})
|
||||
}
|
83
vendor/github.com/rancher/norman/api/validate.go
generated
vendored
83
vendor/github.com/rancher/norman/api/validate.go
generated
vendored
@@ -1,83 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/parse"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
const (
|
||||
csrfCookie = "CSRF"
|
||||
csrfHeader = "X-API-CSRF"
|
||||
)
|
||||
|
||||
func ValidateAction(request *types.APIContext) (*types.Action, error) {
|
||||
if request.Action == "" || request.Link != "" || request.Method != http.MethodPost {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
actions := request.Schema.CollectionActions
|
||||
if request.ID != "" {
|
||||
actions = request.Schema.ResourceActions
|
||||
}
|
||||
|
||||
action, ok := actions[request.Action]
|
||||
if !ok {
|
||||
return nil, httperror.NewAPIError(httperror.InvalidAction, fmt.Sprintf("Invalid action: %s", request.Action))
|
||||
}
|
||||
|
||||
if request.ID != "" && request.ReferenceValidator != nil {
|
||||
resource := request.ReferenceValidator.Lookup(request.Type, request.ID)
|
||||
if resource == nil {
|
||||
return nil, httperror.NewAPIError(httperror.NotFound, fmt.Sprintf("Failed to find type: %s id: %s", request.Type, request.ID))
|
||||
}
|
||||
|
||||
if _, ok := resource.Actions[request.Action]; !ok {
|
||||
return nil, httperror.NewAPIError(httperror.InvalidAction, fmt.Sprintf("Invalid action: %s", request.Action))
|
||||
}
|
||||
}
|
||||
|
||||
return &action, nil
|
||||
}
|
||||
|
||||
func CheckCSRF(apiContext *types.APIContext) error {
|
||||
if !parse.IsBrowser(apiContext.Request, false) {
|
||||
return nil
|
||||
}
|
||||
|
||||
cookie, err := apiContext.Request.Cookie(csrfCookie)
|
||||
if err == http.ErrNoCookie {
|
||||
bytes := make([]byte, 5)
|
||||
_, err := rand.Read(bytes)
|
||||
if err != nil {
|
||||
return httperror.WrapAPIError(err, httperror.ServerError, "Failed in CSRF processing")
|
||||
}
|
||||
|
||||
cookie = &http.Cookie{
|
||||
Name: csrfCookie,
|
||||
Value: hex.EncodeToString(bytes),
|
||||
}
|
||||
} else if err != nil {
|
||||
return httperror.NewAPIError(httperror.InvalidCSRFToken, "Failed to parse cookies")
|
||||
} else if apiContext.Method != http.MethodGet {
|
||||
/*
|
||||
* Very important to use apiContext.Method and not apiContext.Request.Method. The client can override the HTTP method with _method
|
||||
*/
|
||||
if cookie.Value == apiContext.Request.Header.Get(csrfHeader) {
|
||||
// Good
|
||||
} else if cookie.Value == apiContext.Request.URL.Query().Get(csrfCookie) {
|
||||
// Good
|
||||
} else {
|
||||
return httperror.NewAPIError(httperror.InvalidCSRFToken, "Invalid CSRF token")
|
||||
}
|
||||
}
|
||||
|
||||
cookie.Path = "/"
|
||||
http.SetCookie(apiContext.Response, cookie)
|
||||
return nil
|
||||
}
|
30
vendor/github.com/rancher/norman/api/writer/headers.go
generated
vendored
30
vendor/github.com/rancher/norman/api/writer/headers.go
generated
vendored
@@ -1,30 +0,0 @@
|
||||
package writer
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/api/builtin"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
func AddCommonResponseHeader(apiContext *types.APIContext) error {
|
||||
addExpires(apiContext)
|
||||
return addSchemasHeader(apiContext)
|
||||
}
|
||||
|
||||
func addSchemasHeader(apiContext *types.APIContext) error {
|
||||
schema := apiContext.Schemas.Schema(&builtin.Version, "schema")
|
||||
if schema == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
version := apiContext.SchemasVersion
|
||||
if version == nil {
|
||||
version = apiContext.Version
|
||||
}
|
||||
|
||||
apiContext.Response.Header().Set("X-Api-Schemas", apiContext.URLBuilder.Collection(schema, version))
|
||||
return nil
|
||||
}
|
||||
|
||||
func addExpires(apiContext *types.APIContext) {
|
||||
apiContext.Response.Header().Set("Expires", "Wed 24 Feb 1982 18:42:00 GMT")
|
||||
}
|
48
vendor/github.com/rancher/norman/api/writer/html.go
generated
vendored
48
vendor/github.com/rancher/norman/api/writer/html.go
generated
vendored
@@ -1,48 +0,0 @@
|
||||
package writer
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/norman/api/builtin"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
var (
|
||||
start = `
|
||||
<!DOCTYPE html>
|
||||
<!-- If you are reading this, there is a good chance you would prefer sending an
|
||||
"Accept: application/json" header and receiving actual JSON responses. -->
|
||||
<link rel="stylesheet" type="text/css" href="https://releases.rancher.com/api-ui/1.1.5/ui.min.css" />
|
||||
<script src="https://releases.rancher.com/api-ui/1.1.5/ui.min.js"></script>
|
||||
<script>
|
||||
var user = "admin";
|
||||
var curlUser='${CATTLE_ACCESS_KEY}:${CATTLE_SECRET_KEY}';
|
||||
var schemas="%SCHEMAS%";
|
||||
var data =
|
||||
`
|
||||
end = []byte(`</script>
|
||||
`)
|
||||
)
|
||||
|
||||
type HTMLResponseWriter struct {
|
||||
EncodingResponseWriter
|
||||
}
|
||||
|
||||
func (h *HTMLResponseWriter) start(apiContext *types.APIContext, code int, obj interface{}) {
|
||||
AddCommonResponseHeader(apiContext)
|
||||
apiContext.Response.Header().Set("content-type", "text/html")
|
||||
apiContext.Response.WriteHeader(code)
|
||||
}
|
||||
|
||||
func (h *HTMLResponseWriter) Write(apiContext *types.APIContext, code int, obj interface{}) {
|
||||
h.start(apiContext, code, obj)
|
||||
schemaSchema := apiContext.Schemas.Schema(&builtin.Version, "schema")
|
||||
if schemaSchema != nil {
|
||||
headerString := strings.Replace(start, "%SCHEMAS%", apiContext.URLBuilder.Collection(schemaSchema, apiContext.Version), 1)
|
||||
apiContext.Response.Write([]byte(headerString))
|
||||
}
|
||||
h.Body(apiContext, apiContext.Response, obj)
|
||||
if schemaSchema != nil {
|
||||
apiContext.Response.Write(end)
|
||||
}
|
||||
}
|
234
vendor/github.com/rancher/norman/api/writer/json.go
generated
vendored
234
vendor/github.com/rancher/norman/api/writer/json.go
generated
vendored
@@ -1,234 +0,0 @@
|
||||
package writer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/norman/parse"
|
||||
"github.com/rancher/norman/parse/builder"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/definition"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type EncodingResponseWriter struct {
|
||||
ContentType string
|
||||
Encoder func(io.Writer, interface{}) error
|
||||
}
|
||||
|
||||
func (j *EncodingResponseWriter) start(apiContext *types.APIContext, code int, obj interface{}) {
|
||||
AddCommonResponseHeader(apiContext)
|
||||
apiContext.Response.Header().Set("content-type", j.ContentType)
|
||||
apiContext.Response.WriteHeader(code)
|
||||
}
|
||||
|
||||
func (j *EncodingResponseWriter) Write(apiContext *types.APIContext, code int, obj interface{}) {
|
||||
j.start(apiContext, code, obj)
|
||||
j.Body(apiContext, apiContext.Response, obj)
|
||||
}
|
||||
|
||||
func (j *EncodingResponseWriter) Body(apiContext *types.APIContext, writer io.Writer, obj interface{}) error {
|
||||
return j.VersionBody(apiContext, apiContext.Version, writer, obj)
|
||||
|
||||
}
|
||||
|
||||
func (j *EncodingResponseWriter) VersionBody(apiContext *types.APIContext, version *types.APIVersion, writer io.Writer, obj interface{}) error {
|
||||
var output interface{}
|
||||
|
||||
builder := builder.NewBuilder(apiContext)
|
||||
builder.Version = version
|
||||
|
||||
switch v := obj.(type) {
|
||||
case []interface{}:
|
||||
output = j.writeInterfaceSlice(builder, apiContext, v)
|
||||
case []map[string]interface{}:
|
||||
output = j.writeMapSlice(builder, apiContext, v)
|
||||
case map[string]interface{}:
|
||||
output = j.convert(builder, apiContext, v)
|
||||
case types.RawResource:
|
||||
output = v
|
||||
}
|
||||
|
||||
if output != nil {
|
||||
return j.Encoder(writer, output)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (j *EncodingResponseWriter) writeMapSlice(builder *builder.Builder, apiContext *types.APIContext, input []map[string]interface{}) *types.GenericCollection {
|
||||
collection := newCollection(apiContext)
|
||||
for _, value := range input {
|
||||
converted := j.convert(builder, apiContext, value)
|
||||
if converted != nil {
|
||||
collection.Data = append(collection.Data, converted)
|
||||
}
|
||||
}
|
||||
|
||||
if apiContext.Schema.CollectionFormatter != nil {
|
||||
apiContext.Schema.CollectionFormatter(apiContext, collection)
|
||||
}
|
||||
|
||||
return collection
|
||||
}
|
||||
|
||||
func (j *EncodingResponseWriter) writeInterfaceSlice(builder *builder.Builder, apiContext *types.APIContext, input []interface{}) *types.GenericCollection {
|
||||
collection := newCollection(apiContext)
|
||||
for _, value := range input {
|
||||
switch v := value.(type) {
|
||||
case map[string]interface{}:
|
||||
converted := j.convert(builder, apiContext, v)
|
||||
if converted != nil {
|
||||
collection.Data = append(collection.Data, converted)
|
||||
}
|
||||
default:
|
||||
collection.Data = append(collection.Data, v)
|
||||
}
|
||||
}
|
||||
|
||||
if apiContext.Schema.CollectionFormatter != nil {
|
||||
apiContext.Schema.CollectionFormatter(apiContext, collection)
|
||||
}
|
||||
|
||||
return collection
|
||||
}
|
||||
|
||||
func toString(val interface{}) string {
|
||||
if val == nil {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprint(val)
|
||||
}
|
||||
|
||||
func (j *EncodingResponseWriter) convert(b *builder.Builder, context *types.APIContext, input map[string]interface{}) *types.RawResource {
|
||||
schema := context.Schemas.Schema(context.Version, definition.GetFullType(input))
|
||||
if schema == nil {
|
||||
return nil
|
||||
}
|
||||
op := builder.List
|
||||
if context.Method == http.MethodPost {
|
||||
op = builder.ListForCreate
|
||||
}
|
||||
data, err := b.Construct(schema, input, op)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to construct object on output: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
rawResource := &types.RawResource{
|
||||
ID: toString(input["id"]),
|
||||
Type: schema.ID,
|
||||
Schema: schema,
|
||||
Links: map[string]string{},
|
||||
Actions: map[string]string{},
|
||||
Values: data,
|
||||
ActionLinks: context.Request.Header.Get("X-API-Action-Links") != "",
|
||||
}
|
||||
|
||||
j.addLinks(b, schema, context, input, rawResource)
|
||||
|
||||
if schema.Formatter != nil {
|
||||
schema.Formatter(context, rawResource)
|
||||
}
|
||||
|
||||
return rawResource
|
||||
}
|
||||
|
||||
func (j *EncodingResponseWriter) addLinks(b *builder.Builder, schema *types.Schema, context *types.APIContext, input map[string]interface{}, rawResource *types.RawResource) {
|
||||
if rawResource.ID == "" {
|
||||
return
|
||||
}
|
||||
|
||||
self := context.URLBuilder.ResourceLink(rawResource)
|
||||
rawResource.Links["self"] = self
|
||||
if context.AccessControl.CanUpdate(context, input, schema) == nil {
|
||||
rawResource.Links["update"] = self
|
||||
}
|
||||
if context.AccessControl.CanDelete(context, input, schema) == nil {
|
||||
rawResource.Links["remove"] = self
|
||||
}
|
||||
|
||||
subContextVersion := context.Schemas.SubContextVersionForSchema(schema)
|
||||
for _, backRef := range context.Schemas.References(schema) {
|
||||
if backRef.Schema.CanList(context) != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if subContextVersion == nil {
|
||||
rawResource.Links[backRef.Schema.PluralName] = context.URLBuilder.FilterLink(backRef.Schema, backRef.FieldName, rawResource.ID)
|
||||
} else {
|
||||
rawResource.Links[backRef.Schema.PluralName] = context.URLBuilder.SubContextCollection(schema, rawResource.ID, backRef.Schema)
|
||||
}
|
||||
}
|
||||
|
||||
if subContextVersion != nil {
|
||||
for _, subSchema := range context.Schemas.SchemasForVersion(*subContextVersion) {
|
||||
if subSchema.CanList(context) == nil {
|
||||
rawResource.Links[subSchema.PluralName] = context.URLBuilder.SubContextCollection(schema, rawResource.ID, subSchema)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newCollection(apiContext *types.APIContext) *types.GenericCollection {
|
||||
result := &types.GenericCollection{
|
||||
Collection: types.Collection{
|
||||
Type: "collection",
|
||||
ResourceType: apiContext.Type,
|
||||
CreateTypes: map[string]string{},
|
||||
Links: map[string]string{
|
||||
"self": apiContext.URLBuilder.Current(),
|
||||
},
|
||||
Actions: map[string]string{},
|
||||
},
|
||||
Data: []interface{}{},
|
||||
}
|
||||
|
||||
if apiContext.Method == http.MethodGet {
|
||||
if apiContext.AccessControl.CanCreate(apiContext, apiContext.Schema) == nil {
|
||||
result.CreateTypes[apiContext.Schema.ID] = apiContext.URLBuilder.Collection(apiContext.Schema, apiContext.Version)
|
||||
}
|
||||
}
|
||||
|
||||
opts := parse.QueryOptions(apiContext, apiContext.Schema)
|
||||
result.Sort = &opts.Sort
|
||||
result.Sort.Reverse = apiContext.URLBuilder.ReverseSort(result.Sort.Order)
|
||||
result.Sort.Links = map[string]string{}
|
||||
result.Pagination = opts.Pagination
|
||||
result.Filters = map[string][]types.Condition{}
|
||||
|
||||
for _, cond := range opts.Conditions {
|
||||
filters := result.Filters[cond.Field]
|
||||
result.Filters[cond.Field] = append(filters, cond.ToCondition())
|
||||
}
|
||||
|
||||
for name := range apiContext.Schema.CollectionFilters {
|
||||
if _, ok := result.Filters[name]; !ok {
|
||||
result.Filters[name] = nil
|
||||
}
|
||||
}
|
||||
|
||||
for queryField := range apiContext.Schema.CollectionFilters {
|
||||
field, ok := apiContext.Schema.ResourceFields[queryField]
|
||||
if ok && (field.Type == "string" || field.Type == "enum") {
|
||||
result.Sort.Links[queryField] = apiContext.URLBuilder.Sort(queryField)
|
||||
}
|
||||
}
|
||||
|
||||
if result.Pagination != nil && result.Pagination.Partial {
|
||||
if result.Pagination.Next != "" {
|
||||
result.Pagination.Next = apiContext.URLBuilder.Marker(result.Pagination.Next)
|
||||
}
|
||||
if result.Pagination.Previous != "" {
|
||||
result.Pagination.Previous = apiContext.URLBuilder.Marker(result.Pagination.Previous)
|
||||
}
|
||||
if result.Pagination.First != "" {
|
||||
result.Pagination.First = apiContext.URLBuilder.Marker(result.Pagination.First)
|
||||
}
|
||||
if result.Pagination.Last != "" {
|
||||
result.Pagination.Last = apiContext.URLBuilder.Marker(result.Pagination.Last)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
62
vendor/github.com/rancher/norman/authorization/all.go
generated
vendored
62
vendor/github.com/rancher/norman/authorization/all.go
generated
vendored
@@ -1,62 +0,0 @@
|
||||
package authorization
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/slice"
|
||||
)
|
||||
|
||||
type AllAccess struct {
|
||||
}
|
||||
|
||||
func (*AllAccess) CanCreate(apiContext *types.APIContext, schema *types.Schema) error {
|
||||
if slice.ContainsString(schema.CollectionMethods, http.MethodPost) {
|
||||
return nil
|
||||
}
|
||||
return httperror.NewAPIError(httperror.PermissionDenied, "can not create "+schema.ID)
|
||||
}
|
||||
|
||||
func (*AllAccess) CanGet(apiContext *types.APIContext, schema *types.Schema) error {
|
||||
if slice.ContainsString(schema.ResourceMethods, http.MethodGet) {
|
||||
return nil
|
||||
}
|
||||
return httperror.NewAPIError(httperror.PermissionDenied, "can not get "+schema.ID)
|
||||
}
|
||||
|
||||
func (*AllAccess) CanList(apiContext *types.APIContext, schema *types.Schema) error {
|
||||
if slice.ContainsString(schema.CollectionMethods, http.MethodGet) {
|
||||
return nil
|
||||
}
|
||||
return httperror.NewAPIError(httperror.PermissionDenied, "can not list "+schema.ID)
|
||||
}
|
||||
|
||||
func (*AllAccess) CanUpdate(apiContext *types.APIContext, obj map[string]interface{}, schema *types.Schema) error {
|
||||
if slice.ContainsString(schema.ResourceMethods, http.MethodPut) {
|
||||
return nil
|
||||
}
|
||||
return httperror.NewAPIError(httperror.PermissionDenied, "can not update "+schema.ID)
|
||||
}
|
||||
|
||||
func (*AllAccess) CanDelete(apiContext *types.APIContext, obj map[string]interface{}, schema *types.Schema) error {
|
||||
if slice.ContainsString(schema.ResourceMethods, http.MethodDelete) {
|
||||
return nil
|
||||
}
|
||||
return httperror.NewAPIError(httperror.PermissionDenied, "can not delete "+schema.ID)
|
||||
}
|
||||
|
||||
func (*AllAccess) CanDo(apiGroup, resource, verb string, apiContext *types.APIContext, obj map[string]interface{}, schema *types.Schema) error {
|
||||
if slice.ContainsString(schema.ResourceMethods, verb) {
|
||||
return nil
|
||||
}
|
||||
return httperror.NewAPIError(httperror.PermissionDenied, "can not perform "+verb+" "+schema.ID)
|
||||
}
|
||||
|
||||
func (*AllAccess) Filter(apiContext *types.APIContext, schema *types.Schema, obj map[string]interface{}, context map[string]string) map[string]interface{} {
|
||||
return obj
|
||||
}
|
||||
|
||||
func (*AllAccess) FilterList(apiContext *types.APIContext, schema *types.Schema, obj []map[string]interface{}, context map[string]string) []map[string]interface{} {
|
||||
return obj
|
||||
}
|
373
vendor/github.com/rancher/norman/clientbase/common.go
generated
vendored
373
vendor/github.com/rancher/norman/clientbase/common.go
generated
vendored
@@ -1,373 +0,0 @@
|
||||
package clientbase
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
const (
|
||||
SELF = "self"
|
||||
COLLECTION = "collection"
|
||||
)
|
||||
|
||||
var (
|
||||
Debug = false
|
||||
)
|
||||
|
||||
type APIBaseClientInterface interface {
|
||||
Websocket(url string, headers map[string][]string) (*websocket.Conn, *http.Response, error)
|
||||
List(schemaType string, opts *types.ListOpts, respObject interface{}) error
|
||||
Post(url string, createObj interface{}, respObject interface{}) error
|
||||
GetLink(resource types.Resource, link string, respObject interface{}) error
|
||||
Create(schemaType string, createObj interface{}, respObject interface{}) error
|
||||
Update(schemaType string, existing *types.Resource, updates interface{}, respObject interface{}) error
|
||||
Replace(schemaType string, existing *types.Resource, updates interface{}, respObject interface{}) error
|
||||
ByID(schemaType string, id string, respObject interface{}) error
|
||||
Delete(existing *types.Resource) error
|
||||
Reload(existing *types.Resource, output interface{}) error
|
||||
Action(schemaType string, action string, existing *types.Resource, inputObject, respObject interface{}) error
|
||||
}
|
||||
|
||||
type APIBaseClient struct {
|
||||
Ops *APIOperations
|
||||
Opts *ClientOpts
|
||||
Types map[string]types.Schema
|
||||
}
|
||||
|
||||
type ClientOpts struct {
|
||||
URL string
|
||||
AccessKey string
|
||||
SecretKey string
|
||||
TokenKey string
|
||||
Timeout time.Duration
|
||||
HTTPClient *http.Client
|
||||
WSDialer *websocket.Dialer
|
||||
CACerts string
|
||||
Insecure bool
|
||||
}
|
||||
|
||||
func (c *ClientOpts) getAuthHeader() string {
|
||||
if c.TokenKey != "" {
|
||||
return "Bearer " + c.TokenKey
|
||||
}
|
||||
if c.AccessKey != "" && c.SecretKey != "" {
|
||||
s := c.AccessKey + ":" + c.SecretKey
|
||||
return "Basic " + base64.StdEncoding.EncodeToString([]byte(s))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type APIError struct {
|
||||
StatusCode int
|
||||
URL string
|
||||
Msg string
|
||||
Status string
|
||||
Body string
|
||||
}
|
||||
|
||||
func (e *APIError) Error() string {
|
||||
return e.Msg
|
||||
}
|
||||
|
||||
func IsNotFound(err error) bool {
|
||||
apiError, ok := err.(*APIError)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return apiError.StatusCode == http.StatusNotFound
|
||||
}
|
||||
|
||||
func NewAPIError(resp *http.Response, url string) *APIError {
|
||||
contents, err := ioutil.ReadAll(resp.Body)
|
||||
var body string
|
||||
if err != nil {
|
||||
body = "Unreadable body."
|
||||
} else {
|
||||
body = string(contents)
|
||||
}
|
||||
|
||||
data := map[string]interface{}{}
|
||||
if json.Unmarshal(contents, &data) == nil {
|
||||
delete(data, "id")
|
||||
delete(data, "links")
|
||||
delete(data, "actions")
|
||||
delete(data, "type")
|
||||
delete(data, "status")
|
||||
buf := &bytes.Buffer{}
|
||||
for k, v := range data {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
fmt.Fprintf(buf, "%s=%v", k, v)
|
||||
}
|
||||
body = buf.String()
|
||||
}
|
||||
formattedMsg := fmt.Sprintf("Bad response statusCode [%d]. Status [%s]. Body: [%s] from [%s]",
|
||||
resp.StatusCode, resp.Status, body, url)
|
||||
return &APIError{
|
||||
URL: url,
|
||||
Msg: formattedMsg,
|
||||
StatusCode: resp.StatusCode,
|
||||
Status: resp.Status,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
|
||||
func contains(array []string, item string) bool {
|
||||
for _, check := range array {
|
||||
if check == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func appendFilters(urlString string, filters map[string]interface{}) (string, error) {
|
||||
if len(filters) == 0 {
|
||||
return urlString, nil
|
||||
}
|
||||
|
||||
u, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
q := u.Query()
|
||||
for k, v := range filters {
|
||||
if l, ok := v.([]string); ok {
|
||||
for _, v := range l {
|
||||
q.Add(k, v)
|
||||
}
|
||||
} else {
|
||||
q.Add(k, fmt.Sprintf("%v", v))
|
||||
}
|
||||
}
|
||||
|
||||
u.RawQuery = q.Encode()
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
func NewAPIClient(opts *ClientOpts) (APIBaseClient, error) {
|
||||
var err error
|
||||
|
||||
result := APIBaseClient{
|
||||
Types: map[string]types.Schema{},
|
||||
}
|
||||
|
||||
client := opts.HTTPClient
|
||||
if client == nil {
|
||||
client = &http.Client{}
|
||||
}
|
||||
|
||||
if opts.Timeout == 0 {
|
||||
opts.Timeout = time.Minute
|
||||
}
|
||||
|
||||
client.Timeout = opts.Timeout
|
||||
|
||||
if opts.CACerts != "" {
|
||||
roots := x509.NewCertPool()
|
||||
ok := roots.AppendCertsFromPEM([]byte(opts.CACerts))
|
||||
if !ok {
|
||||
return result, err
|
||||
}
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
RootCAs: roots,
|
||||
},
|
||||
}
|
||||
client.Transport = tr
|
||||
}
|
||||
|
||||
if opts.Insecure {
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: opts.Insecure,
|
||||
},
|
||||
}
|
||||
client.Transport = tr
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", opts.URL, nil)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
req.Header.Add("Authorization", opts.getAuthHeader())
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return result, NewAPIError(resp, opts.URL)
|
||||
}
|
||||
|
||||
schemasURLs := resp.Header.Get("X-API-Schemas")
|
||||
if len(schemasURLs) == 0 {
|
||||
return result, errors.New("Failed to find schema at [" + opts.URL + "]")
|
||||
}
|
||||
|
||||
if schemasURLs != opts.URL {
|
||||
req, err = http.NewRequest("GET", schemasURLs, nil)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
req.Header.Add("Authorization", opts.getAuthHeader())
|
||||
|
||||
if Debug {
|
||||
fmt.Println("GET " + req.URL.String())
|
||||
}
|
||||
|
||||
resp, err = client.Do(req)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return result, NewAPIError(resp, schemasURLs)
|
||||
}
|
||||
}
|
||||
|
||||
var schemas types.SchemaCollection
|
||||
bytes, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
if Debug {
|
||||
fmt.Println("Response <= " + string(bytes))
|
||||
}
|
||||
|
||||
err = json.Unmarshal(bytes, &schemas)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
for _, schema := range schemas.Data {
|
||||
result.Types[schema.ID] = schema
|
||||
}
|
||||
|
||||
result.Opts = opts
|
||||
result.Ops = &APIOperations{
|
||||
Opts: opts,
|
||||
Client: client,
|
||||
Dialer: &websocket.Dialer{},
|
||||
Types: result.Types,
|
||||
}
|
||||
|
||||
if result.Opts.WSDialer != nil {
|
||||
result.Ops.Dialer = result.Opts.WSDialer
|
||||
}
|
||||
|
||||
ht, ok := client.Transport.(*http.Transport)
|
||||
if ok {
|
||||
result.Ops.Dialer.TLSClientConfig = ht.TLSClientConfig
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func NewListOpts() *types.ListOpts {
|
||||
return &types.ListOpts{
|
||||
Filters: map[string]interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
func (a *APIBaseClient) Websocket(url string, headers map[string][]string) (*websocket.Conn, *http.Response, error) {
|
||||
httpHeaders := http.Header{}
|
||||
for k, v := range httpHeaders {
|
||||
httpHeaders[k] = v
|
||||
}
|
||||
|
||||
if a.Opts != nil {
|
||||
httpHeaders.Add("Authorization", a.Opts.getAuthHeader())
|
||||
}
|
||||
|
||||
if Debug {
|
||||
fmt.Println("WS " + url)
|
||||
}
|
||||
|
||||
return a.Ops.Dialer.Dial(url, http.Header(httpHeaders))
|
||||
}
|
||||
|
||||
func (a *APIBaseClient) List(schemaType string, opts *types.ListOpts, respObject interface{}) error {
|
||||
return a.Ops.DoList(schemaType, opts, respObject)
|
||||
}
|
||||
|
||||
func (a *APIBaseClient) Post(url string, createObj interface{}, respObject interface{}) error {
|
||||
return a.Ops.DoModify("POST", url, createObj, respObject)
|
||||
}
|
||||
|
||||
func (a *APIBaseClient) GetLink(resource types.Resource, link string, respObject interface{}) error {
|
||||
url := resource.Links[link]
|
||||
if url == "" {
|
||||
return fmt.Errorf("failed to find link: %s", link)
|
||||
}
|
||||
|
||||
return a.Ops.DoGet(url, &types.ListOpts{}, respObject)
|
||||
}
|
||||
|
||||
func (a *APIBaseClient) Create(schemaType string, createObj interface{}, respObject interface{}) error {
|
||||
return a.Ops.DoCreate(schemaType, createObj, respObject)
|
||||
}
|
||||
|
||||
func (a *APIBaseClient) Update(schemaType string, existing *types.Resource, updates interface{}, respObject interface{}) error {
|
||||
return a.Ops.DoUpdate(schemaType, existing, updates, respObject)
|
||||
}
|
||||
|
||||
func (a *APIBaseClient) Replace(schemaType string, existing *types.Resource, updates interface{}, respObject interface{}) error {
|
||||
return a.Ops.DoReplace(schemaType, existing, updates, respObject)
|
||||
}
|
||||
|
||||
func (a *APIBaseClient) ByID(schemaType string, id string, respObject interface{}) error {
|
||||
return a.Ops.DoByID(schemaType, id, respObject)
|
||||
}
|
||||
|
||||
func (a *APIBaseClient) Delete(existing *types.Resource) error {
|
||||
if existing == nil {
|
||||
return nil
|
||||
}
|
||||
return a.Ops.DoResourceDelete(existing.Type, existing)
|
||||
}
|
||||
|
||||
func (a *APIBaseClient) Reload(existing *types.Resource, output interface{}) error {
|
||||
selfURL, ok := existing.Links[SELF]
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to find self URL of [%v]", existing)
|
||||
}
|
||||
|
||||
return a.Ops.DoGet(selfURL, NewListOpts(), output)
|
||||
}
|
||||
|
||||
func (a *APIBaseClient) Action(schemaType string, action string,
|
||||
existing *types.Resource, inputObject, respObject interface{}) error {
|
||||
return a.Ops.DoAction(schemaType, action, existing, inputObject, respObject)
|
||||
}
|
||||
|
||||
func init() {
|
||||
Debug = os.Getenv("RANCHER_CLIENT_DEBUG") == "true"
|
||||
if Debug {
|
||||
fmt.Println("Rancher client debug on")
|
||||
}
|
||||
}
|
372
vendor/github.com/rancher/norman/clientbase/ops.go
generated
vendored
372
vendor/github.com/rancher/norman/clientbase/ops.go
generated
vendored
@@ -1,372 +0,0 @@
|
||||
package clientbase
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
type APIOperations struct {
|
||||
Opts *ClientOpts
|
||||
Types map[string]types.Schema
|
||||
Client *http.Client
|
||||
Dialer *websocket.Dialer
|
||||
}
|
||||
|
||||
func (a *APIOperations) SetupRequest(req *http.Request) {
|
||||
req.Header.Add("Authorization", a.Opts.getAuthHeader())
|
||||
}
|
||||
|
||||
func (a *APIOperations) DoDelete(url string) error {
|
||||
req, err := http.NewRequest("DELETE", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.SetupRequest(req)
|
||||
|
||||
resp, err := a.Client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
io.Copy(ioutil.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
}()
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return NewAPIError(resp, url)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *APIOperations) DoGet(url string, opts *types.ListOpts, respObject interface{}) error {
|
||||
if opts == nil {
|
||||
opts = NewListOpts()
|
||||
}
|
||||
url, err := appendFilters(url, opts.Filters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if Debug {
|
||||
fmt.Println("GET " + url)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.SetupRequest(req)
|
||||
|
||||
resp, err := a.Client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return NewAPIError(resp, url)
|
||||
}
|
||||
|
||||
byteContent, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if Debug {
|
||||
fmt.Println("Response <= " + string(byteContent))
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(byteContent, respObject); err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("Failed to parse: %s", byteContent))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *APIOperations) DoList(schemaType string, opts *types.ListOpts, respObject interface{}) error {
|
||||
schema, ok := a.Types[schemaType]
|
||||
if !ok {
|
||||
return errors.New("Unknown schema type [" + schemaType + "]")
|
||||
}
|
||||
|
||||
if !contains(schema.CollectionMethods, "GET") {
|
||||
return errors.New("Resource type [" + schemaType + "] is not listable")
|
||||
}
|
||||
|
||||
collectionURL, ok := schema.Links["collection"]
|
||||
if !ok {
|
||||
return errors.New("Resource type [" + schemaType + "] does not have a collection URL")
|
||||
}
|
||||
|
||||
return a.DoGet(collectionURL, opts, respObject)
|
||||
}
|
||||
|
||||
func (a *APIOperations) DoNext(nextURL string, respObject interface{}) error {
|
||||
return a.DoGet(nextURL, nil, respObject)
|
||||
}
|
||||
|
||||
func (a *APIOperations) DoModify(method string, url string, createObj interface{}, respObject interface{}) error {
|
||||
bodyContent, err := json.Marshal(createObj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if Debug {
|
||||
fmt.Println(method + " " + url)
|
||||
fmt.Println("Request => " + string(bodyContent))
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, url, bytes.NewBuffer(bodyContent))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.SetupRequest(req)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := a.Client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return NewAPIError(resp, url)
|
||||
}
|
||||
|
||||
byteContent, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(byteContent) > 0 {
|
||||
if Debug {
|
||||
fmt.Println("Response <= " + string(byteContent))
|
||||
}
|
||||
return json.Unmarshal(byteContent, respObject)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *APIOperations) DoCreate(schemaType string, createObj interface{}, respObject interface{}) error {
|
||||
if createObj == nil {
|
||||
createObj = map[string]string{}
|
||||
}
|
||||
if respObject == nil {
|
||||
respObject = &map[string]interface{}{}
|
||||
}
|
||||
schema, ok := a.Types[schemaType]
|
||||
if !ok {
|
||||
return errors.New("Unknown schema type [" + schemaType + "]")
|
||||
}
|
||||
|
||||
if !contains(schema.CollectionMethods, "POST") {
|
||||
return errors.New("Resource type [" + schemaType + "] is not creatable")
|
||||
}
|
||||
|
||||
var collectionURL string
|
||||
collectionURL, ok = schema.Links[COLLECTION]
|
||||
if !ok {
|
||||
// return errors.New("Failed to find collection URL for [" + schemaType + "]")
|
||||
// This is a hack to address https://github.com/rancher/cattle/issues/254
|
||||
re := regexp.MustCompile("schemas.*")
|
||||
collectionURL = re.ReplaceAllString(schema.Links[SELF], schema.PluralName)
|
||||
}
|
||||
|
||||
return a.DoModify("POST", collectionURL, createObj, respObject)
|
||||
}
|
||||
|
||||
func (a *APIOperations) DoReplace(schemaType string, existing *types.Resource, updates interface{}, respObject interface{}) error {
|
||||
return a.doUpdate(schemaType, true, existing, updates, respObject)
|
||||
}
|
||||
|
||||
func (a *APIOperations) DoUpdate(schemaType string, existing *types.Resource, updates interface{}, respObject interface{}) error {
|
||||
return a.doUpdate(schemaType, false, existing, updates, respObject)
|
||||
}
|
||||
|
||||
func (a *APIOperations) doUpdate(schemaType string, replace bool, existing *types.Resource, updates interface{}, respObject interface{}) error {
|
||||
if existing == nil {
|
||||
return errors.New("Existing object is nil")
|
||||
}
|
||||
|
||||
selfURL, ok := existing.Links[SELF]
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to find self URL of [%v]", existing)
|
||||
}
|
||||
|
||||
if replace {
|
||||
u, err := url.Parse(selfURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse url %s: %v", selfURL, err)
|
||||
}
|
||||
q := u.Query()
|
||||
q.Set("_replace", "true")
|
||||
u.RawQuery = q.Encode()
|
||||
selfURL = u.String()
|
||||
}
|
||||
|
||||
if updates == nil {
|
||||
updates = map[string]string{}
|
||||
}
|
||||
|
||||
if respObject == nil {
|
||||
respObject = &map[string]interface{}{}
|
||||
}
|
||||
|
||||
schema, ok := a.Types[schemaType]
|
||||
if !ok {
|
||||
return errors.New("Unknown schema type [" + schemaType + "]")
|
||||
}
|
||||
|
||||
if !contains(schema.ResourceMethods, "PUT") {
|
||||
return errors.New("Resource type [" + schemaType + "] is not updatable")
|
||||
}
|
||||
|
||||
return a.DoModify("PUT", selfURL, updates, respObject)
|
||||
}
|
||||
|
||||
func (a *APIOperations) DoByID(schemaType string, id string, respObject interface{}) error {
|
||||
schema, ok := a.Types[schemaType]
|
||||
if !ok {
|
||||
return errors.New("Unknown schema type [" + schemaType + "]")
|
||||
}
|
||||
|
||||
if !contains(schema.ResourceMethods, "GET") {
|
||||
return errors.New("Resource type [" + schemaType + "] can not be looked up by ID")
|
||||
}
|
||||
|
||||
collectionURL, ok := schema.Links[COLLECTION]
|
||||
if !ok {
|
||||
return errors.New("Failed to find collection URL for [" + schemaType + "]")
|
||||
}
|
||||
|
||||
return a.DoGet(collectionURL+"/"+id, nil, respObject)
|
||||
}
|
||||
|
||||
func (a *APIOperations) DoResourceDelete(schemaType string, existing *types.Resource) error {
|
||||
schema, ok := a.Types[schemaType]
|
||||
if !ok {
|
||||
return errors.New("Unknown schema type [" + schemaType + "]")
|
||||
}
|
||||
|
||||
if !contains(schema.ResourceMethods, "DELETE") {
|
||||
return errors.New("Resource type [" + schemaType + "] can not be deleted")
|
||||
}
|
||||
|
||||
selfURL, ok := existing.Links[SELF]
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to find self URL of [%v]", existing)
|
||||
}
|
||||
|
||||
return a.DoDelete(selfURL)
|
||||
}
|
||||
|
||||
func (a *APIOperations) DoAction(schemaType string, action string,
|
||||
existing *types.Resource, inputObject, respObject interface{}) error {
|
||||
|
||||
if existing == nil {
|
||||
return errors.New("Existing object is nil")
|
||||
}
|
||||
|
||||
actionURL, ok := existing.Actions[action]
|
||||
if !ok {
|
||||
return fmt.Errorf("action [%v] not available on [%v]", action, existing)
|
||||
}
|
||||
|
||||
return a.doAction(schemaType, action, actionURL, inputObject, respObject)
|
||||
}
|
||||
|
||||
func (a *APIOperations) DoCollectionAction(schemaType string, action string,
|
||||
existing *types.Collection, inputObject, respObject interface{}) error {
|
||||
|
||||
if existing == nil {
|
||||
return errors.New("Existing object is nil")
|
||||
}
|
||||
|
||||
actionURL, ok := existing.Actions[action]
|
||||
if !ok {
|
||||
return fmt.Errorf("action [%v] not available on [%v]", action, existing)
|
||||
}
|
||||
|
||||
return a.doAction(schemaType, action, actionURL, inputObject, respObject)
|
||||
}
|
||||
|
||||
func (a *APIOperations) doAction(
|
||||
schemaType string,
|
||||
action string,
|
||||
actionURL string,
|
||||
inputObject interface{},
|
||||
respObject interface{},
|
||||
) error {
|
||||
_, ok := a.Types[schemaType]
|
||||
if !ok {
|
||||
return errors.New("Unknown schema type [" + schemaType + "]")
|
||||
}
|
||||
|
||||
var input io.Reader
|
||||
|
||||
if Debug {
|
||||
fmt.Println("POST " + actionURL)
|
||||
}
|
||||
|
||||
if inputObject != nil {
|
||||
bodyContent, err := json.Marshal(inputObject)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if Debug {
|
||||
fmt.Println("Request => " + string(bodyContent))
|
||||
}
|
||||
input = bytes.NewBuffer(bodyContent)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", actionURL, input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.SetupRequest(req)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Content-Length", "0")
|
||||
|
||||
resp, err := a.Client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 300 {
|
||||
return NewAPIError(resp, actionURL)
|
||||
}
|
||||
|
||||
byteContent, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if Debug {
|
||||
fmt.Println("Response <= " + string(byteContent))
|
||||
}
|
||||
|
||||
if nil != respObject {
|
||||
return json.Unmarshal(byteContent, respObject)
|
||||
}
|
||||
return nil
|
||||
}
|
296
vendor/github.com/rancher/norman/condition/condition.go
generated
vendored
296
vendor/github.com/rancher/norman/condition/condition.go
generated
vendored
@@ -1,296 +0,0 @@
|
||||
package condition
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rancher/norman/controller"
|
||||
err2 "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
type Cond string
|
||||
|
||||
var temfileRegexp = regexp.MustCompile("/tmp/[-_a-zA-Z0-9]+")
|
||||
|
||||
func (c Cond) True(obj runtime.Object) {
|
||||
setStatus(obj, string(c), "True")
|
||||
}
|
||||
|
||||
func (c Cond) IsTrue(obj runtime.Object) bool {
|
||||
return getStatus(obj, string(c)) == "True"
|
||||
}
|
||||
|
||||
func (c Cond) LastUpdated(obj runtime.Object, ts string) {
|
||||
setTS(obj, string(c), ts)
|
||||
}
|
||||
|
||||
func (c Cond) GetLastUpdated(obj runtime.Object) string {
|
||||
return getTS(obj, string(c))
|
||||
}
|
||||
|
||||
func (c Cond) False(obj runtime.Object) {
|
||||
setStatus(obj, string(c), "False")
|
||||
}
|
||||
|
||||
func (c Cond) IsFalse(obj runtime.Object) bool {
|
||||
return getStatus(obj, string(c)) == "False"
|
||||
}
|
||||
|
||||
func (c Cond) GetStatus(obj runtime.Object) string {
|
||||
return getStatus(obj, string(c))
|
||||
}
|
||||
|
||||
func (c Cond) Unknown(obj runtime.Object) {
|
||||
setStatus(obj, string(c), "Unknown")
|
||||
}
|
||||
|
||||
func (c Cond) CreateUnknownIfNotExists(obj runtime.Object) {
|
||||
condSlice := getValue(obj, "Status", "Conditions")
|
||||
cond := findCond(condSlice, string(c))
|
||||
if cond == nil {
|
||||
c.Unknown(obj)
|
||||
}
|
||||
}
|
||||
|
||||
func (c Cond) IsUnknown(obj runtime.Object) bool {
|
||||
return getStatus(obj, string(c)) == "Unknown"
|
||||
}
|
||||
|
||||
func (c Cond) Reason(obj runtime.Object, reason string) {
|
||||
cond := findOrCreateCond(obj, string(c))
|
||||
getFieldValue(cond, "Reason").SetString(reason)
|
||||
}
|
||||
|
||||
func (c Cond) SetMessageIfBlank(obj runtime.Object, message string) {
|
||||
if c.GetMessage(obj) == "" {
|
||||
c.Message(obj, message)
|
||||
}
|
||||
}
|
||||
|
||||
func (c Cond) Message(obj runtime.Object, message string) {
|
||||
cond := findOrCreateCond(obj, string(c))
|
||||
setValue(cond, "Message", message)
|
||||
}
|
||||
|
||||
func (c Cond) GetMessage(obj runtime.Object) string {
|
||||
cond := findOrNotCreateCond(obj, string(c))
|
||||
if cond == nil {
|
||||
return ""
|
||||
}
|
||||
return getFieldValue(*cond, "Message").String()
|
||||
}
|
||||
|
||||
func (c Cond) ReasonAndMessageFromError(obj runtime.Object, err error) {
|
||||
if err2.IsConflict(err) {
|
||||
return
|
||||
}
|
||||
cond := findOrCreateCond(obj, string(c))
|
||||
setValue(cond, "Message", err.Error())
|
||||
switch ce := err.(type) {
|
||||
case *conditionError:
|
||||
setValue(cond, "Reason", ce.reason)
|
||||
case *controller.ForgetError:
|
||||
if ce.Reason != "" {
|
||||
setValue(cond, "Reason", ce.Reason)
|
||||
} else {
|
||||
setValue(cond, "Reason", "Error")
|
||||
}
|
||||
default:
|
||||
setValue(cond, "Reason", "Error")
|
||||
}
|
||||
}
|
||||
|
||||
func (c Cond) GetReason(obj runtime.Object) string {
|
||||
cond := findOrNotCreateCond(obj, string(c))
|
||||
if cond == nil {
|
||||
return ""
|
||||
}
|
||||
return getFieldValue(*cond, "Reason").String()
|
||||
}
|
||||
|
||||
func (c Cond) Once(obj runtime.Object, f func() (runtime.Object, error)) (runtime.Object, error) {
|
||||
if c.IsFalse(obj) {
|
||||
return obj, &controller.ForgetError{
|
||||
Err: errors.New(c.GetReason(obj)),
|
||||
}
|
||||
}
|
||||
|
||||
return c.DoUntilTrue(obj, f)
|
||||
}
|
||||
|
||||
func (c Cond) DoUntilTrue(obj runtime.Object, f func() (runtime.Object, error)) (runtime.Object, error) {
|
||||
if c.IsTrue(obj) {
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
return c.do(obj, f)
|
||||
}
|
||||
|
||||
func (c Cond) Do(obj runtime.Object, f func() (runtime.Object, error)) (runtime.Object, error) {
|
||||
return c.do(obj, f)
|
||||
}
|
||||
|
||||
func (c Cond) do(obj runtime.Object, f func() (runtime.Object, error)) (runtime.Object, error) {
|
||||
status := c.GetStatus(obj)
|
||||
ts := c.GetLastUpdated(obj)
|
||||
reason := c.GetReason(obj)
|
||||
message := c.GetMessage(obj)
|
||||
|
||||
obj, err := c.doInternal(obj, f)
|
||||
|
||||
// This is to prevent non stop flapping of states and update
|
||||
if status == c.GetStatus(obj) &&
|
||||
reason == c.GetReason(obj) {
|
||||
if message != c.GetMessage(obj) {
|
||||
replaced := temfileRegexp.ReplaceAllString(c.GetMessage(obj), "file_path_redacted")
|
||||
c.Message(obj, replaced)
|
||||
}
|
||||
if message == c.GetMessage(obj) {
|
||||
c.LastUpdated(obj, ts)
|
||||
}
|
||||
}
|
||||
|
||||
return obj, err
|
||||
}
|
||||
|
||||
func (c Cond) doInternal(obj runtime.Object, f func() (runtime.Object, error)) (runtime.Object, error) {
|
||||
if !c.IsFalse(obj) {
|
||||
c.Unknown(obj)
|
||||
}
|
||||
|
||||
newObj, err := f()
|
||||
if newObj != nil && !reflect.ValueOf(newObj).IsNil() {
|
||||
obj = newObj
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if _, ok := err.(*controller.ForgetError); ok {
|
||||
if c.GetMessage(obj) == "" {
|
||||
c.ReasonAndMessageFromError(obj, err)
|
||||
}
|
||||
return obj, err
|
||||
}
|
||||
c.False(obj)
|
||||
c.ReasonAndMessageFromError(obj, err)
|
||||
return obj, err
|
||||
}
|
||||
c.True(obj)
|
||||
c.Reason(obj, "")
|
||||
c.Message(obj, "")
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func touchTS(value reflect.Value) {
|
||||
now := time.Now().Format(time.RFC3339)
|
||||
getFieldValue(value, "LastUpdateTime").SetString(now)
|
||||
}
|
||||
|
||||
func getStatus(obj interface{}, condName string) string {
|
||||
cond := findOrNotCreateCond(obj, condName)
|
||||
if cond == nil {
|
||||
return ""
|
||||
}
|
||||
return getFieldValue(*cond, "Status").String()
|
||||
}
|
||||
|
||||
func setTS(obj interface{}, condName, ts string) {
|
||||
cond := findOrCreateCond(obj, condName)
|
||||
getFieldValue(cond, "LastUpdateTime").SetString(ts)
|
||||
}
|
||||
|
||||
func getTS(obj interface{}, condName string) string {
|
||||
cond := findOrNotCreateCond(obj, condName)
|
||||
if cond == nil {
|
||||
return ""
|
||||
}
|
||||
return getFieldValue(*cond, "LastUpdateTime").String()
|
||||
}
|
||||
|
||||
func setStatus(obj interface{}, condName, status string) {
|
||||
cond := findOrCreateCond(obj, condName)
|
||||
setValue(cond, "Status", status)
|
||||
}
|
||||
|
||||
func setValue(cond reflect.Value, fieldName, newValue string) {
|
||||
value := getFieldValue(cond, fieldName)
|
||||
if value.String() != newValue {
|
||||
value.SetString(newValue)
|
||||
touchTS(cond)
|
||||
}
|
||||
}
|
||||
|
||||
func findOrNotCreateCond(obj interface{}, condName string) *reflect.Value {
|
||||
condSlice := getValue(obj, "Status", "Conditions")
|
||||
return findCond(condSlice, condName)
|
||||
}
|
||||
|
||||
func findOrCreateCond(obj interface{}, condName string) reflect.Value {
|
||||
condSlice := getValue(obj, "Status", "Conditions")
|
||||
cond := findCond(condSlice, condName)
|
||||
if cond != nil {
|
||||
return *cond
|
||||
}
|
||||
|
||||
newCond := reflect.New(condSlice.Type().Elem()).Elem()
|
||||
newCond.FieldByName("Type").SetString(condName)
|
||||
newCond.FieldByName("Status").SetString("Unknown")
|
||||
condSlice.Set(reflect.Append(condSlice, newCond))
|
||||
return *findCond(condSlice, condName)
|
||||
}
|
||||
|
||||
func findCond(val reflect.Value, name string) *reflect.Value {
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
cond := val.Index(i)
|
||||
typeVal := getFieldValue(cond, "Type")
|
||||
if typeVal.String() == name {
|
||||
return &cond
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getValue(obj interface{}, name ...string) reflect.Value {
|
||||
if obj == nil {
|
||||
return reflect.Value{}
|
||||
}
|
||||
v := reflect.ValueOf(obj)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
t = v.Type()
|
||||
}
|
||||
|
||||
field := v.FieldByName(name[0])
|
||||
if len(name) == 1 {
|
||||
return field
|
||||
}
|
||||
return getFieldValue(field, name[1:]...)
|
||||
}
|
||||
|
||||
func getFieldValue(v reflect.Value, name ...string) reflect.Value {
|
||||
field := v.FieldByName(name[0])
|
||||
if len(name) == 1 {
|
||||
return field
|
||||
}
|
||||
return getFieldValue(field, name[1:]...)
|
||||
}
|
||||
|
||||
func Error(reason string, err error) error {
|
||||
return &conditionError{
|
||||
reason: reason,
|
||||
message: err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
type conditionError struct {
|
||||
reason string
|
||||
message string
|
||||
}
|
||||
|
||||
func (e *conditionError) Error() string {
|
||||
return e.message
|
||||
}
|
73
vendor/github.com/rancher/norman/controller/cluster_check.go
generated
vendored
73
vendor/github.com/rancher/norman/controller/cluster_check.go
generated
vendored
@@ -1,73 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ObjectInCluster(cluster string, obj interface{}) bool {
|
||||
var clusterName string
|
||||
if c := getValue(obj, "ClusterName"); c.IsValid() {
|
||||
clusterName = c.String()
|
||||
}
|
||||
if clusterName == "" {
|
||||
if c := getValue(obj, "Spec", "ClusterName"); c.IsValid() {
|
||||
clusterName = c.String()
|
||||
}
|
||||
|
||||
}
|
||||
if clusterName == "" {
|
||||
if c := getValue(obj, "ProjectName"); c.IsValid() {
|
||||
if parts := strings.SplitN(c.String(), ":", 2); len(parts) == 2 {
|
||||
clusterName = parts[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
if clusterName == "" {
|
||||
if c := getValue(obj, "Spec", "ProjectName"); c.IsValid() {
|
||||
if parts := strings.SplitN(c.String(), ":", 2); len(parts) == 2 {
|
||||
clusterName = parts[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
if clusterName == "" {
|
||||
if a := getValue(obj, "Annotations"); a.IsValid() {
|
||||
if c := a.MapIndex(reflect.ValueOf("field.cattle.io/projectId")); c.IsValid() {
|
||||
if parts := strings.SplitN(c.String(), ":", 2); len(parts) == 2 {
|
||||
clusterName = parts[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if clusterName == "" {
|
||||
if c := getValue(obj, "Namespace"); c.IsValid() {
|
||||
clusterName = c.String()
|
||||
}
|
||||
}
|
||||
|
||||
return clusterName == cluster
|
||||
}
|
||||
|
||||
func getValue(obj interface{}, name ...string) reflect.Value {
|
||||
v := reflect.ValueOf(obj)
|
||||
t := v.Type()
|
||||
if t.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
t = v.Type()
|
||||
}
|
||||
|
||||
field := v.FieldByName(name[0])
|
||||
if !field.IsValid() || len(name) == 1 {
|
||||
return field
|
||||
}
|
||||
|
||||
return getFieldValue(field, name[1:]...)
|
||||
}
|
||||
|
||||
func getFieldValue(v reflect.Value, name ...string) reflect.Value {
|
||||
field := v.FieldByName(name[0])
|
||||
if len(name) == 1 {
|
||||
return field
|
||||
}
|
||||
return getFieldValue(field, name[1:]...)
|
||||
}
|
10
vendor/github.com/rancher/norman/controller/error.go
generated
vendored
10
vendor/github.com/rancher/norman/controller/error.go
generated
vendored
@@ -1,10 +0,0 @@
|
||||
package controller
|
||||
|
||||
type ForgetError struct {
|
||||
Err error
|
||||
Reason string
|
||||
}
|
||||
|
||||
func (f *ForgetError) Error() string {
|
||||
return f.Err.Error()
|
||||
}
|
291
vendor/github.com/rancher/norman/controller/generic_controller.go
generated
vendored
291
vendor/github.com/rancher/norman/controller/generic_controller.go
generated
vendored
@@ -1,291 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
errors2 "github.com/pkg/errors"
|
||||
"github.com/rancher/norman/metrics"
|
||||
"github.com/rancher/norman/objectclient"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/time/rate"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
)
|
||||
|
||||
const MetricsQueueEnv = "NORMAN_QUEUE_METRICS"
|
||||
const MetricsReflectorEnv = "NORMAN_REFLECTOR_METRICS"
|
||||
|
||||
var (
|
||||
resyncPeriod = 2 * time.Hour
|
||||
)
|
||||
|
||||
// Override the metrics providers
|
||||
func init() {
|
||||
if os.Getenv(MetricsQueueEnv) != "true" {
|
||||
DisableControllerWorkqueuMetrics()
|
||||
}
|
||||
if os.Getenv(MetricsReflectorEnv) != "true" {
|
||||
DisableControllerReflectorMetrics()
|
||||
}
|
||||
}
|
||||
|
||||
type HandlerFunc func(key string) error
|
||||
|
||||
type GenericController interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
AddHandler(name string, handler HandlerFunc)
|
||||
HandlerCount() int
|
||||
Enqueue(namespace, name string)
|
||||
Sync(ctx context.Context) error
|
||||
Start(ctx context.Context, threadiness int) error
|
||||
}
|
||||
|
||||
type Backend interface {
|
||||
List(opts metav1.ListOptions) (runtime.Object, error)
|
||||
Watch(opts metav1.ListOptions) (watch.Interface, error)
|
||||
ObjectFactory() objectclient.ObjectFactory
|
||||
}
|
||||
|
||||
type handlerDef struct {
|
||||
name string
|
||||
handler HandlerFunc
|
||||
}
|
||||
|
||||
type genericController struct {
|
||||
sync.Mutex
|
||||
informer cache.SharedIndexInformer
|
||||
handlers []handlerDef
|
||||
queue workqueue.RateLimitingInterface
|
||||
name string
|
||||
running bool
|
||||
synced bool
|
||||
}
|
||||
|
||||
func NewGenericController(name string, genericClient Backend) GenericController {
|
||||
informer := cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: genericClient.List,
|
||||
WatchFunc: genericClient.Watch,
|
||||
},
|
||||
genericClient.ObjectFactory().Object(), resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
|
||||
|
||||
rl := workqueue.NewMaxOfRateLimiter(
|
||||
workqueue.NewItemExponentialFailureRateLimiter(500*time.Millisecond, 1000*time.Second),
|
||||
// 10 qps, 100 bucket size. This is only for retry speed and its only the overall factor (not per item)
|
||||
&workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
|
||||
)
|
||||
|
||||
return &genericController{
|
||||
informer: informer,
|
||||
queue: workqueue.NewNamedRateLimitingQueue(rl, name),
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genericController) HandlerCount() int {
|
||||
return len(g.handlers)
|
||||
}
|
||||
|
||||
func (g *genericController) Informer() cache.SharedIndexInformer {
|
||||
return g.informer
|
||||
}
|
||||
|
||||
func (g *genericController) Enqueue(namespace, name string) {
|
||||
if namespace == "" {
|
||||
g.queue.Add(name)
|
||||
} else {
|
||||
g.queue.Add(namespace + "/" + name)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genericController) AddHandler(name string, handler HandlerFunc) {
|
||||
g.handlers = append(g.handlers, handlerDef{
|
||||
name: name,
|
||||
handler: handler,
|
||||
})
|
||||
}
|
||||
|
||||
func (g *genericController) Sync(ctx context.Context) error {
|
||||
g.Lock()
|
||||
defer g.Unlock()
|
||||
|
||||
return g.sync(ctx)
|
||||
}
|
||||
|
||||
func (g *genericController) sync(ctx context.Context) error {
|
||||
if g.synced {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer utilruntime.HandleCrash()
|
||||
|
||||
g.informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: g.queueObject,
|
||||
UpdateFunc: func(_, obj interface{}) {
|
||||
g.queueObject(obj)
|
||||
},
|
||||
DeleteFunc: g.queueObject,
|
||||
})
|
||||
|
||||
logrus.Debugf("Syncing %s Controller", g.name)
|
||||
|
||||
go g.informer.Run(ctx.Done())
|
||||
|
||||
if !cache.WaitForCacheSync(ctx.Done(), g.informer.HasSynced) {
|
||||
return fmt.Errorf("failed to sync controller %s", g.name)
|
||||
}
|
||||
logrus.Debugf("Syncing %s Controller Done", g.name)
|
||||
|
||||
g.synced = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *genericController) Start(ctx context.Context, threadiness int) error {
|
||||
g.Lock()
|
||||
defer g.Unlock()
|
||||
|
||||
if !g.synced {
|
||||
if err := g.sync(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !g.running {
|
||||
go g.run(ctx, threadiness)
|
||||
}
|
||||
|
||||
g.running = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *genericController) queueObject(obj interface{}) {
|
||||
key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
|
||||
if err == nil {
|
||||
g.queue.Add(key)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genericController) run(ctx context.Context, threadiness int) {
|
||||
defer utilruntime.HandleCrash()
|
||||
defer g.queue.ShutDown()
|
||||
|
||||
for i := 0; i < threadiness; i++ {
|
||||
go wait.Until(g.runWorker, time.Second, ctx.Done())
|
||||
}
|
||||
|
||||
<-ctx.Done()
|
||||
logrus.Infof("Shutting down %s controller", g.name)
|
||||
}
|
||||
|
||||
func (g *genericController) runWorker() {
|
||||
for g.processNextWorkItem() {
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genericController) processNextWorkItem() bool {
|
||||
key, quit := g.queue.Get()
|
||||
if quit {
|
||||
return false
|
||||
}
|
||||
defer g.queue.Done(key)
|
||||
|
||||
// do your work on the key. This method will contains your "do stuff" logic
|
||||
err := g.syncHandler(key.(string))
|
||||
checkErr := err
|
||||
if handlerErr, ok := checkErr.(*handlerError); ok {
|
||||
checkErr = handlerErr.err
|
||||
}
|
||||
if _, ok := checkErr.(*ForgetError); err == nil || ok {
|
||||
if ok {
|
||||
logrus.Debugf("%v %v completed with dropped err: %v", g.name, key, err)
|
||||
}
|
||||
g.queue.Forget(key)
|
||||
return true
|
||||
}
|
||||
|
||||
if err := filterConflictsError(err); err != nil {
|
||||
logrus.Errorf("%v %v %v", g.name, key, err)
|
||||
}
|
||||
|
||||
g.queue.AddRateLimited(key)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func ignoreError(err error, checkString bool) bool {
|
||||
err = errors2.Cause(err)
|
||||
if errors.IsConflict(err) {
|
||||
return true
|
||||
}
|
||||
if _, ok := err.(*ForgetError); ok {
|
||||
return true
|
||||
}
|
||||
if checkString {
|
||||
return strings.HasSuffix(err.Error(), "please apply your changes to the latest version and try again")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func filterConflictsError(err error) error {
|
||||
if ignoreError(err, false) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if errs, ok := errors2.Cause(err).(*types.MultiErrors); ok {
|
||||
var newErrors []error
|
||||
for _, err := range errs.Errors {
|
||||
if !ignoreError(err, true) {
|
||||
newErrors = append(newErrors)
|
||||
}
|
||||
}
|
||||
return types.NewErrors(newErrors...)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *genericController) syncHandler(s string) (err error) {
|
||||
defer utilruntime.RecoverFromPanic(&err)
|
||||
|
||||
var errs []error
|
||||
for _, handler := range g.handlers {
|
||||
logrus.Debugf("%s calling handler %s %s", g.name, handler.name, s)
|
||||
metrics.IncTotalHandlerExecution(g.name, handler.name)
|
||||
if err := handler.handler(s); err != nil {
|
||||
if !ignoreError(err, false) {
|
||||
metrics.IncTotalHandlerFailure(g.name, handler.name, s)
|
||||
}
|
||||
errs = append(errs, &handlerError{
|
||||
name: handler.name,
|
||||
err: err,
|
||||
})
|
||||
}
|
||||
}
|
||||
err = types.NewErrors(errs...)
|
||||
return
|
||||
}
|
||||
|
||||
type handlerError struct {
|
||||
name string
|
||||
err error
|
||||
}
|
||||
|
||||
func (h *handlerError) Error() string {
|
||||
return fmt.Sprintf("[%s] failed with : %v", h.name, h.err)
|
||||
}
|
||||
|
||||
func (h *handlerError) Cause() error {
|
||||
return h.err
|
||||
}
|
71
vendor/github.com/rancher/norman/controller/noop_metrics.go
generated
vendored
71
vendor/github.com/rancher/norman/controller/noop_metrics.go
generated
vendored
@@ -1,71 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
)
|
||||
|
||||
type noopMetric struct{}
|
||||
|
||||
func (noopMetric) Inc() {}
|
||||
func (noopMetric) Dec() {}
|
||||
func (noopMetric) Observe(float64) {}
|
||||
func (noopMetric) Set(float64) {}
|
||||
|
||||
type noopWorkqueueMetricsProvider struct{}
|
||||
|
||||
func (noopWorkqueueMetricsProvider) NewDepthMetric(name string) workqueue.GaugeMetric {
|
||||
return noopMetric{}
|
||||
}
|
||||
|
||||
func (noopWorkqueueMetricsProvider) NewAddsMetric(name string) workqueue.CounterMetric {
|
||||
return noopMetric{}
|
||||
}
|
||||
|
||||
func (noopWorkqueueMetricsProvider) NewLatencyMetric(name string) workqueue.SummaryMetric {
|
||||
return noopMetric{}
|
||||
}
|
||||
|
||||
func (noopWorkqueueMetricsProvider) NewWorkDurationMetric(name string) workqueue.SummaryMetric {
|
||||
return noopMetric{}
|
||||
}
|
||||
|
||||
func (noopWorkqueueMetricsProvider) NewRetriesMetric(name string) workqueue.CounterMetric {
|
||||
return noopMetric{}
|
||||
}
|
||||
|
||||
type noopCacheMetricsProvider struct{}
|
||||
|
||||
func (noopCacheMetricsProvider) NewListsMetric(name string) cache.CounterMetric { return noopMetric{} }
|
||||
func (noopCacheMetricsProvider) NewListDurationMetric(name string) cache.SummaryMetric {
|
||||
return noopMetric{}
|
||||
}
|
||||
func (noopCacheMetricsProvider) NewItemsInListMetric(name string) cache.SummaryMetric {
|
||||
return noopMetric{}
|
||||
}
|
||||
func (noopCacheMetricsProvider) NewWatchesMetric(name string) cache.CounterMetric { return noopMetric{} }
|
||||
func (noopCacheMetricsProvider) NewShortWatchesMetric(name string) cache.CounterMetric {
|
||||
return noopMetric{}
|
||||
}
|
||||
func (noopCacheMetricsProvider) NewWatchDurationMetric(name string) cache.SummaryMetric {
|
||||
return noopMetric{}
|
||||
}
|
||||
func (noopCacheMetricsProvider) NewItemsInWatchMetric(name string) cache.SummaryMetric {
|
||||
return noopMetric{}
|
||||
}
|
||||
func (noopCacheMetricsProvider) NewLastResourceVersionMetric(name string) cache.GaugeMetric {
|
||||
return noopMetric{}
|
||||
}
|
||||
|
||||
func DisableAllControllerMetrics() {
|
||||
DisableControllerReflectorMetrics()
|
||||
DisableControllerWorkqueuMetrics()
|
||||
}
|
||||
|
||||
func DisableControllerWorkqueuMetrics() {
|
||||
workqueue.SetProvider(noopWorkqueueMetricsProvider{})
|
||||
}
|
||||
|
||||
func DisableControllerReflectorMetrics() {
|
||||
cache.SetReflectorMetricsProvider(noopCacheMetricsProvider{})
|
||||
}
|
40
vendor/github.com/rancher/norman/controller/starter.go
generated
vendored
40
vendor/github.com/rancher/norman/controller/starter.go
generated
vendored
@@ -1,40 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type Starter interface {
|
||||
Sync(ctx context.Context) error
|
||||
Start(ctx context.Context, threadiness int) error
|
||||
}
|
||||
|
||||
func SyncThenStart(ctx context.Context, threadiness int, starters ...Starter) error {
|
||||
if err := Sync(ctx, starters...); err != nil {
|
||||
return err
|
||||
}
|
||||
return Start(ctx, threadiness, starters...)
|
||||
}
|
||||
|
||||
func Sync(ctx context.Context, starters ...Starter) error {
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
for _, starter := range starters {
|
||||
func(starter Starter) {
|
||||
eg.Go(func() error {
|
||||
return starter.Sync(ctx)
|
||||
})
|
||||
}(starter)
|
||||
}
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, threadiness int, starters ...Starter) error {
|
||||
for _, starter := range starters {
|
||||
if err := starter.Start(ctx, threadiness); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
66
vendor/github.com/rancher/norman/example/main.go
generated
vendored
66
vendor/github.com/rancher/norman/example/main.go
generated
vendored
@@ -1,66 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/rancher/norman/api"
|
||||
"github.com/rancher/norman/store/crd"
|
||||
"github.com/rancher/norman/store/proxy"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/factory"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
type Foo struct {
|
||||
types.Resource
|
||||
Name string `json:"name"`
|
||||
Foo string `json:"foo"`
|
||||
SubThing Baz `json:"subThing"`
|
||||
}
|
||||
|
||||
type Baz struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
var (
|
||||
version = types.APIVersion{
|
||||
Version: "v1",
|
||||
Group: "example.core.cattle.io",
|
||||
Path: "/example/v1",
|
||||
}
|
||||
|
||||
Schemas = factory.Schemas(&version)
|
||||
)
|
||||
|
||||
func main() {
|
||||
kubeConfig, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
client, err := proxy.NewClientGetterFromConfig(*kubeConfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
crdFactory := crd.Factory{
|
||||
ClientGetter: client,
|
||||
}
|
||||
|
||||
Schemas.MustImportAndCustomize(&version, Foo{}, func(schema *types.Schema) {
|
||||
if err := crdFactory.AssignStores(context.Background(), types.DefaultStorageContext, schema); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
|
||||
server := api.NewAPIServer()
|
||||
if err := server.AddSchemas(Schemas); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println("Listening on 0.0.0.0:1234")
|
||||
http.ListenAndServe("0.0.0.0:1234", server)
|
||||
}
|
31
vendor/github.com/rancher/norman/generator/client_template.go
generated
vendored
31
vendor/github.com/rancher/norman/generator/client_template.go
generated
vendored
@@ -1,31 +0,0 @@
|
||||
package generator
|
||||
|
||||
var clientTemplate = `package client
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/clientbase"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
clientbase.APIBaseClient
|
||||
|
||||
{{range .schemas}}
|
||||
{{- if . | hasGet }}{{.CodeName}} {{.CodeName}}Operations
|
||||
{{end}}{{end}}}
|
||||
|
||||
func NewClient(opts *clientbase.ClientOpts) (*Client, error) {
|
||||
baseClient, err := clientbase.NewAPIClient(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := &Client{
|
||||
APIBaseClient: baseClient,
|
||||
}
|
||||
|
||||
{{range .schemas}}
|
||||
{{- if . | hasGet }}client.{{.CodeName}} = new{{.CodeName}}Client(client)
|
||||
{{end}}{{end}}
|
||||
return client, nil
|
||||
}
|
||||
`
|
265
vendor/github.com/rancher/norman/generator/controller_template.go
generated
vendored
265
vendor/github.com/rancher/norman/generator/controller_template.go
generated
vendored
@@ -1,265 +0,0 @@
|
||||
package generator
|
||||
|
||||
var controllerTemplate = `package {{.schema.Version.Version}}
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
{{.importPackage}}
|
||||
"github.com/rancher/norman/objectclient"
|
||||
"github.com/rancher/norman/controller"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
{{.schema.CodeName}}GroupVersionKind = schema.GroupVersionKind{
|
||||
Version: Version,
|
||||
Group: GroupName,
|
||||
Kind: "{{.schema.CodeName}}",
|
||||
}
|
||||
{{.schema.CodeName}}Resource = metav1.APIResource{
|
||||
Name: "{{.schema.PluralName | toLower}}",
|
||||
SingularName: "{{.schema.ID | toLower}}",
|
||||
{{- if eq .schema.Scope "namespace" }}
|
||||
Namespaced: true,
|
||||
{{ else }}
|
||||
Namespaced: false,
|
||||
{{- end }}
|
||||
Kind: {{.schema.CodeName}}GroupVersionKind.Kind,
|
||||
}
|
||||
)
|
||||
|
||||
type {{.schema.CodeName}}List struct {
|
||||
metav1.TypeMeta %BACK%json:",inline"%BACK%
|
||||
metav1.ListMeta %BACK%json:"metadata,omitempty"%BACK%
|
||||
Items []{{.prefix}}{{.schema.CodeName}}
|
||||
}
|
||||
|
||||
type {{.schema.CodeName}}HandlerFunc func(key string, obj *{{.prefix}}{{.schema.CodeName}}) error
|
||||
|
||||
type {{.schema.CodeName}}Lister interface {
|
||||
List(namespace string, selector labels.Selector) (ret []*{{.prefix}}{{.schema.CodeName}}, err error)
|
||||
Get(namespace, name string) (*{{.prefix}}{{.schema.CodeName}}, error)
|
||||
}
|
||||
|
||||
type {{.schema.CodeName}}Controller interface {
|
||||
Generic() controller.GenericController
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() {{.schema.CodeName}}Lister
|
||||
AddHandler(name string, handler {{.schema.CodeName}}HandlerFunc)
|
||||
AddClusterScopedHandler(name, clusterName string, handler {{.schema.CodeName}}HandlerFunc)
|
||||
Enqueue(namespace, name string)
|
||||
Sync(ctx context.Context) error
|
||||
Start(ctx context.Context, threadiness int) error
|
||||
}
|
||||
|
||||
type {{.schema.CodeName}}Interface interface {
|
||||
ObjectClient() *objectclient.ObjectClient
|
||||
Create(*{{.prefix}}{{.schema.CodeName}}) (*{{.prefix}}{{.schema.CodeName}}, error)
|
||||
GetNamespaced(namespace, name string, opts metav1.GetOptions) (*{{.prefix}}{{.schema.CodeName}}, error)
|
||||
Get(name string, opts metav1.GetOptions) (*{{.prefix}}{{.schema.CodeName}}, error)
|
||||
Update(*{{.prefix}}{{.schema.CodeName}}) (*{{.prefix}}{{.schema.CodeName}}, error)
|
||||
Delete(name string, options *metav1.DeleteOptions) error
|
||||
DeleteNamespaced(namespace, name string, options *metav1.DeleteOptions) error
|
||||
List(opts metav1.ListOptions) (*{{.schema.CodeName}}List, error)
|
||||
Watch(opts metav1.ListOptions) (watch.Interface, error)
|
||||
DeleteCollection(deleteOpts *metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||
Controller() {{.schema.CodeName}}Controller
|
||||
AddHandler(name string, sync {{.schema.CodeName}}HandlerFunc)
|
||||
AddLifecycle(name string, lifecycle {{.schema.CodeName}}Lifecycle)
|
||||
AddClusterScopedHandler(name, clusterName string, sync {{.schema.CodeName}}HandlerFunc)
|
||||
AddClusterScopedLifecycle(name, clusterName string, lifecycle {{.schema.CodeName}}Lifecycle)
|
||||
}
|
||||
|
||||
type {{.schema.ID}}Lister struct {
|
||||
controller *{{.schema.ID}}Controller
|
||||
}
|
||||
|
||||
func (l *{{.schema.ID}}Lister) List(namespace string, selector labels.Selector) (ret []*{{.prefix}}{{.schema.CodeName}}, err error) {
|
||||
err = cache.ListAllByNamespace(l.controller.Informer().GetIndexer(), namespace, selector, func(obj interface{}) {
|
||||
ret = append(ret, obj.(*{{.prefix}}{{.schema.CodeName}}))
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (l *{{.schema.ID}}Lister) Get(namespace, name string) (*{{.prefix}}{{.schema.CodeName}}, error) {
|
||||
var key string
|
||||
if namespace != "" {
|
||||
key = namespace + "/" + name
|
||||
} else {
|
||||
key = name
|
||||
}
|
||||
obj, exists, err := l.controller.Informer().GetIndexer().GetByKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(schema.GroupResource{
|
||||
Group: {{.schema.CodeName}}GroupVersionKind.Group,
|
||||
Resource: "{{.schema.ID}}",
|
||||
}, key)
|
||||
}
|
||||
return obj.(*{{.prefix}}{{.schema.CodeName}}), nil
|
||||
}
|
||||
|
||||
type {{.schema.ID}}Controller struct {
|
||||
controller.GenericController
|
||||
}
|
||||
|
||||
func (c *{{.schema.ID}}Controller) Generic() controller.GenericController {
|
||||
return c.GenericController
|
||||
}
|
||||
|
||||
func (c *{{.schema.ID}}Controller) Lister() {{.schema.CodeName}}Lister {
|
||||
return &{{.schema.ID}}Lister{
|
||||
controller: c,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (c *{{.schema.ID}}Controller) AddHandler(name string, handler {{.schema.CodeName}}HandlerFunc) {
|
||||
c.GenericController.AddHandler(name, func(key string) error {
|
||||
obj, exists, err := c.Informer().GetStore().GetByKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return handler(key, nil)
|
||||
}
|
||||
return handler(key, obj.(*{{.prefix}}{{.schema.CodeName}}))
|
||||
})
|
||||
}
|
||||
|
||||
func (c *{{.schema.ID}}Controller) AddClusterScopedHandler(name, cluster string, handler {{.schema.CodeName}}HandlerFunc) {
|
||||
c.GenericController.AddHandler(name, func(key string) error {
|
||||
obj, exists, err := c.Informer().GetStore().GetByKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return handler(key, nil)
|
||||
}
|
||||
|
||||
if !controller.ObjectInCluster(cluster, obj) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return handler(key, obj.(*{{.prefix}}{{.schema.CodeName}}))
|
||||
})
|
||||
}
|
||||
|
||||
type {{.schema.ID}}Factory struct {
|
||||
}
|
||||
|
||||
func (c {{.schema.ID}}Factory) Object() runtime.Object {
|
||||
return &{{.prefix}}{{.schema.CodeName}}{}
|
||||
}
|
||||
|
||||
func (c {{.schema.ID}}Factory) List() runtime.Object {
|
||||
return &{{.schema.CodeName}}List{}
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) Controller() {{.schema.CodeName}}Controller {
|
||||
s.client.Lock()
|
||||
defer s.client.Unlock()
|
||||
|
||||
c, ok := s.client.{{.schema.ID}}Controllers[s.ns]
|
||||
if ok {
|
||||
return c
|
||||
}
|
||||
|
||||
genericController := controller.NewGenericController({{.schema.CodeName}}GroupVersionKind.Kind+"Controller",
|
||||
s.objectClient)
|
||||
|
||||
c = &{{.schema.ID}}Controller{
|
||||
GenericController: genericController,
|
||||
}
|
||||
|
||||
s.client.{{.schema.ID}}Controllers[s.ns] = c
|
||||
s.client.starters = append(s.client.starters, c)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
type {{.schema.ID}}Client struct {
|
||||
client *Client
|
||||
ns string
|
||||
objectClient *objectclient.ObjectClient
|
||||
controller {{.schema.CodeName}}Controller
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) ObjectClient() *objectclient.ObjectClient {
|
||||
return s.objectClient
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) Create(o *{{.prefix}}{{.schema.CodeName}}) (*{{.prefix}}{{.schema.CodeName}}, error) {
|
||||
obj, err := s.objectClient.Create(o)
|
||||
return obj.(*{{.prefix}}{{.schema.CodeName}}), err
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) Get(name string, opts metav1.GetOptions) (*{{.prefix}}{{.schema.CodeName}}, error) {
|
||||
obj, err := s.objectClient.Get(name, opts)
|
||||
return obj.(*{{.prefix}}{{.schema.CodeName}}), err
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) GetNamespaced(namespace, name string, opts metav1.GetOptions) (*{{.prefix}}{{.schema.CodeName}}, error) {
|
||||
obj, err := s.objectClient.GetNamespaced(namespace, name, opts)
|
||||
return obj.(*{{.prefix}}{{.schema.CodeName}}), err
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) Update(o *{{.prefix}}{{.schema.CodeName}}) (*{{.prefix}}{{.schema.CodeName}}, error) {
|
||||
obj, err := s.objectClient.Update(o.Name, o)
|
||||
return obj.(*{{.prefix}}{{.schema.CodeName}}), err
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) Delete(name string, options *metav1.DeleteOptions) error {
|
||||
return s.objectClient.Delete(name, options)
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) DeleteNamespaced(namespace, name string, options *metav1.DeleteOptions) error {
|
||||
return s.objectClient.DeleteNamespaced(namespace, name, options)
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) List(opts metav1.ListOptions) (*{{.schema.CodeName}}List, error) {
|
||||
obj, err := s.objectClient.List(opts)
|
||||
return obj.(*{{.schema.CodeName}}List), err
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) Watch(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
return s.objectClient.Watch(opts)
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched deployment.
|
||||
func (s *{{.schema.ID}}Client) Patch(o *{{.prefix}}{{.schema.CodeName}}, data []byte, subresources ...string) (*{{.prefix}}{{.schema.CodeName}}, error) {
|
||||
obj, err := s.objectClient.Patch(o.Name, o, data, subresources...)
|
||||
return obj.(*{{.prefix}}{{.schema.CodeName}}), err
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) DeleteCollection(deleteOpts *metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
||||
return s.objectClient.DeleteCollection(deleteOpts, listOpts)
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) AddHandler(name string, sync {{.schema.CodeName}}HandlerFunc) {
|
||||
s.Controller().AddHandler(name, sync)
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) AddLifecycle(name string, lifecycle {{.schema.CodeName}}Lifecycle) {
|
||||
sync := New{{.schema.CodeName}}LifecycleAdapter(name, false, s, lifecycle)
|
||||
s.AddHandler(name, sync)
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) AddClusterScopedHandler(name, clusterName string, sync {{.schema.CodeName}}HandlerFunc) {
|
||||
s.Controller().AddClusterScopedHandler(name, clusterName, sync)
|
||||
}
|
||||
|
||||
func (s *{{.schema.ID}}Client) AddClusterScopedLifecycle(name, clusterName string, lifecycle {{.schema.CodeName}}Lifecycle) {
|
||||
sync := New{{.schema.CodeName}}LifecycleAdapter(name+"_"+clusterName, true, s, lifecycle)
|
||||
s.AddClusterScopedHandler(name, clusterName, sync)
|
||||
}
|
||||
`
|
50
vendor/github.com/rancher/norman/generator/funcs.go
generated
vendored
50
vendor/github.com/rancher/norman/generator/funcs.go
generated
vendored
@@ -1,50 +0,0 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
)
|
||||
|
||||
func funcs() template.FuncMap {
|
||||
return template.FuncMap{
|
||||
"capitalize": convert.Capitalize,
|
||||
"unCapitalize": convert.Uncapitalize,
|
||||
"upper": strings.ToUpper,
|
||||
"toLower": strings.ToLower,
|
||||
"hasGet": hasGet,
|
||||
"hasPost": hasPost,
|
||||
"getCollectionOutput": getCollectionOutput,
|
||||
}
|
||||
}
|
||||
|
||||
func addUnderscore(input string) string {
|
||||
return strings.ToLower(underscoreRegexp.ReplaceAllString(input, `${1}_${2}`))
|
||||
}
|
||||
|
||||
func hasGet(schema *types.Schema) bool {
|
||||
return contains(schema.CollectionMethods, http.MethodGet)
|
||||
}
|
||||
|
||||
func hasPost(schema *types.Schema) bool {
|
||||
return contains(schema.CollectionMethods, http.MethodPost)
|
||||
}
|
||||
|
||||
func contains(list []string, needle string) bool {
|
||||
for _, i := range list {
|
||||
if i == needle {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getCollectionOutput(output, codeName string) string {
|
||||
if output == "collection" {
|
||||
return codeName + "Collection"
|
||||
}
|
||||
return convert.Capitalize(output)
|
||||
}
|
526
vendor/github.com/rancher/norman/generator/generator.go
generated
vendored
526
vendor/github.com/rancher/norman/generator/generator.go
generated
vendored
@@ -1,526 +0,0 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
"k8s.io/gengo/args"
|
||||
"k8s.io/gengo/examples/deepcopy-gen/generators"
|
||||
"k8s.io/gengo/generator"
|
||||
gengotypes "k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
var (
|
||||
blackListTypes = map[string]bool{
|
||||
"schema": true,
|
||||
"resource": true,
|
||||
"collection": true,
|
||||
}
|
||||
underscoreRegexp = regexp.MustCompile(`([a-z])([A-Z])`)
|
||||
)
|
||||
|
||||
type fieldInfo struct {
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
|
||||
func getGoType(field types.Field, schema *types.Schema, schemas *types.Schemas) string {
|
||||
return getTypeString(field.Nullable, field.Type, schema, schemas)
|
||||
}
|
||||
|
||||
func getTypeString(nullable bool, typeName string, schema *types.Schema, schemas *types.Schemas) string {
|
||||
switch {
|
||||
case strings.HasPrefix(typeName, "reference["):
|
||||
return "string"
|
||||
case strings.HasPrefix(typeName, "map["):
|
||||
return "map[string]" + getTypeString(false, typeName[len("map["):len(typeName)-1], schema, schemas)
|
||||
case strings.HasPrefix(typeName, "array["):
|
||||
return "[]" + getTypeString(false, typeName[len("array["):len(typeName)-1], schema, schemas)
|
||||
}
|
||||
|
||||
name := ""
|
||||
|
||||
switch typeName {
|
||||
case "base64":
|
||||
return "string"
|
||||
case "json":
|
||||
return "interface{}"
|
||||
case "boolean":
|
||||
name = "bool"
|
||||
case "float":
|
||||
name = "float64"
|
||||
case "int":
|
||||
name = "int64"
|
||||
case "multiline":
|
||||
return "string"
|
||||
case "masked":
|
||||
return "string"
|
||||
case "password":
|
||||
return "string"
|
||||
case "date":
|
||||
return "string"
|
||||
case "string":
|
||||
return "string"
|
||||
case "enum":
|
||||
return "string"
|
||||
case "intOrString":
|
||||
return "intstr.IntOrString"
|
||||
case "dnsLabel":
|
||||
return "string"
|
||||
case "dnsLabelRestricted":
|
||||
return "string"
|
||||
case "hostname":
|
||||
return "string"
|
||||
default:
|
||||
if schema != nil && schemas != nil {
|
||||
otherSchema := schemas.Schema(&schema.Version, typeName)
|
||||
if otherSchema != nil {
|
||||
name = otherSchema.CodeName
|
||||
}
|
||||
}
|
||||
|
||||
if name == "" {
|
||||
name = convert.Capitalize(typeName)
|
||||
}
|
||||
}
|
||||
|
||||
if nullable {
|
||||
return "*" + name
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
func getTypeMap(schema *types.Schema, schemas *types.Schemas) map[string]fieldInfo {
|
||||
result := map[string]fieldInfo{}
|
||||
for name, field := range schema.ResourceFields {
|
||||
if strings.EqualFold(name, "id") {
|
||||
continue
|
||||
}
|
||||
result[field.CodeName] = fieldInfo{
|
||||
Name: name,
|
||||
Type: getGoType(field, schema, schemas),
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func getResourceActions(schema *types.Schema, schemas *types.Schemas) map[string]types.Action {
|
||||
result := map[string]types.Action{}
|
||||
for name, action := range schema.ResourceActions {
|
||||
if action.Output != "" {
|
||||
if schemas.Schema(&schema.Version, action.Output) != nil {
|
||||
result[name] = action
|
||||
}
|
||||
} else {
|
||||
result[name] = action
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func getCollectionActions(schema *types.Schema, schemas *types.Schemas) map[string]types.Action {
|
||||
result := map[string]types.Action{}
|
||||
for name, action := range schema.CollectionActions {
|
||||
if action.Output != "" {
|
||||
output := action.Output
|
||||
if action.Output == "collection" {
|
||||
output = strings.ToLower(schema.CodeName)
|
||||
}
|
||||
if schemas.Schema(&schema.Version, output) != nil {
|
||||
result[name] = action
|
||||
}
|
||||
} else {
|
||||
result[name] = action
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func generateType(outputDir string, schema *types.Schema, schemas *types.Schemas) error {
|
||||
filePath := strings.ToLower("zz_generated_" + addUnderscore(schema.ID) + ".go")
|
||||
output, err := os.Create(path.Join(outputDir, filePath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
|
||||
typeTemplate, err := template.New("type.template").
|
||||
Funcs(funcs()).
|
||||
Parse(strings.Replace(typeTemplate, "%BACK%", "`", -1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return typeTemplate.Execute(output, map[string]interface{}{
|
||||
"schema": schema,
|
||||
"structFields": getTypeMap(schema, schemas),
|
||||
"resourceActions": getResourceActions(schema, schemas),
|
||||
"collectionActions": getCollectionActions(schema, schemas),
|
||||
})
|
||||
}
|
||||
|
||||
func generateLifecycle(external bool, outputDir string, schema *types.Schema, schemas *types.Schemas) error {
|
||||
filePath := strings.ToLower("zz_generated_" + addUnderscore(schema.ID) + "_lifecycle_adapter.go")
|
||||
output, err := os.Create(path.Join(outputDir, filePath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
|
||||
typeTemplate, err := template.New("lifecycle.template").
|
||||
Funcs(funcs()).
|
||||
Parse(strings.Replace(lifecycleTemplate, "%BACK%", "`", -1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
importPackage := ""
|
||||
prefix := ""
|
||||
if external {
|
||||
parts := strings.Split(schema.PkgName, "/vendor/")
|
||||
importPackage = fmt.Sprintf("\"%s\"", parts[len(parts)-1])
|
||||
prefix = schema.Version.Version + "."
|
||||
}
|
||||
|
||||
return typeTemplate.Execute(output, map[string]interface{}{
|
||||
"schema": schema,
|
||||
"importPackage": importPackage,
|
||||
"prefix": prefix,
|
||||
})
|
||||
}
|
||||
|
||||
func generateController(external bool, outputDir string, schema *types.Schema, schemas *types.Schemas) error {
|
||||
filePath := strings.ToLower("zz_generated_" + addUnderscore(schema.ID) + "_controller.go")
|
||||
output, err := os.Create(path.Join(outputDir, filePath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
|
||||
typeTemplate, err := template.New("controller.template").
|
||||
Funcs(funcs()).
|
||||
Parse(strings.Replace(controllerTemplate, "%BACK%", "`", -1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
importPackage := ""
|
||||
prefix := ""
|
||||
if external {
|
||||
parts := strings.Split(schema.PkgName, "/vendor/")
|
||||
importPackage = fmt.Sprintf("\"%s\"", parts[len(parts)-1])
|
||||
prefix = schema.Version.Version + "."
|
||||
}
|
||||
|
||||
return typeTemplate.Execute(output, map[string]interface{}{
|
||||
"schema": schema,
|
||||
"importPackage": importPackage,
|
||||
"prefix": prefix,
|
||||
})
|
||||
}
|
||||
|
||||
func generateScheme(external bool, outputDir string, version *types.APIVersion, schemas []*types.Schema) error {
|
||||
filePath := strings.ToLower("zz_generated_scheme.go")
|
||||
output, err := os.Create(path.Join(outputDir, filePath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
|
||||
typeTemplate, err := template.New("scheme.template").
|
||||
Funcs(funcs()).
|
||||
Parse(strings.Replace(schemeTemplate, "%BACK%", "`", -1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
names := []string{}
|
||||
for _, schema := range schemas {
|
||||
if !external {
|
||||
names = append(names, schema.CodeName)
|
||||
}
|
||||
if schema.CanList(nil) == nil {
|
||||
names = append(names, schema.CodeName+"List")
|
||||
}
|
||||
}
|
||||
|
||||
return typeTemplate.Execute(output, map[string]interface{}{
|
||||
"version": version,
|
||||
"schemas": schemas,
|
||||
"names": names,
|
||||
})
|
||||
}
|
||||
|
||||
func generateK8sClient(outputDir string, version *types.APIVersion, schemas []*types.Schema) error {
|
||||
filePath := strings.ToLower("zz_generated_k8s_client.go")
|
||||
output, err := os.Create(path.Join(outputDir, filePath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
|
||||
typeTemplate, err := template.New("k8sClient.template").
|
||||
Funcs(funcs()).
|
||||
Parse(strings.Replace(k8sClientTemplate, "%BACK%", "`", -1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return typeTemplate.Execute(output, map[string]interface{}{
|
||||
"version": version,
|
||||
"schemas": schemas,
|
||||
})
|
||||
}
|
||||
|
||||
func generateClient(outputDir string, schemas []*types.Schema) error {
|
||||
template, err := template.New("client.template").
|
||||
Funcs(funcs()).
|
||||
Parse(clientTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
output, err := os.Create(path.Join(outputDir, "zz_generated_client.go"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
|
||||
return template.Execute(output, map[string]interface{}{
|
||||
"schemas": schemas,
|
||||
})
|
||||
}
|
||||
|
||||
func GenerateControllerForTypes(version *types.APIVersion, k8sOutputPackage string, nsObjs []interface{}, objs []interface{}) error {
|
||||
baseDir := args.DefaultSourceTree()
|
||||
k8sDir := path.Join(baseDir, k8sOutputPackage)
|
||||
|
||||
if err := prepareDirs(k8sDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
schemas := types.NewSchemas()
|
||||
var controllers []*types.Schema
|
||||
|
||||
for _, obj := range objs {
|
||||
schema, err := schemas.Import(version, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
controllers = append(controllers, schema)
|
||||
|
||||
if err := generateController(true, k8sDir, schema, schemas); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := generateLifecycle(true, k8sDir, schema, schemas); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, obj := range nsObjs {
|
||||
schema, err := schemas.Import(version, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
schema.Scope = types.NamespaceScope
|
||||
controllers = append(controllers, schema)
|
||||
|
||||
if err := generateController(true, k8sDir, schema, schemas); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := generateLifecycle(true, k8sDir, schema, schemas); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := deepCopyGen(baseDir, k8sOutputPackage); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := generateK8sClient(k8sDir, version, controllers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := generateScheme(true, k8sDir, version, controllers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gofmt(baseDir, k8sOutputPackage)
|
||||
}
|
||||
|
||||
func Generate(schemas *types.Schemas, backendTypes map[string]bool, cattleOutputPackage, k8sOutputPackage string) error {
|
||||
baseDir := args.DefaultSourceTree()
|
||||
cattleDir := path.Join(baseDir, cattleOutputPackage)
|
||||
k8sDir := path.Join(baseDir, k8sOutputPackage)
|
||||
|
||||
if err := prepareDirs(cattleDir, k8sDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
controllers := []*types.Schema{}
|
||||
|
||||
cattleClientTypes := []*types.Schema{}
|
||||
for _, schema := range schemas.Schemas() {
|
||||
if blackListTypes[schema.ID] {
|
||||
continue
|
||||
}
|
||||
|
||||
_, backendType := backendTypes[schema.ID]
|
||||
|
||||
if err := generateType(cattleDir, schema, schemas); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if backendType ||
|
||||
(contains(schema.CollectionMethods, http.MethodGet) &&
|
||||
!strings.HasPrefix(schema.PkgName, "k8s.io") &&
|
||||
!strings.Contains(schema.PkgName, "/vendor/")) {
|
||||
controllers = append(controllers, schema)
|
||||
if err := generateController(false, k8sDir, schema, schemas); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := generateLifecycle(false, k8sDir, schema, schemas); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !backendType {
|
||||
cattleClientTypes = append(cattleClientTypes, schema)
|
||||
}
|
||||
}
|
||||
|
||||
if err := generateClient(cattleDir, cattleClientTypes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(controllers) > 0 {
|
||||
if err := deepCopyGen(baseDir, k8sOutputPackage); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := generateK8sClient(k8sDir, &controllers[0].Version, controllers); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := generateScheme(false, k8sDir, &controllers[0].Version, controllers); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := gofmt(baseDir, k8sOutputPackage); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gofmt(baseDir, cattleOutputPackage)
|
||||
}
|
||||
|
||||
func prepareDirs(dirs ...string) error {
|
||||
for _, dir := range dirs {
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
files, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if strings.HasPrefix(file.Name(), "zz_generated") {
|
||||
if err := os.Remove(path.Join(dir, file.Name())); err != nil {
|
||||
return errors.Wrapf(err, "failed to delete %s", path.Join(dir, file.Name()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func gofmt(workDir, pkg string) error {
|
||||
cmd := exec.Command("goimports", "-w", "-l", "./"+pkg)
|
||||
cmd.Dir = workDir
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func deepCopyGen(workDir, pkg string) error {
|
||||
arguments := &args.GeneratorArgs{
|
||||
InputDirs: []string{pkg},
|
||||
OutputBase: workDir,
|
||||
OutputPackagePath: pkg,
|
||||
OutputFileBaseName: "zz_generated_deepcopy",
|
||||
GoHeaderFilePath: "/dev/null",
|
||||
GeneratedBuildTag: "ignore_autogenerated",
|
||||
}
|
||||
|
||||
return arguments.Execute(
|
||||
generators.NameSystems(),
|
||||
generators.DefaultNameSystem(),
|
||||
func(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
|
||||
packageParts := strings.Split(pkg, "/")
|
||||
return generator.Packages{
|
||||
&generator.DefaultPackage{
|
||||
PackageName: packageParts[len(packageParts)-1],
|
||||
PackagePath: pkg,
|
||||
HeaderText: []byte{},
|
||||
GeneratorFunc: func(c *generator.Context) []generator.Generator {
|
||||
return []generator.Generator{
|
||||
//&noInitGenerator{
|
||||
generators.NewGenDeepCopy(arguments.OutputFileBaseName, pkg, nil, true, true),
|
||||
//},
|
||||
}
|
||||
},
|
||||
FilterFunc: func(c *generator.Context, t *gengotypes.Type) bool {
|
||||
if t.Name.Package != pkg {
|
||||
return false
|
||||
}
|
||||
|
||||
if isObjectOrList(t) {
|
||||
t.SecondClosestCommentLines = append(t.SecondClosestCommentLines,
|
||||
"+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object")
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type noInitGenerator struct {
|
||||
generator.Generator
|
||||
}
|
||||
|
||||
func (n *noInitGenerator) Init(*generator.Context, io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func isObjectOrList(t *gengotypes.Type) bool {
|
||||
for _, member := range t.Members {
|
||||
if member.Embedded && (member.Name == "ObjectMeta" || member.Name == "ListMeta") {
|
||||
return true
|
||||
}
|
||||
if member.Embedded && isObjectOrList(member.Type) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
74
vendor/github.com/rancher/norman/generator/k8s_client_template.go
generated
vendored
74
vendor/github.com/rancher/norman/generator/k8s_client_template.go
generated
vendored
@@ -1,74 +0,0 @@
|
||||
package generator
|
||||
|
||||
var k8sClientTemplate = `package {{.version.Version}}
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"context"
|
||||
|
||||
"github.com/rancher/norman/objectclient"
|
||||
"github.com/rancher/norman/objectclient/dynamic"
|
||||
"github.com/rancher/norman/controller"
|
||||
"github.com/rancher/norman/restwatch"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
controller.Starter
|
||||
{{range .schemas}}
|
||||
{{.CodeNamePlural}}Getter{{end}}
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
sync.Mutex
|
||||
restClient rest.Interface
|
||||
starters []controller.Starter
|
||||
{{range .schemas}}
|
||||
{{.ID}}Controllers map[string]{{.CodeName}}Controller{{end}}
|
||||
}
|
||||
|
||||
func NewForConfig(config rest.Config) (Interface, error) {
|
||||
if config.NegotiatedSerializer == nil {
|
||||
config.NegotiatedSerializer = dynamic.NegotiatedSerializer
|
||||
}
|
||||
|
||||
restClient, err := restwatch.UnversionedRESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{
|
||||
restClient: restClient,
|
||||
{{range .schemas}}
|
||||
{{.ID}}Controllers: map[string]{{.CodeName}}Controller{},{{end}}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) RESTClient() rest.Interface {
|
||||
return c.restClient
|
||||
}
|
||||
|
||||
func (c *Client) Sync(ctx context.Context) error {
|
||||
return controller.Sync(ctx, c.starters...)
|
||||
}
|
||||
|
||||
func (c *Client) Start(ctx context.Context, threadiness int) error {
|
||||
return controller.Start(ctx, threadiness, c.starters...)
|
||||
}
|
||||
|
||||
{{range .schemas}}
|
||||
type {{.CodeNamePlural}}Getter interface {
|
||||
{{.CodeNamePlural}}(namespace string) {{.CodeName}}Interface
|
||||
}
|
||||
|
||||
func (c *Client) {{.CodeNamePlural}}(namespace string) {{.CodeName}}Interface {
|
||||
objectClient := objectclient.NewObjectClient(namespace, c.restClient, &{{.CodeName}}Resource, {{.CodeName}}GroupVersionKind, {{.ID}}Factory{})
|
||||
return &{{.ID}}Client{
|
||||
ns: namespace,
|
||||
client: c,
|
||||
objectClient: objectClient,
|
||||
}
|
||||
}
|
||||
{{end}}
|
||||
`
|
55
vendor/github.com/rancher/norman/generator/lifecycle_template.go
generated
vendored
55
vendor/github.com/rancher/norman/generator/lifecycle_template.go
generated
vendored
@@ -1,55 +0,0 @@
|
||||
package generator
|
||||
|
||||
var lifecycleTemplate = `package {{.schema.Version.Version}}
|
||||
|
||||
import (
|
||||
{{.importPackage}}
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"github.com/rancher/norman/lifecycle"
|
||||
)
|
||||
|
||||
type {{.schema.CodeName}}Lifecycle interface {
|
||||
Create(obj *{{.prefix}}{{.schema.CodeName}}) (*{{.prefix}}{{.schema.CodeName}}, error)
|
||||
Remove(obj *{{.prefix}}{{.schema.CodeName}}) (*{{.prefix}}{{.schema.CodeName}}, error)
|
||||
Updated(obj *{{.prefix}}{{.schema.CodeName}}) (*{{.prefix}}{{.schema.CodeName}}, error)
|
||||
}
|
||||
|
||||
type {{.schema.ID}}LifecycleAdapter struct {
|
||||
lifecycle {{.schema.CodeName}}Lifecycle
|
||||
}
|
||||
|
||||
func (w *{{.schema.ID}}LifecycleAdapter) Create(obj runtime.Object) (runtime.Object, error) {
|
||||
o, err := w.lifecycle.Create(obj.(*{{.prefix}}{{.schema.CodeName}}))
|
||||
if o == nil {
|
||||
return nil, err
|
||||
}
|
||||
return o, err
|
||||
}
|
||||
|
||||
func (w *{{.schema.ID}}LifecycleAdapter) Finalize(obj runtime.Object) (runtime.Object, error) {
|
||||
o, err := w.lifecycle.Remove(obj.(*{{.prefix}}{{.schema.CodeName}}))
|
||||
if o == nil {
|
||||
return nil, err
|
||||
}
|
||||
return o, err
|
||||
}
|
||||
|
||||
func (w *{{.schema.ID}}LifecycleAdapter) Updated(obj runtime.Object) (runtime.Object, error) {
|
||||
o, err := w.lifecycle.Updated(obj.(*{{.prefix}}{{.schema.CodeName}}))
|
||||
if o == nil {
|
||||
return nil, err
|
||||
}
|
||||
return o, err
|
||||
}
|
||||
|
||||
func New{{.schema.CodeName}}LifecycleAdapter(name string, clusterScoped bool, client {{.schema.CodeName}}Interface, l {{.schema.CodeName}}Lifecycle) {{.schema.CodeName}}HandlerFunc {
|
||||
adapter := &{{.schema.ID}}LifecycleAdapter{lifecycle: l}
|
||||
syncFn := lifecycle.NewObjectLifecycleAdapter(name, clusterScoped, adapter, client.ObjectClient())
|
||||
return func(key string, obj *{{.prefix}}{{.schema.CodeName}}) error {
|
||||
if obj == nil {
|
||||
return syncFn(key, nil)
|
||||
}
|
||||
return syncFn(key, obj)
|
||||
}
|
||||
}
|
||||
`
|
42
vendor/github.com/rancher/norman/generator/scheme_template.go
generated
vendored
42
vendor/github.com/rancher/norman/generator/scheme_template.go
generated
vendored
@@ -1,42 +0,0 @@
|
||||
package generator
|
||||
|
||||
var schemeTemplate = `package {{.version.Version}}
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
GroupName = "{{.version.Group}}"
|
||||
Version = "{{.version.Version}}"
|
||||
)
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: Version}
|
||||
|
||||
// Kind takes an unqualified kind and returns a Group qualified GroupKind
|
||||
func Kind(kind string) schema.GroupKind {
|
||||
return SchemeGroupVersion.WithKind(kind).GroupKind()
|
||||
}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
var (
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
// TODO this gets cleaned up when the types are fixed
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
{{range .names}}
|
||||
&{{.}}{},{{end}}
|
||||
)
|
||||
return nil
|
||||
}
|
||||
`
|
166
vendor/github.com/rancher/norman/generator/type_template.go
generated
vendored
166
vendor/github.com/rancher/norman/generator/type_template.go
generated
vendored
@@ -1,166 +0,0 @@
|
||||
package generator
|
||||
|
||||
var typeTemplate = `package client
|
||||
|
||||
{{- if .schema | hasGet }}
|
||||
import (
|
||||
"github.com/rancher/norman/types"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
{{- end}}
|
||||
|
||||
const (
|
||||
{{.schema.CodeName}}Type = "{{.schema.ID}}"
|
||||
{{- range $key, $value := .structFields}}
|
||||
{{$.schema.CodeName}}Field{{$key}} = "{{$value.Name}}"
|
||||
{{- end}}
|
||||
)
|
||||
|
||||
type {{.schema.CodeName}} struct {
|
||||
{{- if .schema | hasGet }}
|
||||
types.Resource
|
||||
{{- end}}
|
||||
{{- range $key, $value := .structFields}}
|
||||
{{$key}} {{$value.Type}} %BACK%json:"{{$value.Name}},omitempty" yaml:"{{$value.Name}},omitempty"%BACK%
|
||||
{{- end}}
|
||||
}
|
||||
|
||||
{{ if .schema | hasGet }}
|
||||
type {{.schema.CodeName}}Collection struct {
|
||||
types.Collection
|
||||
Data []{{.schema.CodeName}} %BACK%json:"data,omitempty"%BACK%
|
||||
client *{{.schema.CodeName}}Client
|
||||
}
|
||||
|
||||
type {{.schema.CodeName}}Client struct {
|
||||
apiClient *Client
|
||||
}
|
||||
|
||||
type {{.schema.CodeName}}Operations interface {
|
||||
List(opts *types.ListOpts) (*{{.schema.CodeName}}Collection, error)
|
||||
Create(opts *{{.schema.CodeName}}) (*{{.schema.CodeName}}, error)
|
||||
Update(existing *{{.schema.CodeName}}, updates interface{}) (*{{.schema.CodeName}}, error)
|
||||
Replace(existing *{{.schema.CodeName}}) (*{{.schema.CodeName}}, error)
|
||||
ByID(id string) (*{{.schema.CodeName}}, error)
|
||||
Delete(container *{{.schema.CodeName}}) error
|
||||
{{range $key, $value := .resourceActions}}
|
||||
{{if (and (eq $value.Input "") (eq $value.Output ""))}}
|
||||
Action{{$key | capitalize}} (resource *{{$.schema.CodeName}}) (error)
|
||||
{{else if (and (eq $value.Input "") (ne $value.Output ""))}}
|
||||
Action{{$key | capitalize}} (resource *{{$.schema.CodeName}}) (*{{.Output | capitalize}}, error)
|
||||
{{else if (and (ne $value.Input "") (eq $value.Output ""))}}
|
||||
Action{{$key | capitalize}} (resource *{{$.schema.CodeName}}, input *{{$value.Input | capitalize}}) (error)
|
||||
{{else}}
|
||||
Action{{$key | capitalize}} (resource *{{$.schema.CodeName}}, input *{{$value.Input | capitalize}}) (*{{.Output | capitalize}}, error)
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{range $key, $value := .collectionActions}}
|
||||
{{if (and (eq $value.Input "") (eq $value.Output ""))}}
|
||||
CollectionAction{{$key | capitalize}} (resource *{{$.schema.CodeName}}Collection) (error)
|
||||
{{else if (and (eq $value.Input "") (ne $value.Output ""))}}
|
||||
CollectionAction{{$key | capitalize}} (resource *{{$.schema.CodeName}}Collection) (*{{getCollectionOutput $value.Output $.schema.CodeName}}, error)
|
||||
{{else if (and (ne $value.Input "") (eq $value.Output ""))}}
|
||||
CollectionAction{{$key | capitalize}} (resource *{{$.schema.CodeName}}Collection, input *{{$value.Input | capitalize}}) (error)
|
||||
{{else}}
|
||||
CollectionAction{{$key | capitalize}} (resource *{{$.schema.CodeName}}Collection, input *{{$value.Input | capitalize}}) (*{{getCollectionOutput $value.Output $.schema.CodeName}}, error)
|
||||
{{end}}
|
||||
{{end}}
|
||||
}
|
||||
|
||||
func new{{.schema.CodeName}}Client(apiClient *Client) *{{.schema.CodeName}}Client {
|
||||
return &{{.schema.CodeName}}Client{
|
||||
apiClient: apiClient,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *{{.schema.CodeName}}Client) Create(container *{{.schema.CodeName}}) (*{{.schema.CodeName}}, error) {
|
||||
resp := &{{.schema.CodeName}}{}
|
||||
err := c.apiClient.Ops.DoCreate({{.schema.CodeName}}Type, container, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (c *{{.schema.CodeName}}Client) Update(existing *{{.schema.CodeName}}, updates interface{}) (*{{.schema.CodeName}}, error) {
|
||||
resp := &{{.schema.CodeName}}{}
|
||||
err := c.apiClient.Ops.DoUpdate({{.schema.CodeName}}Type, &existing.Resource, updates, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (c *{{.schema.CodeName}}Client) Replace(obj *{{.schema.CodeName}}) (*{{.schema.CodeName}}, error) {
|
||||
resp := &{{.schema.CodeName}}{}
|
||||
err := c.apiClient.Ops.DoReplace({{.schema.CodeName}}Type, &obj.Resource, obj, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (c *{{.schema.CodeName}}Client) List(opts *types.ListOpts) (*{{.schema.CodeName}}Collection, error) {
|
||||
resp := &{{.schema.CodeName}}Collection{}
|
||||
err := c.apiClient.Ops.DoList({{.schema.CodeName}}Type, opts, resp)
|
||||
resp.client = c
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (cc *{{.schema.CodeName}}Collection) Next() (*{{.schema.CodeName}}Collection, error) {
|
||||
if cc != nil && cc.Pagination != nil && cc.Pagination.Next != "" {
|
||||
resp := &{{.schema.CodeName}}Collection{}
|
||||
err := cc.client.apiClient.Ops.DoNext(cc.Pagination.Next, resp)
|
||||
resp.client = cc.client
|
||||
return resp, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *{{.schema.CodeName}}Client) ByID(id string) (*{{.schema.CodeName}}, error) {
|
||||
resp := &{{.schema.CodeName}}{}
|
||||
err := c.apiClient.Ops.DoByID({{.schema.CodeName}}Type, id, resp)
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (c *{{.schema.CodeName}}Client) Delete(container *{{.schema.CodeName}}) error {
|
||||
return c.apiClient.Ops.DoResourceDelete({{.schema.CodeName}}Type, &container.Resource)
|
||||
}
|
||||
|
||||
{{range $key, $value := .resourceActions}}
|
||||
{{if (and (eq $value.Input "") (eq $value.Output ""))}}
|
||||
func (c *{{$.schema.CodeName}}Client) Action{{$key | capitalize}} (resource *{{$.schema.CodeName}}) (error) {
|
||||
err := c.apiClient.Ops.DoAction({{$.schema.CodeName}}Type, "{{$key}}", &resource.Resource, nil, nil)
|
||||
return err
|
||||
{{else if (and (eq $value.Input "") (ne $value.Output ""))}}
|
||||
func (c *{{$.schema.CodeName}}Client) Action{{$key | capitalize}} (resource *{{$.schema.CodeName}}) (*{{.Output | capitalize}}, error) {
|
||||
resp := &{{.Output | capitalize}}{}
|
||||
err := c.apiClient.Ops.DoAction({{$.schema.CodeName}}Type, "{{$key}}", &resource.Resource, nil, resp)
|
||||
return resp, err
|
||||
{{else if (and (ne $value.Input "") (eq $value.Output ""))}}
|
||||
func (c *{{$.schema.CodeName}}Client) Action{{$key | capitalize}} (resource *{{$.schema.CodeName}}, input *{{$value.Input | capitalize}}) (error) {
|
||||
err := c.apiClient.Ops.DoAction({{$.schema.CodeName}}Type, "{{$key}}", &resource.Resource, input, nil)
|
||||
return err
|
||||
{{else}}
|
||||
func (c *{{$.schema.CodeName}}Client) Action{{$key | capitalize}} (resource *{{$.schema.CodeName}}, input *{{$value.Input | capitalize}}) (*{{.Output | capitalize}}, error) {
|
||||
resp := &{{.Output | capitalize}}{}
|
||||
err := c.apiClient.Ops.DoAction({{$.schema.CodeName}}Type, "{{$key}}", &resource.Resource, input, resp)
|
||||
return resp, err
|
||||
{{- end -}}
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{range $key, $value := .collectionActions}}
|
||||
{{if (and (eq $value.Input "") (eq $value.Output ""))}}
|
||||
func (c *{{$.schema.CodeName}}Client) CollectionAction{{$key | capitalize}} (resource *{{$.schema.CodeName}}Collection) (error) {
|
||||
err := c.apiClient.Ops.DoCollectionAction({{$.schema.CodeName}}Type, "{{$key}}", &resource.Collection, nil, nil)
|
||||
return err
|
||||
{{else if (and (eq $value.Input "") (ne $value.Output ""))}}
|
||||
func (c *{{$.schema.CodeName}}Client) CollectionAction{{$key | capitalize}} (resource *{{$.schema.CodeName}}Collection) (*{{getCollectionOutput $value.Output $.schema.CodeName}}, error) {
|
||||
resp := &{{getCollectionOutput $value.Output $.schema.CodeName}}{}
|
||||
err := c.apiClient.Ops.DoCollectionAction({{$.schema.CodeName}}Type, "{{$key}}", &resource.Collection, nil, resp)
|
||||
return resp, err
|
||||
{{else if (and (ne $value.Input "") (eq $value.Output ""))}}
|
||||
func (c *{{$.schema.CodeName}}Client) CollectionAction{{$key | capitalize}} (resource *{{$.schema.CodeName}}Collection, input *{{$value.Input | capitalize}}) (error) {
|
||||
err := c.apiClient.Ops.DoCollectionAction({{$.schema.CodeName}}Type, "{{$key}}", &resource.Collection, input, nil)
|
||||
return err
|
||||
{{else}}
|
||||
func (c *{{$.schema.CodeName}}Client) CollectionAction{{$key | capitalize}} (resource *{{$.schema.CodeName}}Collection, input *{{$value.Input | capitalize}}) (*{{getCollectionOutput $value.Output $.schema.CodeName}}, error) {
|
||||
resp := &{{getCollectionOutput $value.Output $.schema.CodeName}}{}
|
||||
err := c.apiClient.Ops.DoCollectionAction({{$.schema.CodeName}}Type, "{{$key}}", &resource.Collection, input, resp)
|
||||
return resp, err
|
||||
{{- end -}}
|
||||
}
|
||||
{{end}}
|
||||
{{end}}`
|
55
vendor/github.com/rancher/norman/go.mod
generated
vendored
55
vendor/github.com/rancher/norman/go.mod
generated
vendored
@@ -1,55 +0,0 @@
|
||||
module github.com/rancher/norman
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1-0.20170626231645-782f4967f2dc // indirect
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680
|
||||
github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e // indirect
|
||||
github.com/golang/glog v0.0.0-20141105023935-44145f04b68c // indirect
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 // indirect
|
||||
github.com/golang/protobuf v1.2.0 // indirect
|
||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 // indirect
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d // indirect
|
||||
github.com/gorilla/websocket v0.0.0-20150714140627-6eb6ad425a89
|
||||
github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880 // indirect
|
||||
github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c // indirect
|
||||
github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1 // indirect
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3 // indirect
|
||||
github.com/kr/pretty v0.0.0-20140812000539-f31442d60e51 // indirect
|
||||
github.com/kr/text v0.0.0-20130911015532-6807e777504f // indirect
|
||||
github.com/maruel/panicparse v1.1.1
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da // indirect
|
||||
github.com/onsi/ginkgo v1.2.1-0.20170318221715-67b9df7f55fe // indirect
|
||||
github.com/onsi/gomega v0.0.0-20160911051023-d59fa0ac68bb // indirect
|
||||
github.com/pkg/errors v0.8.0
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0 // indirect
|
||||
github.com/prometheus/client_golang v0.8.0
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e // indirect
|
||||
github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7 // indirect
|
||||
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2
|
||||
github.com/spf13/pflag v1.0.1 // indirect
|
||||
github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680
|
||||
golang.org/x/crypto v0.0.0-20170825220121-81e90905daef // indirect
|
||||
golang.org/x/net v0.0.0-20170809000501-1c05540f6879 // indirect
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f
|
||||
golang.org/x/sys v0.0.0-20171031081856-95c657629925 // indirect
|
||||
golang.org/x/text v0.0.0-20170810154203-b19bf474d317 // indirect
|
||||
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d
|
||||
golang.org/x/tools v0.0.0-20170428054726-2382e3994d48 // indirect
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect
|
||||
gopkg.in/inf.v0 v0.9.0 // indirect
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect
|
||||
gopkg.in/yaml.v2 v2.0.0-20170721113624-670d4cfef054 // indirect
|
||||
k8s.io/api v0.0.0-20180621150657-6c0bbc3e58fa
|
||||
k8s.io/apiextensions-apiserver v0.0.0-20180621165922-80db67131e8d
|
||||
k8s.io/apimachinery v0.0.0-20180619225948-e386b2658ed2
|
||||
k8s.io/client-go v2.0.0-alpha.0.0.20180621152933-b0722d92a7c1+incompatible
|
||||
k8s.io/gengo v0.0.0-20180223161844-01a732e01d00
|
||||
k8s.io/kube-openapi v0.0.0-20180509051136-39cb288412c4 // indirect
|
||||
k8s.io/kubernetes v1.10.5
|
||||
)
|
104
vendor/github.com/rancher/norman/go.sum
generated
vendored
104
vendor/github.com/rancher/norman/go.sum
generated
vendored
@@ -1,104 +0,0 @@
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/davecgh/go-spew v1.1.1-0.20170626231645-782f4967f2dc h1:NlbIJbqL8zjb55Vdrsr5uqyVC6/NoUUd2YrLojfE2zI=
|
||||
github.com/davecgh/go-spew v1.1.1-0.20170626231645-782f4967f2dc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 h1:ZktWZesgun21uEDrwW7iEV1zPCGQldM2atlJZ3TdvVM=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e h1:ago6fNuQ6IhszPsXkeU7qRCyfsIX7L67WDybsAPkLl8=
|
||||
github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20141105023935-44145f04b68c h1:CbdkBQ1/PiAo0FYJhQGwASD8wrgNvTdf01g6+O9tNuA=
|
||||
github.com/golang/glog v0.0.0-20141105023935-44145f04b68c/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/protobuf v0.0.0-20171021043952-1643683e1b54 h1:nRNJXiJvemchkOTn0V4U11TZkvacB94gTzbTZbSA7Rw=
|
||||
github.com/golang/protobuf v0.0.0-20171021043952-1643683e1b54/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 h1:ScAXWS+TR6MZKex+7Z8rneuSJH+FSDqd6ocQyl+ZHo4=
|
||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/gorilla/websocket v0.0.0-20150714140627-6eb6ad425a89 h1:f3M+RTnIGEhCF8ynRezzgqxlQ+VBfer6kL61+4/W+v4=
|
||||
github.com/gorilla/websocket v0.0.0-20150714140627-6eb6ad425a89/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880 h1:OaRuzt9oCKNui8cCskZijoKUwe+aCuuCwvx1ox8FNyw=
|
||||
github.com/hashicorp/golang-lru v0.0.0-20160207214719-a0d98a5f2880/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c h1:kQWxfPIHVLbgLzphqk3QUflDy9QdksZR4ygR807bpy0=
|
||||
github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
|
||||
github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1 h1:FeeCi0I2Fu8kA8IXrdVPtGzym+mW9bzfj9f26EaES9k=
|
||||
github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3 h1:/UewZcckqhvnnS0C6r3Sher2hSEbVmM6Ogpcjen08+Y=
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/kr/pretty v0.0.0-20140812000539-f31442d60e51 h1:kGEU5h0EzkNa+B8Q3e0GlaIocJYB1G6ZpefcceXhfgc=
|
||||
github.com/kr/pretty v0.0.0-20140812000539-f31442d60e51/go.mod h1:Bvhd+E3laJ0AVkG0c9rmtZcnhV0HQ3+c3YxxqTvc/gA=
|
||||
github.com/kr/text v0.0.0-20130911015532-6807e777504f h1:JaNmHIV9Eby6srQVWuiQ6n8ko2o/lG6udSRCbFZe1fs=
|
||||
github.com/kr/text v0.0.0-20130911015532-6807e777504f/go.mod h1:sjUstKUATFIcff4qlB53Kml0wQPtJVc/3fWrmuUmcfA=
|
||||
github.com/maruel/panicparse v1.1.1 h1:k62YPcEoLncEEpjMt92GtG5ugb8WL/510Ys3/h5IkRc=
|
||||
github.com/maruel/panicparse v1.1.1/go.mod h1:nty42YY5QByNC5MM7q/nj938VbgPU7avs45z6NClpxI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da h1:ZQGIPjr1iTtUPXZFk8WShqb5G+Qg65VHFLtSvmHh+Mw=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/onsi/ginkgo v1.2.1-0.20170318221715-67b9df7f55fe h1:d3gNxYlRvgsR9X/YxcYc0e0wsFAhC6u5zM51TC+o+EA=
|
||||
github.com/onsi/ginkgo v1.2.1-0.20170318221715-67b9df7f55fe/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v0.0.0-20160911051023-d59fa0ac68bb h1:myDTJUQm/UVMeOHuw47rGP+3Id5b0s0T7EVl71ZweuI=
|
||||
github.com/onsi/gomega v0.0.0-20160911051023-d59fa0ac68bb/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0 h1:GD+A8+e+wFkqje55/2fOVnZPkoDIu1VooBWfNrnY8Uo=
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.8.0 h1:1921Yw9Gc3iSc4VQh3PIoOqgPCZS7G/4xQNVUp8Mda8=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrOUCzh1Y3Re6aJUUWRp2M9+Oc3eVn/54=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7 h1:NgR6WN8nQ4SmFC1sSUHY8SriLuWCZ6cCIQtH4vDZN3c=
|
||||
github.com/prometheus/procfs v0.0.0-20180920065004-418d78d0b9a7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2 h1:a07zp0wovcAE2jH+wlD22JLqUH6Rdl8Aon+NiyPxE+0=
|
||||
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680 h1:oAXco1Ts88F75L1qvG3BAa4ChXI3EZDfxbB+p+y8+gE=
|
||||
github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
golang.org/x/crypto v0.0.0-20170825220121-81e90905daef h1:R8ubLIilYRXIXpgjOg2l/ECVs3HzVKIjJEhxSsQ91u4=
|
||||
golang.org/x/crypto v0.0.0-20170825220121-81e90905daef/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/net v0.0.0-20170809000501-1c05540f6879 h1:0rFa7EaCGdQPmZVbo9F7MNF65b8dyzS6EUnXjs9Cllk=
|
||||
golang.org/x/net v0.0.0-20170809000501-1c05540f6879/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20171031081856-95c657629925 h1:nCH33NboKIsT4HoXBsXTWX8ul303HxWgkc5s2Ezwacg=
|
||||
golang.org/x/sys v0.0.0-20171031081856-95c657629925/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.0.0-20170810154203-b19bf474d317 h1:WKW+OPdYPlvOTVGHuMfjnIC6yY2SI93yFB0pZ7giBmQ=
|
||||
golang.org/x/text v0.0.0-20170810154203-b19bf474d317/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d h1:TnM+PKb3ylGmZvyPXmo9m/wktg7Jn/a/fNmr33HSj8g=
|
||||
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20170428054726-2382e3994d48 h1:Al/HKLBwsMBsWhxa71LOWO8MeCbD21L+x5rHb83JHjI=
|
||||
golang.org/x/tools v0.0.0-20170428054726-2382e3994d48/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0=
|
||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
||||
gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o=
|
||||
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU=
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170721113624-670d4cfef054 h1:ROF+R/wHHruzF40n5DfPv2jwm7rCJwvs8fz+RTZWjLE=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170721113624-670d4cfef054/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
k8s.io/api v0.0.0-20180621150657-6c0bbc3e58fa h1:FdiZyyrmQXY7AWCNUfAJrx9UCjMF/oBNZP8CmKoc2aU=
|
||||
k8s.io/api v0.0.0-20180621150657-6c0bbc3e58fa/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
|
||||
k8s.io/apiextensions-apiserver v0.0.0-20180621165922-80db67131e8d h1:QYxqxjF8LG0fEp4lhpDj4zGXaO1EAbt97/3vqVL0dpk=
|
||||
k8s.io/apiextensions-apiserver v0.0.0-20180621165922-80db67131e8d/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE=
|
||||
k8s.io/apimachinery v0.0.0-20180619225948-e386b2658ed2 h1:NJEj7o7SKxpURej3uJ1QZJZCeRlRj21EatnCK65nrB4=
|
||||
k8s.io/apimachinery v0.0.0-20180619225948-e386b2658ed2/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
|
||||
k8s.io/client-go v2.0.0-alpha.0.0.20180621152933-b0722d92a7c1+incompatible h1:lph8g2o3QoQdw5W+fKHD/+Td4MEN2dmXgAjoOH5aISo=
|
||||
k8s.io/client-go v2.0.0-alpha.0.0.20180621152933-b0722d92a7c1+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
|
||||
k8s.io/gengo v0.0.0-20180223161844-01a732e01d00 h1:vt4Sh/+HFnLoTScgFLNoMjNqOg0sQgAzViarcz+UX3Q=
|
||||
k8s.io/gengo v0.0.0-20180223161844-01a732e01d00/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/kube-openapi v0.0.0-20180509051136-39cb288412c4 h1:gW+EUB2I96nbxVenV/8ctfbACsHP+yxlT2dhMCsiy+s=
|
||||
k8s.io/kube-openapi v0.0.0-20180509051136-39cb288412c4/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
|
||||
k8s.io/kubernetes v1.10.5 h1:buoMLO5r3BpYzUebBdwxa67P2evcpmaydiiKMLq9K1U=
|
||||
k8s.io/kubernetes v1.10.5/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
114
vendor/github.com/rancher/norman/httperror/error.go
generated
vendored
114
vendor/github.com/rancher/norman/httperror/error.go
generated
vendored
@@ -1,114 +0,0 @@
|
||||
package httperror
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
Unauthorized = ErrorCode{"Unauthorized", 401}
|
||||
PermissionDenied = ErrorCode{"PermissionDenied", 403}
|
||||
NotFound = ErrorCode{"NotFound", 404}
|
||||
MethodNotAllowed = ErrorCode{"MethodNotAllow", 405}
|
||||
Conflict = ErrorCode{"Conflict", 409}
|
||||
|
||||
InvalidDateFormat = ErrorCode{"InvalidDateFormat", 422}
|
||||
InvalidFormat = ErrorCode{"InvalidFormat", 422}
|
||||
InvalidReference = ErrorCode{"InvalidReference", 422}
|
||||
NotNullable = ErrorCode{"NotNullable", 422}
|
||||
NotUnique = ErrorCode{"NotUnique", 422}
|
||||
MinLimitExceeded = ErrorCode{"MinLimitExceeded", 422}
|
||||
MaxLimitExceeded = ErrorCode{"MaxLimitExceeded", 422}
|
||||
MinLengthExceeded = ErrorCode{"MinLengthExceeded", 422}
|
||||
MaxLengthExceeded = ErrorCode{"MaxLengthExceeded", 422}
|
||||
InvalidOption = ErrorCode{"InvalidOption", 422}
|
||||
InvalidCharacters = ErrorCode{"InvalidCharacters", 422}
|
||||
MissingRequired = ErrorCode{"MissingRequired", 422}
|
||||
InvalidCSRFToken = ErrorCode{"InvalidCSRFToken", 422}
|
||||
InvalidAction = ErrorCode{"InvalidAction", 422}
|
||||
InvalidBodyContent = ErrorCode{"InvalidBodyContent", 422}
|
||||
InvalidType = ErrorCode{"InvalidType", 422}
|
||||
ActionNotAvailable = ErrorCode{"ActionNotAvailable", 404}
|
||||
InvalidState = ErrorCode{"InvalidState", 422}
|
||||
|
||||
ServerError = ErrorCode{"ServerError", 500}
|
||||
ClusterUnavailable = ErrorCode{"ClusterUnavailable", 503}
|
||||
)
|
||||
|
||||
type ErrorCode struct {
|
||||
Code string
|
||||
Status int
|
||||
}
|
||||
|
||||
func (e ErrorCode) String() string {
|
||||
return fmt.Sprintf("%s %d", e.Code, e.Status)
|
||||
}
|
||||
|
||||
type APIError struct {
|
||||
Code ErrorCode
|
||||
Message string
|
||||
Cause error
|
||||
FieldName string
|
||||
}
|
||||
|
||||
func NewAPIErrorLong(status int, code, message string) error {
|
||||
return NewAPIError(ErrorCode{
|
||||
Code: code,
|
||||
Status: status,
|
||||
}, message)
|
||||
}
|
||||
|
||||
func NewAPIError(code ErrorCode, message string) error {
|
||||
return &APIError{
|
||||
Code: code,
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
|
||||
func NewFieldAPIError(code ErrorCode, fieldName, message string) error {
|
||||
return &APIError{
|
||||
Code: code,
|
||||
Message: message,
|
||||
FieldName: fieldName,
|
||||
}
|
||||
}
|
||||
|
||||
// WrapFieldAPIError will cause the API framework to log the underlying err before returning the APIError as a response.
|
||||
// err WILL NOT be in the API response
|
||||
func WrapFieldAPIError(err error, code ErrorCode, fieldName, message string) error {
|
||||
return &APIError{
|
||||
Cause: err,
|
||||
Code: code,
|
||||
Message: message,
|
||||
FieldName: fieldName,
|
||||
}
|
||||
}
|
||||
|
||||
// WrapAPIError will cause the API framework to log the underlying err before returning the APIError as a response.
|
||||
// err WILL NOT be in the API response
|
||||
func WrapAPIError(err error, code ErrorCode, message string) error {
|
||||
return &APIError{
|
||||
Code: code,
|
||||
Message: message,
|
||||
Cause: err,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *APIError) Error() string {
|
||||
if a.FieldName != "" {
|
||||
return fmt.Sprintf("%s=%s: %s", a.FieldName, a.Code, a.Message)
|
||||
}
|
||||
return fmt.Sprintf("%s: %s", a.Code, a.Message)
|
||||
}
|
||||
|
||||
func IsAPIError(err error) bool {
|
||||
_, ok := err.(*APIError)
|
||||
return ok
|
||||
}
|
||||
|
||||
func IsConflict(err error) bool {
|
||||
if apiError, ok := err.(*APIError); ok {
|
||||
return apiError.Code.Status == 409
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
47
vendor/github.com/rancher/norman/httperror/handler/handler.go
generated
vendored
47
vendor/github.com/rancher/norman/httperror/handler/handler.go
generated
vendored
@@ -1,47 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func ErrorHandler(request *types.APIContext, err error) {
|
||||
var error *httperror.APIError
|
||||
if apiError, ok := err.(*httperror.APIError); ok {
|
||||
if apiError.Cause != nil {
|
||||
url, _ := url.PathUnescape(request.Request.URL.String())
|
||||
if url == "" {
|
||||
url = request.Request.URL.String()
|
||||
}
|
||||
logrus.Errorf("API error response %v for %v %v. Cause: %v", apiError.Code.Status, request.Request.Method,
|
||||
url, apiError.Cause)
|
||||
}
|
||||
error = apiError
|
||||
} else {
|
||||
logrus.Errorf("Unknown error: %v", err)
|
||||
error = &httperror.APIError{
|
||||
Code: httperror.ServerError,
|
||||
Message: err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
data := toError(error)
|
||||
request.WriteResponse(error.Code.Status, data)
|
||||
}
|
||||
|
||||
func toError(apiError *httperror.APIError) map[string]interface{} {
|
||||
e := map[string]interface{}{
|
||||
"type": "/meta/schemas/error",
|
||||
"status": apiError.Code.Status,
|
||||
"code": apiError.Code.Code,
|
||||
"message": apiError.Message,
|
||||
}
|
||||
if apiError.FieldName != "" {
|
||||
e["fieldName"] = apiError.FieldName
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
77
vendor/github.com/rancher/norman/leader/leader.go
generated
vendored
77
vendor/github.com/rancher/norman/leader/leader.go
generated
vendored
@@ -1,77 +0,0 @@
|
||||
package leader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/client-go/tools/leaderelection"
|
||||
"k8s.io/client-go/tools/leaderelection/resourcelock"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/client/leaderelectionconfig"
|
||||
)
|
||||
|
||||
type Callback func(cb context.Context)
|
||||
|
||||
func RunOrDie(ctx context.Context, name string, client kubernetes.Interface, cb Callback) {
|
||||
err := run(ctx, name, client, cb)
|
||||
if err != nil {
|
||||
logrus.Fatalf("Failed to start leader election for %s", name)
|
||||
}
|
||||
panic("Failed to start leader election for " + name)
|
||||
}
|
||||
|
||||
func run(ctx context.Context, name string, client kubernetes.Interface, cb Callback) error {
|
||||
id, err := os.Hostname()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
le := leaderelectionconfig.DefaultLeaderElectionConfiguration()
|
||||
le.LeaderElect = true
|
||||
le.ResourceLock = resourcelock.ConfigMapsResourceLock
|
||||
|
||||
recorder := createRecorder(name, client)
|
||||
|
||||
rl, err := resourcelock.New(le.ResourceLock,
|
||||
"kube-system",
|
||||
name,
|
||||
client.CoreV1(),
|
||||
resourcelock.ResourceLockConfig{
|
||||
Identity: id,
|
||||
EventRecorder: recorder,
|
||||
})
|
||||
if err != nil {
|
||||
logrus.Fatalf("error creating leader lock for %s: %v", name, err)
|
||||
}
|
||||
|
||||
leaderelection.RunOrDie(leaderelection.LeaderElectionConfig{
|
||||
Lock: rl,
|
||||
LeaseDuration: le.LeaseDuration.Duration,
|
||||
RenewDeadline: le.RenewDeadline.Duration,
|
||||
RetryPeriod: le.RetryPeriod.Duration,
|
||||
Callbacks: leaderelection.LeaderCallbacks{
|
||||
OnStartedLeading: func(stop <-chan struct{}) {
|
||||
subCtx, cancel := context.WithCancel(ctx)
|
||||
go cb(subCtx)
|
||||
<-stop
|
||||
cancel()
|
||||
},
|
||||
OnStoppedLeading: func() {
|
||||
logrus.Fatalf("leaderelection lost for %s", name)
|
||||
},
|
||||
},
|
||||
})
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func createRecorder(name string, kubeClient kubernetes.Interface) record.EventRecorder {
|
||||
eventBroadcaster := record.NewBroadcaster()
|
||||
eventBroadcaster.StartLogging(logrus.Debugf)
|
||||
eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: v1core.New(kubeClient.CoreV1().RESTClient()).Events("")})
|
||||
return eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: name})
|
||||
}
|
195
vendor/github.com/rancher/norman/lifecycle/object.go
generated
vendored
195
vendor/github.com/rancher/norman/lifecycle/object.go
generated
vendored
@@ -1,195 +0,0 @@
|
||||
package lifecycle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/rancher/norman/objectclient"
|
||||
"github.com/rancher/norman/types/slice"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
created = "lifecycle.cattle.io/create"
|
||||
finalizerKey = "controller.cattle.io/"
|
||||
ScopedFinalizerKey = "clusterscoped.controller.cattle.io/"
|
||||
)
|
||||
|
||||
type ObjectLifecycle interface {
|
||||
Create(obj runtime.Object) (runtime.Object, error)
|
||||
Finalize(obj runtime.Object) (runtime.Object, error)
|
||||
Updated(obj runtime.Object) (runtime.Object, error)
|
||||
}
|
||||
|
||||
type objectLifecycleAdapter struct {
|
||||
name string
|
||||
clusterScoped bool
|
||||
lifecycle ObjectLifecycle
|
||||
objectClient *objectclient.ObjectClient
|
||||
}
|
||||
|
||||
func NewObjectLifecycleAdapter(name string, clusterScoped bool, lifecycle ObjectLifecycle, objectClient *objectclient.ObjectClient) func(key string, obj runtime.Object) error {
|
||||
o := objectLifecycleAdapter{
|
||||
name: name,
|
||||
clusterScoped: clusterScoped,
|
||||
lifecycle: lifecycle,
|
||||
objectClient: objectClient,
|
||||
}
|
||||
return o.sync
|
||||
}
|
||||
|
||||
func (o *objectLifecycleAdapter) sync(key string, obj runtime.Object) error {
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
metadata, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cont, err := o.finalize(metadata, obj); err != nil || !cont {
|
||||
return err
|
||||
}
|
||||
|
||||
if cont, err := o.create(metadata, obj); err != nil || !cont {
|
||||
return err
|
||||
}
|
||||
|
||||
copyObj := obj.DeepCopyObject()
|
||||
newObj, err := o.lifecycle.Updated(copyObj)
|
||||
if newObj != nil {
|
||||
o.update(metadata.GetName(), obj, newObj)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *objectLifecycleAdapter) update(name string, orig, obj runtime.Object) (runtime.Object, error) {
|
||||
if obj != nil && !reflect.DeepEqual(orig, obj) {
|
||||
return o.objectClient.Update(name, obj)
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func (o *objectLifecycleAdapter) finalize(metadata metav1.Object, obj runtime.Object) (bool, error) {
|
||||
// Check finalize
|
||||
if metadata.GetDeletionTimestamp() == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if !slice.ContainsString(metadata.GetFinalizers(), o.constructFinalizerKey()) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
copyObj := obj.DeepCopyObject()
|
||||
if newObj, err := o.lifecycle.Finalize(copyObj); err != nil {
|
||||
if newObj != nil {
|
||||
o.update(metadata.GetName(), obj, newObj)
|
||||
}
|
||||
return false, err
|
||||
} else if newObj != nil {
|
||||
copyObj = newObj
|
||||
}
|
||||
|
||||
return false, o.removeFinalizer(o.constructFinalizerKey(), copyObj)
|
||||
}
|
||||
|
||||
func (o *objectLifecycleAdapter) removeFinalizer(name string, obj runtime.Object) error {
|
||||
for i := 0; i < 3; i++ {
|
||||
metadata, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var finalizers []string
|
||||
for _, finalizer := range metadata.GetFinalizers() {
|
||||
if finalizer == name {
|
||||
continue
|
||||
}
|
||||
finalizers = append(finalizers, finalizer)
|
||||
}
|
||||
metadata.SetFinalizers(finalizers)
|
||||
|
||||
_, err = o.objectClient.Update(metadata.GetName(), obj)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
obj, err = o.objectClient.GetNamespaced(metadata.GetNamespace(), metadata.GetName(), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to remove finalizer on %s", name)
|
||||
}
|
||||
|
||||
func (o *objectLifecycleAdapter) createKey() string {
|
||||
return created + "." + o.name
|
||||
}
|
||||
|
||||
func (o *objectLifecycleAdapter) constructFinalizerKey() string {
|
||||
if o.clusterScoped {
|
||||
return ScopedFinalizerKey + o.name
|
||||
}
|
||||
return finalizerKey + o.name
|
||||
}
|
||||
|
||||
func (o *objectLifecycleAdapter) create(metadata metav1.Object, obj runtime.Object) (bool, error) {
|
||||
if o.isInitialized(metadata) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
copyObj := obj.DeepCopyObject()
|
||||
copyObj, err := o.addFinalizer(copyObj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if newObj, err := o.lifecycle.Create(copyObj); err != nil {
|
||||
o.update(metadata.GetName(), obj, newObj)
|
||||
return false, err
|
||||
} else if newObj != nil {
|
||||
copyObj = newObj
|
||||
}
|
||||
|
||||
return false, o.setInitialized(copyObj)
|
||||
}
|
||||
|
||||
func (o *objectLifecycleAdapter) isInitialized(metadata metav1.Object) bool {
|
||||
initialized := o.createKey()
|
||||
return metadata.GetAnnotations()[initialized] == "true"
|
||||
}
|
||||
|
||||
func (o *objectLifecycleAdapter) setInitialized(obj runtime.Object) error {
|
||||
metadata, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
initialized := o.createKey()
|
||||
|
||||
if metadata.GetAnnotations() == nil {
|
||||
metadata.SetAnnotations(map[string]string{})
|
||||
}
|
||||
metadata.GetAnnotations()[initialized] = "true"
|
||||
|
||||
_, err = o.objectClient.Update(metadata.GetName(), obj)
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *objectLifecycleAdapter) addFinalizer(obj runtime.Object) (runtime.Object, error) {
|
||||
metadata, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if slice.ContainsString(metadata.GetFinalizers(), o.constructFinalizerKey()) {
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
metadata.SetFinalizers(append(metadata.GetFinalizers(), o.constructFinalizerKey()))
|
||||
return o.objectClient.Update(metadata.GetName(), obj)
|
||||
}
|
58
vendor/github.com/rancher/norman/metrics/generic_controller.go
generated
vendored
58
vendor/github.com/rancher/norman/metrics/generic_controller.go
generated
vendored
@@ -1,58 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const MetricsGenericControllerEnv = "NORMAN_GENERIC_CONTROLLER_METRICS"
|
||||
|
||||
var (
|
||||
genericControllerMetrics = false
|
||||
TotalHandlerExecution = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Subsystem: "norman_generic_controller",
|
||||
Name: "total_handler_execution",
|
||||
Help: "Total Count of executing handler",
|
||||
},
|
||||
[]string{"name", "handlerName"},
|
||||
)
|
||||
|
||||
TotalHandlerFailure = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Subsystem: "norman_generic_controller",
|
||||
Name: "total_handler_failure",
|
||||
Help: "Total Count of handler failure",
|
||||
},
|
||||
[]string{"name", "handlerName", "key"},
|
||||
)
|
||||
)
|
||||
|
||||
func init() {
|
||||
if os.Getenv(MetricsGenericControllerEnv) == "true" {
|
||||
genericControllerMetrics = true
|
||||
}
|
||||
}
|
||||
|
||||
func IncTotalHandlerExecution(controllerName, handlerName string) {
|
||||
if genericControllerMetrics {
|
||||
TotalHandlerExecution.With(
|
||||
prometheus.Labels{
|
||||
"name": controllerName,
|
||||
"handlerName": handlerName},
|
||||
).Inc()
|
||||
}
|
||||
}
|
||||
|
||||
func IncTotalHandlerFailure(controllerName, handlerName, key string) {
|
||||
if genericControllerMetrics {
|
||||
TotalHandlerFailure.With(
|
||||
prometheus.Labels{
|
||||
"name": controllerName,
|
||||
"handlerName": handlerName,
|
||||
"key": key,
|
||||
},
|
||||
).Inc()
|
||||
}
|
||||
}
|
11
vendor/github.com/rancher/norman/metrics/register/generic_controller.go
generated
vendored
11
vendor/github.com/rancher/norman/metrics/register/generic_controller.go
generated
vendored
@@ -1,11 +0,0 @@
|
||||
package register
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/rancher/norman/metrics"
|
||||
)
|
||||
|
||||
func init() {
|
||||
prometheus.MustRegister(metrics.TotalHandlerExecution)
|
||||
prometheus.MustRegister(metrics.TotalHandlerFailure)
|
||||
}
|
27
vendor/github.com/rancher/norman/name/name.go
generated
vendored
27
vendor/github.com/rancher/norman/name/name.go
generated
vendored
@@ -1,27 +0,0 @@
|
||||
package name
|
||||
|
||||
import "strings"
|
||||
|
||||
func GuessPluralName(name string) string {
|
||||
if name == "" {
|
||||
return name
|
||||
}
|
||||
|
||||
if strings.EqualFold(name, "Endpoints") {
|
||||
return name
|
||||
}
|
||||
|
||||
if suffix(name, "s") || suffix(name, "ch") || suffix(name, "x") {
|
||||
return name + "es"
|
||||
}
|
||||
|
||||
if suffix(name, "y") && len(name) > 2 && !strings.ContainsAny(name[len(name)-2:len(name)-1], "[aeiou]") {
|
||||
return name[0:len(name)-1] + "ies"
|
||||
}
|
||||
|
||||
return name + "s"
|
||||
}
|
||||
|
||||
func suffix(str, end string) bool {
|
||||
return strings.HasSuffix(str, end)
|
||||
}
|
58
vendor/github.com/rancher/norman/objectclient/dynamic/content.go
generated
vendored
58
vendor/github.com/rancher/norman/objectclient/dynamic/content.go
generated
vendored
@@ -1,58 +0,0 @@
|
||||
package dynamic
|
||||
|
||||
import (
|
||||
ejson "encoding/json"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
NegotiatedSerializer = negotiatedSerializer{}
|
||||
)
|
||||
|
||||
type negotiatedSerializer struct{}
|
||||
|
||||
func (s negotiatedSerializer) SupportedMediaTypes() []runtime.SerializerInfo {
|
||||
return []runtime.SerializerInfo{
|
||||
{
|
||||
MediaType: "application/json",
|
||||
EncodesAsText: true,
|
||||
Serializer: dynamicCodec{
|
||||
Encoder: unstructured.UnstructuredJSONScheme,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s negotiatedSerializer) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
|
||||
return encoder
|
||||
}
|
||||
|
||||
func (s negotiatedSerializer) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
|
||||
return decoder
|
||||
}
|
||||
|
||||
type dynamicCodec struct {
|
||||
runtime.Encoder
|
||||
}
|
||||
|
||||
func (dynamicCodec) Decode(data []byte, gvk *schema.GroupVersionKind, obj runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
|
||||
obj, gvk, err := unstructured.UnstructuredJSONScheme.Decode(data, gvk, obj)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if _, ok := obj.(*metav1.Status); !ok && strings.ToLower(gvk.Kind) == "status" {
|
||||
obj = &metav1.Status{}
|
||||
err := ejson.Unmarshal(data, obj)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return obj, gvk, nil
|
||||
}
|
310
vendor/github.com/rancher/norman/objectclient/object_client.go
generated
vendored
310
vendor/github.com/rancher/norman/objectclient/object_client.go
generated
vendored
@@ -1,310 +0,0 @@
|
||||
package objectclient
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rancher/norman/restwatch"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
json2 "k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/rest"
|
||||
restclientwatch "k8s.io/client-go/rest/watch"
|
||||
)
|
||||
|
||||
type ObjectFactory interface {
|
||||
Object() runtime.Object
|
||||
List() runtime.Object
|
||||
}
|
||||
|
||||
type UnstructuredObjectFactory struct {
|
||||
}
|
||||
|
||||
func (u *UnstructuredObjectFactory) Object() runtime.Object {
|
||||
return &unstructured.Unstructured{}
|
||||
}
|
||||
|
||||
func (u *UnstructuredObjectFactory) List() runtime.Object {
|
||||
return &unstructured.UnstructuredList{}
|
||||
}
|
||||
|
||||
type GenericClient interface {
|
||||
UnstructuredClient() GenericClient
|
||||
GroupVersionKind() schema.GroupVersionKind
|
||||
Create(o runtime.Object) (runtime.Object, error)
|
||||
GetNamespaced(namespace, name string, opts metav1.GetOptions) (runtime.Object, error)
|
||||
Get(name string, opts metav1.GetOptions) (runtime.Object, error)
|
||||
Update(name string, o runtime.Object) (runtime.Object, error)
|
||||
DeleteNamespaced(namespace, name string, opts *metav1.DeleteOptions) error
|
||||
Delete(name string, opts *metav1.DeleteOptions) error
|
||||
List(opts metav1.ListOptions) (runtime.Object, error)
|
||||
Watch(opts metav1.ListOptions) (watch.Interface, error)
|
||||
DeleteCollection(deleteOptions *metav1.DeleteOptions, listOptions metav1.ListOptions) error
|
||||
Patch(name string, o runtime.Object, data []byte, subresources ...string) (runtime.Object, error)
|
||||
ObjectFactory() ObjectFactory
|
||||
}
|
||||
|
||||
type ObjectClient struct {
|
||||
restClient rest.Interface
|
||||
resource *metav1.APIResource
|
||||
gvk schema.GroupVersionKind
|
||||
ns string
|
||||
Factory ObjectFactory
|
||||
}
|
||||
|
||||
func NewObjectClient(namespace string, restClient rest.Interface, apiResource *metav1.APIResource, gvk schema.GroupVersionKind, factory ObjectFactory) *ObjectClient {
|
||||
return &ObjectClient{
|
||||
restClient: restClient,
|
||||
resource: apiResource,
|
||||
gvk: gvk,
|
||||
ns: namespace,
|
||||
Factory: factory,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ObjectClient) UnstructuredClient() GenericClient {
|
||||
return &ObjectClient{
|
||||
restClient: p.restClient,
|
||||
resource: p.resource,
|
||||
gvk: p.gvk,
|
||||
ns: p.ns,
|
||||
Factory: &UnstructuredObjectFactory{},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ObjectClient) GroupVersionKind() schema.GroupVersionKind {
|
||||
return p.gvk
|
||||
}
|
||||
|
||||
func (p *ObjectClient) getAPIPrefix() string {
|
||||
if p.gvk.Group == "" {
|
||||
return "api"
|
||||
}
|
||||
return "apis"
|
||||
}
|
||||
|
||||
func (p *ObjectClient) Create(o runtime.Object) (runtime.Object, error) {
|
||||
ns := p.ns
|
||||
obj, ok := o.(metav1.Object)
|
||||
if ok && obj.GetNamespace() != "" {
|
||||
ns = obj.GetNamespace()
|
||||
}
|
||||
|
||||
if ok {
|
||||
labels := obj.GetLabels()
|
||||
if labels == nil {
|
||||
labels = make(map[string]string)
|
||||
}
|
||||
labels["cattle.io/creator"] = "norman"
|
||||
obj.SetLabels(labels)
|
||||
}
|
||||
|
||||
if t, err := meta.TypeAccessor(o); err == nil {
|
||||
if t.GetKind() == "" {
|
||||
t.SetKind(p.gvk.Kind)
|
||||
}
|
||||
if t.GetAPIVersion() == "" {
|
||||
apiVersion, _ := p.gvk.ToAPIVersionAndKind()
|
||||
t.SetAPIVersion(apiVersion)
|
||||
}
|
||||
}
|
||||
result := p.Factory.Object()
|
||||
logrus.Debugf("REST CREATE %s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, ns, p.resource.Name)
|
||||
err := p.restClient.Post().
|
||||
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
|
||||
NamespaceIfScoped(ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
Body(o).
|
||||
Do().
|
||||
Into(result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (p *ObjectClient) GetNamespaced(namespace, name string, opts metav1.GetOptions) (runtime.Object, error) {
|
||||
result := p.Factory.Object()
|
||||
req := p.restClient.Get().
|
||||
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version)
|
||||
if namespace != "" {
|
||||
req = req.Namespace(namespace)
|
||||
}
|
||||
err := req.
|
||||
Resource(p.resource.Name).
|
||||
VersionedParams(&opts, metav1.ParameterCodec).
|
||||
Name(name).
|
||||
Do().
|
||||
Into(result)
|
||||
logrus.Debugf("REST GET %s/%s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, namespace, p.resource.Name, name)
|
||||
return result, err
|
||||
|
||||
}
|
||||
|
||||
func (p *ObjectClient) Get(name string, opts metav1.GetOptions) (runtime.Object, error) {
|
||||
result := p.Factory.Object()
|
||||
err := p.restClient.Get().
|
||||
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
|
||||
NamespaceIfScoped(p.ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
VersionedParams(&opts, metav1.ParameterCodec).
|
||||
Name(name).
|
||||
Do().
|
||||
Into(result)
|
||||
logrus.Debugf("REST GET %s/%s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, p.ns, p.resource.Name, name)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (p *ObjectClient) Update(name string, o runtime.Object) (runtime.Object, error) {
|
||||
ns := p.ns
|
||||
if obj, ok := o.(metav1.Object); ok && obj.GetNamespace() != "" {
|
||||
ns = obj.GetNamespace()
|
||||
}
|
||||
result := p.Factory.Object()
|
||||
if len(name) == 0 {
|
||||
return result, errors.New("object missing name")
|
||||
}
|
||||
logrus.Debugf("REST UPDATE %s/%s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, ns, p.resource.Name, name)
|
||||
err := p.restClient.Put().
|
||||
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
|
||||
NamespaceIfScoped(ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
Name(name).
|
||||
Body(o).
|
||||
Do().
|
||||
Into(result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (p *ObjectClient) DeleteNamespaced(namespace, name string, opts *metav1.DeleteOptions) error {
|
||||
req := p.restClient.Delete().
|
||||
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version)
|
||||
if namespace != "" {
|
||||
req = req.Namespace(namespace)
|
||||
}
|
||||
logrus.Debugf("REST DELETE %s/%s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, namespace, p.resource.Name, name)
|
||||
return req.Resource(p.resource.Name).
|
||||
Name(name).
|
||||
Body(opts).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
func (p *ObjectClient) Delete(name string, opts *metav1.DeleteOptions) error {
|
||||
logrus.Debugf("REST DELETE %s/%s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, p.ns, p.resource.Name, name)
|
||||
return p.restClient.Delete().
|
||||
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
|
||||
NamespaceIfScoped(p.ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
Name(name).
|
||||
Body(opts).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
func (p *ObjectClient) List(opts metav1.ListOptions) (runtime.Object, error) {
|
||||
result := p.Factory.List()
|
||||
logrus.Debugf("REST LIST %s/%s/%s/%s/%s", p.getAPIPrefix(), p.gvk.Group, p.gvk.Version, p.ns, p.resource.Name)
|
||||
return result, p.restClient.Get().
|
||||
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
|
||||
NamespaceIfScoped(p.ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
VersionedParams(&opts, metav1.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
}
|
||||
|
||||
func (p *ObjectClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
restClient := p.restClient
|
||||
if watchClient, ok := restClient.(restwatch.WatchClient); ok {
|
||||
restClient = watchClient.WatchClient()
|
||||
}
|
||||
|
||||
r, err := restClient.Get().
|
||||
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
|
||||
Prefix("watch").
|
||||
NamespaceIfScoped(p.ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
VersionedParams(&opts, metav1.ParameterCodec).
|
||||
Stream()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
embeddedDecoder := &structuredDecoder{
|
||||
factory: p.Factory,
|
||||
}
|
||||
streamDecoder := streaming.NewDecoder(json2.Framer.NewFrameReader(r), embeddedDecoder)
|
||||
decoder := restclientwatch.NewDecoder(streamDecoder, embeddedDecoder)
|
||||
return watch.NewStreamWatcher(decoder), nil
|
||||
}
|
||||
|
||||
type structuredDecoder struct {
|
||||
factory ObjectFactory
|
||||
}
|
||||
|
||||
func (d *structuredDecoder) Decode(data []byte, defaults *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
|
||||
if into == nil {
|
||||
into = d.factory.Object()
|
||||
}
|
||||
|
||||
err := json.Unmarshal(data, &into)
|
||||
if err != nil {
|
||||
status := &metav1.Status{}
|
||||
if err := json.Unmarshal(data, status); err == nil && strings.ToLower(status.Kind) == "status" {
|
||||
return status, defaults, nil
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if _, ok := into.(*metav1.Status); !ok && strings.ToLower(into.GetObjectKind().GroupVersionKind().Kind) == "status" {
|
||||
into = &metav1.Status{}
|
||||
err := json.Unmarshal(data, into)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return into, defaults, err
|
||||
}
|
||||
|
||||
func (p *ObjectClient) DeleteCollection(deleteOptions *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
|
||||
return p.restClient.Delete().
|
||||
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
|
||||
NamespaceIfScoped(p.ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
VersionedParams(&listOptions, metav1.ParameterCodec).
|
||||
Body(deleteOptions).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
func (p *ObjectClient) Patch(name string, o runtime.Object, data []byte, subresources ...string) (runtime.Object, error) {
|
||||
ns := p.ns
|
||||
if obj, ok := o.(metav1.Object); ok && obj.GetNamespace() != "" {
|
||||
ns = obj.GetNamespace()
|
||||
}
|
||||
result := p.Factory.Object()
|
||||
if len(name) == 0 {
|
||||
return result, errors.New("object missing name")
|
||||
}
|
||||
err := p.restClient.Patch(types.StrategicMergePatchType).
|
||||
Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version).
|
||||
NamespaceIfScoped(ns, p.resource.Namespaced).
|
||||
Resource(p.resource.Name).
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (p *ObjectClient) ObjectFactory() ObjectFactory {
|
||||
return p.Factory
|
||||
}
|
18
vendor/github.com/rancher/norman/parse/browser.go
generated
vendored
18
vendor/github.com/rancher/norman/parse/browser.go
generated
vendored
@@ -1,18 +0,0 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func IsBrowser(req *http.Request, checkAccepts bool) bool {
|
||||
accepts := strings.ToLower(req.Header.Get("Accept"))
|
||||
userAgent := strings.ToLower(req.Header.Get("User-Agent"))
|
||||
|
||||
if accepts == "" || !checkAccepts {
|
||||
accepts = "*/*"
|
||||
}
|
||||
|
||||
// User agent has Mozilla and browser accepts */*
|
||||
return strings.Contains(userAgent, "mozilla") && strings.Contains(accepts, "*/*")
|
||||
}
|
500
vendor/github.com/rancher/norman/parse/builder/builder.go
generated
vendored
500
vendor/github.com/rancher/norman/parse/builder/builder.go
generated
vendored
@@ -1,500 +0,0 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
"github.com/rancher/norman/types/definition"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
)
|
||||
|
||||
var (
|
||||
Create = Operation("create")
|
||||
Update = Operation("update")
|
||||
Action = Operation("action")
|
||||
List = Operation("list")
|
||||
ListForCreate = Operation("listcreate")
|
||||
ErrComplexType = errors.New("complex type")
|
||||
)
|
||||
|
||||
type Operation string
|
||||
|
||||
func (o Operation) IsList() bool {
|
||||
return strings.HasPrefix(string(o), "list")
|
||||
}
|
||||
|
||||
type Builder struct {
|
||||
apiContext *types.APIContext
|
||||
Version *types.APIVersion
|
||||
Schemas *types.Schemas
|
||||
RefValidator types.ReferenceValidator
|
||||
edit bool
|
||||
export bool
|
||||
yaml bool
|
||||
}
|
||||
|
||||
func NewBuilder(apiRequest *types.APIContext) *Builder {
|
||||
return &Builder{
|
||||
apiContext: apiRequest,
|
||||
yaml: apiRequest.ResponseFormat == "yaml",
|
||||
edit: apiRequest.Option("edit") == "true",
|
||||
export: apiRequest.Option("export") == "true",
|
||||
Version: apiRequest.Version,
|
||||
Schemas: apiRequest.Schemas,
|
||||
RefValidator: apiRequest.ReferenceValidator,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Builder) Construct(schema *types.Schema, input map[string]interface{}, op Operation) (map[string]interface{}, error) {
|
||||
result, err := b.copyFields(schema, input, op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if (op == Create || op == Update) && schema.Validator != nil {
|
||||
if err := schema.Validator(b.apiContext, schema, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (b *Builder) copyInputs(schema *types.Schema, input map[string]interface{}, op Operation, result map[string]interface{}) error {
|
||||
for fieldName, value := range input {
|
||||
field, ok := schema.ResourceFields[fieldName]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if !fieldMatchesOp(field, op) {
|
||||
continue
|
||||
}
|
||||
|
||||
wasNull := value == nil && (field.Nullable || field.Default == nil)
|
||||
value, err := b.convert(field.Type, value, op)
|
||||
if err != nil {
|
||||
return httperror.WrapFieldAPIError(err, httperror.InvalidFormat, fieldName, err.Error())
|
||||
}
|
||||
|
||||
if value != nil || wasNull {
|
||||
if !op.IsList() {
|
||||
if slice, ok := value.([]interface{}); ok {
|
||||
for _, sliceValue := range slice {
|
||||
if sliceValue == nil {
|
||||
return httperror.NewFieldAPIError(httperror.NotNullable, fieldName, "Individual array values can not be null")
|
||||
}
|
||||
if err := CheckFieldCriteria(fieldName, field, sliceValue); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := CheckFieldCriteria(fieldName, field, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
result[fieldName] = value
|
||||
|
||||
if op.IsList() && field.Type == "date" && value != "" && !b.edit {
|
||||
ts, err := convert.ToTimestamp(value)
|
||||
if err == nil {
|
||||
result[fieldName+"TS"] = ts
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if op.IsList() && !b.edit && !b.export {
|
||||
if !convert.IsAPIObjectEmpty(input["type"]) {
|
||||
result["type"] = input["type"]
|
||||
}
|
||||
if !convert.IsAPIObjectEmpty(input["id"]) {
|
||||
result["id"] = input["id"]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) checkDefaultAndRequired(schema *types.Schema, input map[string]interface{}, op Operation, result map[string]interface{}) error {
|
||||
for fieldName, field := range schema.ResourceFields {
|
||||
val, hasKey := result[fieldName]
|
||||
if op == Create && (!hasKey || val == "") && field.Default != nil {
|
||||
result[fieldName] = field.Default
|
||||
}
|
||||
|
||||
_, hasKey = result[fieldName]
|
||||
if op == Create && fieldMatchesOp(field, Create) && field.Required {
|
||||
if !hasKey {
|
||||
return httperror.NewFieldAPIError(httperror.MissingRequired, fieldName, "")
|
||||
}
|
||||
|
||||
if definition.IsArrayType(field.Type) {
|
||||
slice, err := b.convertArray(field.Type, result[fieldName], op)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(slice) == 0 {
|
||||
return httperror.NewFieldAPIError(httperror.MissingRequired, fieldName, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if op.IsList() && fieldMatchesOp(field, List) && definition.IsReferenceType(field.Type) && !hasKey {
|
||||
result[fieldName] = nil
|
||||
} else if op.IsList() && fieldMatchesOp(field, List) && !hasKey && field.Default != nil {
|
||||
result[fieldName] = field.Default
|
||||
}
|
||||
}
|
||||
|
||||
if op.IsList() && b.edit {
|
||||
b.populateMissingFieldsForEdit(schema, result)
|
||||
}
|
||||
|
||||
if op.IsList() && b.export {
|
||||
b.dropDefaultsAndReadOnly(schema, result)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) dropDefaultsAndReadOnly(schema *types.Schema, result map[string]interface{}) {
|
||||
for name, existingVal := range result {
|
||||
field, ok := schema.ResourceFields[name]
|
||||
if !ok {
|
||||
delete(result, name)
|
||||
}
|
||||
|
||||
if !field.Create {
|
||||
delete(result, name)
|
||||
continue
|
||||
}
|
||||
|
||||
if field.Default == existingVal {
|
||||
delete(result, name)
|
||||
continue
|
||||
}
|
||||
|
||||
val, err := b.convert(field.Type, nil, List)
|
||||
if err == nil && val == existingVal {
|
||||
delete(result, name)
|
||||
continue
|
||||
}
|
||||
|
||||
if convert.IsAPIObjectEmpty(existingVal) {
|
||||
delete(result, name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Builder) populateMissingFieldsForEdit(schema *types.Schema, result map[string]interface{}) {
|
||||
for name, field := range schema.ResourceFields {
|
||||
if !field.Update {
|
||||
if name != "name" {
|
||||
delete(result, name)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
desc := field.Description
|
||||
if len(desc) > 0 {
|
||||
desc += " "
|
||||
}
|
||||
|
||||
value, hasKey := result[name]
|
||||
if hasKey {
|
||||
if field.Default != nil && field.Default == value {
|
||||
delete(result, name)
|
||||
result["zzz#("+desc+")("+field.Type+")"+name] = value
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if field.Default != nil {
|
||||
result["zzz#("+desc+")("+field.Type+")"+name] = field.Default
|
||||
} else {
|
||||
val, err := b.convert(field.Type, nil, List)
|
||||
if err == nil {
|
||||
result["zzz#("+desc+")("+field.Type+")"+name] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Builder) copyFields(schema *types.Schema, input map[string]interface{}, op Operation) (map[string]interface{}, error) {
|
||||
result := map[string]interface{}{}
|
||||
|
||||
if err := b.copyInputs(schema, input, op, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, b.checkDefaultAndRequired(schema, input, op, result)
|
||||
}
|
||||
|
||||
func CheckFieldCriteria(fieldName string, field types.Field, value interface{}) error {
|
||||
numVal, isNum := value.(int64)
|
||||
strVal := ""
|
||||
hasStrVal := false
|
||||
|
||||
if value == nil && field.Default != nil {
|
||||
value = field.Default
|
||||
}
|
||||
|
||||
if value != nil && value != "" {
|
||||
hasStrVal = true
|
||||
strVal = fmt.Sprint(value)
|
||||
}
|
||||
|
||||
if (value == nil || value == "") && !field.Nullable {
|
||||
if field.Default == nil {
|
||||
return httperror.NewFieldAPIError(httperror.NotNullable, fieldName, "")
|
||||
}
|
||||
}
|
||||
|
||||
if isNum {
|
||||
if field.Min != nil && numVal < *field.Min {
|
||||
return httperror.NewFieldAPIError(httperror.MinLimitExceeded, fieldName, "")
|
||||
}
|
||||
if field.Max != nil && numVal > *field.Max {
|
||||
return httperror.NewFieldAPIError(httperror.MaxLimitExceeded, fieldName, "")
|
||||
}
|
||||
}
|
||||
|
||||
if hasStrVal {
|
||||
if field.MinLength != nil && int64(len(strVal)) < *field.MinLength {
|
||||
return httperror.NewFieldAPIError(httperror.MinLengthExceeded, fieldName, "")
|
||||
}
|
||||
if field.MaxLength != nil && int64(len(strVal)) > *field.MaxLength {
|
||||
return httperror.NewFieldAPIError(httperror.MaxLengthExceeded, fieldName, "")
|
||||
}
|
||||
}
|
||||
|
||||
if len(field.Options) > 0 {
|
||||
if hasStrVal || !field.Nullable {
|
||||
found := false
|
||||
for _, option := range field.Options {
|
||||
if strVal == option {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return httperror.NewFieldAPIError(httperror.InvalidOption, fieldName, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(field.ValidChars) > 0 && hasStrVal {
|
||||
for _, c := range strVal {
|
||||
if !strings.ContainsRune(field.ValidChars, c) {
|
||||
return httperror.NewFieldAPIError(httperror.InvalidCharacters, fieldName, "")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if len(field.InvalidChars) > 0 && hasStrVal {
|
||||
if strings.ContainsAny(strVal, field.InvalidChars) {
|
||||
return httperror.NewFieldAPIError(httperror.InvalidCharacters, fieldName, "")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ConvertSimple(fieldType string, value interface{}, op Operation) (interface{}, error) {
|
||||
if value == nil {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
switch fieldType {
|
||||
case "json":
|
||||
return value, nil
|
||||
case "date":
|
||||
v := convert.ToString(value)
|
||||
if v == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return v, nil
|
||||
case "boolean":
|
||||
return convert.ToBool(value), nil
|
||||
case "enum":
|
||||
return convert.ToString(value), nil
|
||||
case "int":
|
||||
return convert.ToNumber(value)
|
||||
case "password":
|
||||
return convert.ToString(value), nil
|
||||
case "string":
|
||||
if op.IsList() {
|
||||
return convert.ToStringNoTrim(value), nil
|
||||
}
|
||||
return convert.ToString(value), nil
|
||||
case "dnsLabel":
|
||||
str := convert.ToString(value)
|
||||
if str == "" {
|
||||
return "", nil
|
||||
}
|
||||
if op == Create || op == Update {
|
||||
if errs := validation.IsDNS1123Label(str); len(errs) != 0 {
|
||||
return value, httperror.NewAPIError(httperror.InvalidFormat, fmt.Sprintf("invalid value %s: %s", value,
|
||||
strings.Join(errs, ",")))
|
||||
}
|
||||
}
|
||||
return str, nil
|
||||
case "dnsLabelRestricted":
|
||||
str := convert.ToString(value)
|
||||
if str == "" {
|
||||
return "", nil
|
||||
}
|
||||
if op == Create || op == Update {
|
||||
if errs := validation.IsDNS1035Label(str); len(errs) != 0 {
|
||||
return value, httperror.NewAPIError(httperror.InvalidFormat, fmt.Sprintf("invalid value %s: %s", value,
|
||||
strings.Join(errs, ",")))
|
||||
}
|
||||
}
|
||||
return str, nil
|
||||
case "hostname":
|
||||
str := convert.ToString(value)
|
||||
if str == "" {
|
||||
return "", nil
|
||||
}
|
||||
if op == Create || op == Update {
|
||||
if errs := validation.IsDNS1123Subdomain(str); len(errs) != 0 {
|
||||
return value, httperror.NewAPIError(httperror.InvalidFormat, fmt.Sprintf("invalid value %s: %s", value,
|
||||
strings.Join(errs, ",")))
|
||||
}
|
||||
}
|
||||
return str, nil
|
||||
case "intOrString":
|
||||
num, err := convert.ToNumber(value)
|
||||
if err == nil {
|
||||
return num, nil
|
||||
}
|
||||
return convert.ToString(value), nil
|
||||
case "base64":
|
||||
return convert.ToString(value), nil
|
||||
case "reference":
|
||||
return convert.ToString(value), nil
|
||||
}
|
||||
|
||||
return nil, ErrComplexType
|
||||
}
|
||||
|
||||
func (b *Builder) convert(fieldType string, value interface{}, op Operation) (interface{}, error) {
|
||||
if value == nil {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
switch {
|
||||
case definition.IsMapType(fieldType):
|
||||
return b.convertMap(fieldType, value, op)
|
||||
case definition.IsArrayType(fieldType):
|
||||
return b.convertArray(fieldType, value, op)
|
||||
case definition.IsReferenceType(fieldType):
|
||||
return b.convertReferenceType(fieldType, value)
|
||||
}
|
||||
|
||||
newValue, err := ConvertSimple(fieldType, value, op)
|
||||
if err == ErrComplexType {
|
||||
return b.convertType(fieldType, value, op)
|
||||
}
|
||||
return newValue, err
|
||||
}
|
||||
|
||||
func (b *Builder) convertType(fieldType string, value interface{}, op Operation) (interface{}, error) {
|
||||
schema := b.Schemas.Schema(b.Version, fieldType)
|
||||
if schema == nil {
|
||||
return nil, httperror.NewAPIError(httperror.InvalidType, "Failed to find type "+fieldType)
|
||||
}
|
||||
|
||||
mapValue, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, httperror.NewAPIError(httperror.InvalidFormat, fmt.Sprintf("Value can not be converted to type %s: %v", fieldType, value))
|
||||
}
|
||||
|
||||
return b.Construct(schema, mapValue, op)
|
||||
}
|
||||
|
||||
func (b *Builder) convertReferenceType(fieldType string, value interface{}) (string, error) {
|
||||
subType := definition.SubType(fieldType)
|
||||
strVal := convert.ToString(value)
|
||||
if b.RefValidator != nil && !b.RefValidator.Validate(subType, strVal) {
|
||||
return "", httperror.NewAPIError(httperror.InvalidReference, fmt.Sprintf("Not found type: %s id: %s", subType, strVal))
|
||||
}
|
||||
return strVal, nil
|
||||
}
|
||||
|
||||
func (b *Builder) convertArray(fieldType string, value interface{}, op Operation) ([]interface{}, error) {
|
||||
if strSliceValue, ok := value.([]string); ok {
|
||||
// Form data will be []string
|
||||
var result []interface{}
|
||||
for _, value := range strSliceValue {
|
||||
result = append(result, value)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
sliceValue, ok := value.([]interface{})
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var result []interface{}
|
||||
subType := definition.SubType(fieldType)
|
||||
|
||||
for _, value := range sliceValue {
|
||||
val, err := b.convert(subType, value, op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, val)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (b *Builder) convertMap(fieldType string, value interface{}, op Operation) (map[string]interface{}, error) {
|
||||
mapValue, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
result := map[string]interface{}{}
|
||||
subType := definition.SubType(fieldType)
|
||||
|
||||
for key, value := range mapValue {
|
||||
val, err := b.convert(subType, value, op)
|
||||
if err != nil {
|
||||
return nil, httperror.WrapAPIError(err, httperror.InvalidFormat, err.Error())
|
||||
}
|
||||
result[key] = val
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func fieldMatchesOp(field types.Field, op Operation) bool {
|
||||
switch op {
|
||||
case Create:
|
||||
return field.Create
|
||||
case Update:
|
||||
return field.Update
|
||||
case List:
|
||||
if field.Type == "password" {
|
||||
return false
|
||||
}
|
||||
return !field.WriteOnly
|
||||
case ListForCreate:
|
||||
if field.Type == "password" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
112
vendor/github.com/rancher/norman/parse/collection.go
generated
vendored
112
vendor/github.com/rancher/norman/parse/collection.go
generated
vendored
@@ -1,112 +0,0 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultLimit = int64(1000)
|
||||
maxLimit = int64(3000)
|
||||
)
|
||||
|
||||
func QueryOptions(apiContext *types.APIContext, schema *types.Schema) types.QueryOptions {
|
||||
req := apiContext.Request
|
||||
if req.Method != http.MethodGet {
|
||||
return types.QueryOptions{}
|
||||
}
|
||||
|
||||
result := &types.QueryOptions{}
|
||||
|
||||
result.Sort = parseSort(schema, apiContext)
|
||||
result.Pagination = parsePagination(apiContext)
|
||||
result.Conditions = parseFilters(schema, apiContext)
|
||||
|
||||
return *result
|
||||
}
|
||||
|
||||
func parseOrder(apiContext *types.APIContext) types.SortOrder {
|
||||
order := apiContext.Query.Get("order")
|
||||
if types.SortOrder(order) == types.DESC {
|
||||
return types.DESC
|
||||
}
|
||||
return types.ASC
|
||||
}
|
||||
|
||||
func parseSort(schema *types.Schema, apiContext *types.APIContext) types.Sort {
|
||||
sortField := apiContext.Query.Get("sort")
|
||||
if _, ok := schema.CollectionFilters[sortField]; !ok {
|
||||
sortField = ""
|
||||
}
|
||||
return types.Sort{
|
||||
Order: parseOrder(apiContext),
|
||||
Name: sortField,
|
||||
}
|
||||
}
|
||||
|
||||
func parsePagination(apiContext *types.APIContext) *types.Pagination {
|
||||
if apiContext.Pagination != nil {
|
||||
return apiContext.Pagination
|
||||
}
|
||||
|
||||
q := apiContext.Query
|
||||
limit := q.Get("limit")
|
||||
marker := q.Get("marker")
|
||||
|
||||
result := &types.Pagination{
|
||||
Limit: &defaultLimit,
|
||||
Marker: marker,
|
||||
}
|
||||
|
||||
if limit != "" {
|
||||
limitInt, err := strconv.ParseInt(limit, 10, 64)
|
||||
if err != nil {
|
||||
return result
|
||||
}
|
||||
|
||||
if limitInt > maxLimit {
|
||||
result.Limit = &maxLimit
|
||||
} else if limitInt >= 0 {
|
||||
result.Limit = &limitInt
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func parseNameAndOp(value string) (string, types.ModifierType) {
|
||||
name := value
|
||||
op := "eq"
|
||||
|
||||
idx := strings.LastIndex(value, "_")
|
||||
if idx > 0 {
|
||||
op = value[idx+1:]
|
||||
name = value[0:idx]
|
||||
}
|
||||
|
||||
return name, types.ModifierType(op)
|
||||
}
|
||||
|
||||
func parseFilters(schema *types.Schema, apiContext *types.APIContext) []*types.QueryCondition {
|
||||
var conditions []*types.QueryCondition
|
||||
for key, values := range apiContext.Query {
|
||||
name, op := parseNameAndOp(key)
|
||||
filter, ok := schema.CollectionFilters[name]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, mod := range filter.Modifiers {
|
||||
if op != mod || !types.ValidMod(op) {
|
||||
continue
|
||||
}
|
||||
|
||||
conditions = append(conditions, types.NewConditionFromString(name, mod, values...))
|
||||
}
|
||||
}
|
||||
|
||||
return conditions
|
||||
}
|
310
vendor/github.com/rancher/norman/parse/parse.go
generated
vendored
310
vendor/github.com/rancher/norman/parse/parse.go
generated
vendored
@@ -1,310 +0,0 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"sort"
|
||||
|
||||
"github.com/rancher/norman/api/builtin"
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/urlbuilder"
|
||||
)
|
||||
|
||||
const (
|
||||
maxFormSize = 2 * 1 << 20
|
||||
)
|
||||
|
||||
var (
|
||||
multiSlashRegexp = regexp.MustCompile("//+")
|
||||
allowedFormats = map[string]bool{
|
||||
"html": true,
|
||||
"json": true,
|
||||
"yaml": true,
|
||||
}
|
||||
)
|
||||
|
||||
type ParsedURL struct {
|
||||
Version *types.APIVersion
|
||||
SchemasVersion *types.APIVersion
|
||||
Type string
|
||||
ID string
|
||||
Link string
|
||||
Method string
|
||||
Action string
|
||||
SubContext map[string]string
|
||||
SubContextPrefix string
|
||||
Query url.Values
|
||||
}
|
||||
|
||||
type ResolverFunc func(typeName string, context *types.APIContext) error
|
||||
|
||||
type URLParser func(schema *types.Schemas, url *url.URL) (ParsedURL, error)
|
||||
|
||||
func DefaultURLParser(schemas *types.Schemas, url *url.URL) (ParsedURL, error) {
|
||||
result := ParsedURL{}
|
||||
|
||||
path := url.EscapedPath()
|
||||
path = multiSlashRegexp.ReplaceAllString(path, "/")
|
||||
schemaVersion, version, prefix, parts, subContext := parseVersionAndSubContext(schemas, path)
|
||||
|
||||
if version == nil {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
result.Version = version
|
||||
result.SchemasVersion = schemaVersion
|
||||
result.SubContext = subContext
|
||||
result.SubContextPrefix = prefix
|
||||
result.Action, result.Method = parseAction(url)
|
||||
result.Query = url.Query()
|
||||
|
||||
result.Type = safeIndex(parts, 0)
|
||||
result.ID = safeIndex(parts, 1)
|
||||
result.Link = safeIndex(parts, 2)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func Parse(rw http.ResponseWriter, req *http.Request, schemas *types.Schemas, urlParser URLParser, resolverFunc ResolverFunc) (*types.APIContext, error) {
|
||||
var err error
|
||||
|
||||
result := types.NewAPIContext(req, rw, schemas)
|
||||
result.Method = parseMethod(req)
|
||||
result.ResponseFormat = parseResponseFormat(req)
|
||||
result.URLBuilder, _ = urlbuilder.New(req, types.APIVersion{}, schemas)
|
||||
|
||||
// The response format is guarenteed to be set even in the event of an error
|
||||
parsedURL, err := urlParser(schemas, req.URL)
|
||||
// wait to check error, want to set as much as possible
|
||||
|
||||
result.SubContext = parsedURL.SubContext
|
||||
result.Type = parsedURL.Type
|
||||
result.ID = parsedURL.ID
|
||||
result.Link = parsedURL.Link
|
||||
result.Action = parsedURL.Action
|
||||
result.Query = parsedURL.Query
|
||||
if parsedURL.Method != "" {
|
||||
result.Method = parsedURL.Method
|
||||
}
|
||||
|
||||
result.Version = parsedURL.Version
|
||||
result.SchemasVersion = parsedURL.SchemasVersion
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
if result.Version == nil {
|
||||
result.Method = http.MethodGet
|
||||
result.URLBuilder, err = urlbuilder.New(req, types.APIVersion{}, result.Schemas)
|
||||
result.Type = "apiRoot"
|
||||
result.Schema = result.Schemas.Schema(&builtin.Version, "apiRoot")
|
||||
return result, nil
|
||||
}
|
||||
|
||||
result.URLBuilder, err = urlbuilder.New(req, *result.Version, result.Schemas)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
if parsedURL.SubContextPrefix != "" {
|
||||
result.URLBuilder.SetSubContext(parsedURL.SubContextPrefix)
|
||||
}
|
||||
|
||||
if err := resolverFunc(result.Type, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
if result.Schema == nil {
|
||||
if result.Type != "" {
|
||||
err = httperror.NewAPIError(httperror.NotFound, "failed to find schema "+result.Type)
|
||||
}
|
||||
result.Method = http.MethodGet
|
||||
result.Type = "apiRoot"
|
||||
result.Schema = result.Schemas.Schema(&builtin.Version, "apiRoot")
|
||||
result.ID = result.Version.Path
|
||||
return result, err
|
||||
}
|
||||
|
||||
result.Type = result.Schema.ID
|
||||
|
||||
if err := ValidateMethod(result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func versionsForPath(schemas *types.Schemas, path string) []types.APIVersion {
|
||||
var matchedVersion []types.APIVersion
|
||||
for _, version := range schemas.Versions() {
|
||||
if strings.HasPrefix(path, version.Path) {
|
||||
afterPath := path[len(version.Path):]
|
||||
// if version.Path is /v3/cluster allow /v3/clusters but not /v3/clusterstuff
|
||||
if len(afterPath) < 3 || strings.Contains(afterPath[:3], "/") {
|
||||
matchedVersion = append(matchedVersion, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(matchedVersion, func(i, j int) bool {
|
||||
return len(matchedVersion[i].Path) > len(matchedVersion[j].Path)
|
||||
})
|
||||
return matchedVersion
|
||||
}
|
||||
|
||||
func parseVersionAndSubContext(schemas *types.Schemas, escapedPath string) (*types.APIVersion, *types.APIVersion, string, []string, map[string]string) {
|
||||
versions := versionsForPath(schemas, escapedPath)
|
||||
if len(versions) == 0 {
|
||||
return nil, nil, "", nil, nil
|
||||
}
|
||||
version := &versions[0]
|
||||
|
||||
if strings.HasSuffix(escapedPath, "/") {
|
||||
escapedPath = escapedPath[:len(escapedPath)-1]
|
||||
}
|
||||
|
||||
versionParts := strings.Split(version.Path, "/")
|
||||
pp := strings.Split(escapedPath, "/")
|
||||
var pathParts []string
|
||||
for _, p := range pp {
|
||||
part, err := url.PathUnescape(p)
|
||||
if err == nil {
|
||||
pathParts = append(pathParts, part)
|
||||
} else {
|
||||
pathParts = append(pathParts, p)
|
||||
}
|
||||
}
|
||||
|
||||
paths := pathParts[len(versionParts):]
|
||||
|
||||
if !version.SubContext || len(versions) < 2 {
|
||||
return nil, version, "", paths, nil
|
||||
}
|
||||
|
||||
// Handle the special case of /v3/clusters/schema(s)
|
||||
if len(paths) >= 1 && (paths[0] == "schema" || paths[0] == "schemas") {
|
||||
return nil, version, "", paths, nil
|
||||
}
|
||||
|
||||
if len(paths) < 2 {
|
||||
// Handle case like /v3/clusters/foo where /v3 and /v3/clusters are API versions.
|
||||
// In this situation you want the version to be /v3 and the path "clusters", "foo"
|
||||
newVersion := versions[0]
|
||||
if len(paths) > 0 {
|
||||
newVersion.Path = newVersion.Path + "/" + paths[0]
|
||||
}
|
||||
return &newVersion, &versions[1], "", pathParts[len(versionParts)-1:], nil
|
||||
}
|
||||
|
||||
// Length is always >= 3
|
||||
|
||||
attrs := map[string]string{
|
||||
version.SubContextSchema: paths[0],
|
||||
}
|
||||
|
||||
for i, version := range versions {
|
||||
schema := schemas.Schema(&version, paths[1])
|
||||
if schema != nil {
|
||||
if i == 0 {
|
||||
break
|
||||
}
|
||||
return nil, &version, "", paths[1:], attrs
|
||||
}
|
||||
}
|
||||
|
||||
return nil, version, "/" + paths[0], paths[1:], attrs
|
||||
}
|
||||
|
||||
func DefaultResolver(typeName string, apiContext *types.APIContext) error {
|
||||
if typeName == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
schema := apiContext.Schemas.Schema(apiContext.Version, typeName)
|
||||
if schema == nil && (typeName == builtin.Schema.ID || typeName == builtin.Schema.PluralName) {
|
||||
// Schemas are special, we include it as though part of the API request version
|
||||
schema = apiContext.Schemas.Schema(&builtin.Version, typeName)
|
||||
}
|
||||
if schema == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
apiContext.Schema = schema
|
||||
return nil
|
||||
}
|
||||
|
||||
func safeIndex(slice []string, index int) string {
|
||||
if index >= len(slice) {
|
||||
return ""
|
||||
}
|
||||
return slice[index]
|
||||
}
|
||||
|
||||
func parseResponseFormat(req *http.Request) string {
|
||||
format := req.URL.Query().Get("_format")
|
||||
|
||||
if format != "" {
|
||||
format = strings.TrimSpace(strings.ToLower(format))
|
||||
}
|
||||
|
||||
/* Format specified */
|
||||
if allowedFormats[format] {
|
||||
return format
|
||||
}
|
||||
|
||||
// User agent has Mozilla and browser accepts */*
|
||||
if IsBrowser(req, true) {
|
||||
return "html"
|
||||
}
|
||||
|
||||
if isYaml(req) {
|
||||
return "yaml"
|
||||
}
|
||||
return "json"
|
||||
}
|
||||
|
||||
func isYaml(req *http.Request) bool {
|
||||
return strings.Contains(req.Header.Get("Accept"), "application/yaml")
|
||||
}
|
||||
|
||||
func parseMethod(req *http.Request) string {
|
||||
method := req.URL.Query().Get("_method")
|
||||
if method == "" {
|
||||
method = req.Method
|
||||
}
|
||||
return method
|
||||
}
|
||||
|
||||
func parseAction(url *url.URL) (string, string) {
|
||||
action := url.Query().Get("action")
|
||||
if action == "remove" {
|
||||
return "", http.MethodDelete
|
||||
}
|
||||
|
||||
return action, ""
|
||||
}
|
||||
|
||||
func Body(req *http.Request) (map[string]interface{}, error) {
|
||||
req.ParseMultipartForm(maxFormSize)
|
||||
if req.MultipartForm != nil {
|
||||
return valuesToBody(req.MultipartForm.Value), nil
|
||||
}
|
||||
|
||||
if req.PostForm != nil && len(req.PostForm) > 0 {
|
||||
return valuesToBody(map[string][]string(req.Form)), nil
|
||||
}
|
||||
|
||||
return ReadBody(req)
|
||||
}
|
||||
|
||||
func valuesToBody(input map[string][]string) map[string]interface{} {
|
||||
result := map[string]interface{}{}
|
||||
for k, v := range input {
|
||||
result[k] = v
|
||||
}
|
||||
return result
|
||||
}
|
45
vendor/github.com/rancher/norman/parse/read_input.go
generated
vendored
45
vendor/github.com/rancher/norman/parse/read_input.go
generated
vendored
@@ -1,45 +0,0 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/norman/httperror"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
)
|
||||
|
||||
const reqMaxSize = (2 * 1 << 20) + 1
|
||||
|
||||
var bodyMethods = map[string]bool{
|
||||
http.MethodPut: true,
|
||||
http.MethodPost: true,
|
||||
}
|
||||
|
||||
type Decode func(interface{}) error
|
||||
|
||||
func ReadBody(req *http.Request) (map[string]interface{}, error) {
|
||||
if !bodyMethods[req.Method] {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
decode := getDecoder(req, io.LimitReader(req.Body, maxFormSize))
|
||||
|
||||
data := map[string]interface{}{}
|
||||
if err := decode(&data); err != nil {
|
||||
return nil, httperror.NewAPIError(httperror.InvalidBodyContent,
|
||||
fmt.Sprintf("Failed to parse body: %v", err))
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func getDecoder(req *http.Request, reader io.Reader) Decode {
|
||||
if req.Header.Get("Content-type") == "application/yaml" {
|
||||
return yaml.NewYAMLToJSONDecoder(reader).Decode
|
||||
}
|
||||
decoder := json.NewDecoder(reader)
|
||||
decoder.UseNumber()
|
||||
return decoder.Decode
|
||||
}
|
50
vendor/github.com/rancher/norman/parse/subcontext.go
generated
vendored
50
vendor/github.com/rancher/norman/parse/subcontext.go
generated
vendored
@@ -1,50 +0,0 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
)
|
||||
|
||||
type DefaultSubContextAttributeProvider struct {
|
||||
}
|
||||
|
||||
func (d *DefaultSubContextAttributeProvider) Query(apiContext *types.APIContext, schema *types.Schema) []*types.QueryCondition {
|
||||
var result []*types.QueryCondition
|
||||
|
||||
for name, value := range d.create(apiContext, schema) {
|
||||
result = append(result, types.NewConditionFromString(name, types.ModifierEQ, value))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (d *DefaultSubContextAttributeProvider) Create(apiContext *types.APIContext, schema *types.Schema) map[string]interface{} {
|
||||
result := map[string]interface{}{}
|
||||
for key, value := range d.create(apiContext, schema) {
|
||||
result[key] = value
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (d *DefaultSubContextAttributeProvider) create(apiContext *types.APIContext, schema *types.Schema) map[string]string {
|
||||
result := map[string]string{}
|
||||
|
||||
for subContextSchemaID, value := range apiContext.SubContext {
|
||||
subContextSchema := apiContext.Schemas.Schema(nil, subContextSchemaID)
|
||||
if subContextSchema == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
ref := convert.ToReference(subContextSchema.ID)
|
||||
fullRef := convert.ToFullReference(subContextSchema.Version.Path, subContextSchema.ID)
|
||||
|
||||
for name, field := range schema.ResourceFields {
|
||||
if field.Type == ref || field.Type == fullRef {
|
||||
result[name] = value
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
45
vendor/github.com/rancher/norman/parse/validate.go
generated
vendored
45
vendor/github.com/rancher/norman/parse/validate.go
generated
vendored
@@ -1,45 +0,0 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
var (
|
||||
supportedMethods = map[string]bool{
|
||||
http.MethodPost: true,
|
||||
http.MethodGet: true,
|
||||
http.MethodPut: true,
|
||||
http.MethodDelete: true,
|
||||
}
|
||||
)
|
||||
|
||||
func ValidateMethod(request *types.APIContext) error {
|
||||
if request.Action != "" && request.Method == http.MethodPost {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !supportedMethods[request.Method] {
|
||||
return httperror.NewAPIError(httperror.MethodNotAllowed, fmt.Sprintf("Method %s not supported", request.Method))
|
||||
}
|
||||
|
||||
if request.Type == "" || request.Schema == nil || request.Link != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
allowed := request.Schema.ResourceMethods
|
||||
if request.ID == "" {
|
||||
allowed = request.Schema.CollectionMethods
|
||||
}
|
||||
|
||||
for _, method := range allowed {
|
||||
if method == request.Method {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return httperror.NewAPIError(httperror.MethodNotAllowed, fmt.Sprintf("Method %s not supported", request.Method))
|
||||
}
|
71
vendor/github.com/rancher/norman/pkg/changeset/changeset.go
generated
vendored
71
vendor/github.com/rancher/norman/pkg/changeset/changeset.go
generated
vendored
@@ -1,71 +0,0 @@
|
||||
package changeset
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/norman/controller"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
type Key struct {
|
||||
Namespace string
|
||||
Name string
|
||||
}
|
||||
|
||||
type ControllerProvider interface {
|
||||
Generic() controller.GenericController
|
||||
}
|
||||
|
||||
type Enqueuer func(namespace, name string)
|
||||
|
||||
type Resolver func(namespace, name string, obj runtime.Object) ([]Key, error)
|
||||
|
||||
func Watch(name string, resolve Resolver, enq Enqueuer, controllers ...ControllerProvider) {
|
||||
for _, c := range controllers {
|
||||
watch(name, enq, resolve, c.Generic())
|
||||
}
|
||||
}
|
||||
|
||||
func watch(name string, enq Enqueuer, resolve Resolver, genericController controller.GenericController) {
|
||||
genericController.AddHandler(name, func(key string) error {
|
||||
obj, exists, err := genericController.Informer().GetStore().GetByKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
obj = nil
|
||||
}
|
||||
|
||||
var (
|
||||
ns string
|
||||
name string
|
||||
)
|
||||
|
||||
parts := strings.SplitN(key, "/", 2)
|
||||
if len(parts) == 2 {
|
||||
ns = parts[0]
|
||||
name = parts[1]
|
||||
} else {
|
||||
name = parts[0]
|
||||
}
|
||||
|
||||
ro, ok := obj.(runtime.Object)
|
||||
if !ok {
|
||||
ro = nil
|
||||
}
|
||||
|
||||
keys, err := resolve(ns, name, ro)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
if key.Name != "" {
|
||||
enq(key.Namespace, key.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
44
vendor/github.com/rancher/norman/pkg/dump/dump.go
generated
vendored
44
vendor/github.com/rancher/norman/pkg/dump/dump.go
generated
vendored
@@ -1,44 +0,0 @@
|
||||
package dump
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
|
||||
"github.com/maruel/panicparse/stack"
|
||||
)
|
||||
|
||||
func GoroutineDumpOn(signals ...os.Signal) {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, signals...)
|
||||
go func() {
|
||||
for range c {
|
||||
var (
|
||||
buf []byte
|
||||
stackSize int
|
||||
)
|
||||
bufferLen := 16384
|
||||
for stackSize == len(buf) {
|
||||
buf = make([]byte, bufferLen)
|
||||
stackSize = runtime.Stack(buf, true)
|
||||
bufferLen *= 2
|
||||
}
|
||||
buf = buf[:stackSize]
|
||||
src := bytes.NewBuffer(buf)
|
||||
if goroutines, err := stack.ParseDump(src, os.Stderr); err == nil {
|
||||
buckets := stack.SortBuckets(stack.Bucketize(goroutines, stack.AnyValue))
|
||||
srcLen, pkgLen := stack.CalcLengths(buckets, true)
|
||||
p := &stack.Palette{}
|
||||
for _, bucket := range buckets {
|
||||
_, _ = io.WriteString(os.Stderr, p.BucketHeader(&bucket, true, len(buckets) > 1))
|
||||
_, _ = io.WriteString(os.Stderr, p.StackLines(&bucket.Signature, srcLen, pkgLen, true))
|
||||
}
|
||||
io.Copy(os.Stderr, bytes.NewBuffer(buf))
|
||||
} else {
|
||||
io.Copy(os.Stderr, src)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
24
vendor/github.com/rancher/norman/pkg/kv/split.go
generated
vendored
24
vendor/github.com/rancher/norman/pkg/kv/split.go
generated
vendored
@@ -1,24 +0,0 @@
|
||||
package kv
|
||||
|
||||
import "strings"
|
||||
|
||||
func Split(s, sep string) (string, string) {
|
||||
parts := strings.SplitN(s, sep, 2)
|
||||
return strings.TrimSpace(parts[0]), strings.TrimSpace(safeIndex(parts, 1))
|
||||
}
|
||||
|
||||
func SplitMap(s, sep string) map[string]string {
|
||||
result := map[string]string{}
|
||||
for _, part := range strings.Split(s, sep) {
|
||||
k, v := Split(part, "=")
|
||||
result[k] = v
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func safeIndex(parts []string, idx int) string {
|
||||
if len(parts) <= idx {
|
||||
return ""
|
||||
}
|
||||
return parts[idx]
|
||||
}
|
174
vendor/github.com/rancher/norman/pkg/subscribe/handler.go
generated
vendored
174
vendor/github.com/rancher/norman/pkg/subscribe/handler.go
generated
vendored
@@ -1,174 +0,0 @@
|
||||
package subscribe
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/rancher/norman/api/writer"
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/parse"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
"github.com/rancher/norman/types/slice"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
var upgrader = websocket.Upgrader{}
|
||||
|
||||
type Subscribe struct {
|
||||
ResourceTypes []string
|
||||
APIVersions []string
|
||||
ProjectID string `norman:"type=reference[/v3/schemas/project]"`
|
||||
}
|
||||
|
||||
func Handler(apiContext *types.APIContext, _ types.RequestHandler) error {
|
||||
err := handler(apiContext)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error during subscribe %v", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func getMatchingSchemas(apiContext *types.APIContext) []*types.Schema {
|
||||
resourceTypes := apiContext.Request.URL.Query()["resourceTypes"]
|
||||
|
||||
var schemas []*types.Schema
|
||||
for _, schema := range apiContext.Schemas.SchemasForVersion(*apiContext.Version) {
|
||||
if !matches(resourceTypes, schema.ID) {
|
||||
continue
|
||||
}
|
||||
if schema.Store != nil {
|
||||
schemas = append(schemas, schema)
|
||||
}
|
||||
}
|
||||
|
||||
return schemas
|
||||
}
|
||||
|
||||
func handler(apiContext *types.APIContext) error {
|
||||
schemas := getMatchingSchemas(apiContext)
|
||||
if len(schemas) == 0 {
|
||||
return httperror.NewAPIError(httperror.NotFound, "no resources types matched")
|
||||
}
|
||||
|
||||
c, err := upgrader.Upgrade(apiContext.Response, apiContext.Request, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
cancelCtx, cancel := context.WithCancel(apiContext.Request.Context())
|
||||
readerGroup, ctx := errgroup.WithContext(cancelCtx)
|
||||
apiContext.Request = apiContext.Request.WithContext(ctx)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
if _, _, err := c.NextReader(); err != nil {
|
||||
cancel()
|
||||
c.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
events := make(chan map[string]interface{})
|
||||
for _, schema := range schemas {
|
||||
streamStore(ctx, readerGroup, apiContext, schema, events)
|
||||
}
|
||||
|
||||
go func() {
|
||||
readerGroup.Wait()
|
||||
close(events)
|
||||
}()
|
||||
|
||||
jsonWriter := writer.EncodingResponseWriter{
|
||||
ContentType: "application/json",
|
||||
Encoder: types.JSONEncoder,
|
||||
}
|
||||
t := time.NewTicker(5 * time.Second)
|
||||
defer t.Stop()
|
||||
|
||||
done := false
|
||||
for !done {
|
||||
select {
|
||||
case item, ok := <-events:
|
||||
if !ok {
|
||||
done = true
|
||||
break
|
||||
}
|
||||
|
||||
header := `{"name":"resource.change","data":`
|
||||
if item[".removed"] == true {
|
||||
header = `{"name":"resource.remove","data":`
|
||||
}
|
||||
schema := apiContext.Schemas.Schema(apiContext.Version, convert.ToString(item["type"]))
|
||||
if schema != nil {
|
||||
buffer := &bytes.Buffer{}
|
||||
if err := jsonWriter.VersionBody(apiContext, &schema.Version, buffer, item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := writeData(c, header, buffer.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case <-t.C:
|
||||
if err := writeData(c, `{"name":"ping","data":`, []byte("{}")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no point in ever returning null because the connection is hijacked and we can't write it
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeData(c *websocket.Conn, header string, buf []byte) error {
|
||||
messageWriter, err := c.NextWriter(websocket.TextMessage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := messageWriter.Write([]byte(header)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := messageWriter.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := messageWriter.Write([]byte(`}`)); err != nil {
|
||||
return err
|
||||
}
|
||||
return messageWriter.Close()
|
||||
}
|
||||
|
||||
func streamStore(ctx context.Context, eg *errgroup.Group, apiContext *types.APIContext, schema *types.Schema, result chan map[string]interface{}) {
|
||||
eg.Go(func() error {
|
||||
opts := parse.QueryOptions(apiContext, schema)
|
||||
events, err := schema.Store.Watch(apiContext, schema, &opts)
|
||||
if err != nil || events == nil {
|
||||
if err != nil {
|
||||
logrus.Errorf("failed on subscribe %s: %v", schema.ID, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.Debugf("watching %s", schema.ID)
|
||||
|
||||
for e := range events {
|
||||
result <- e
|
||||
}
|
||||
|
||||
return errors.New("disconnect")
|
||||
})
|
||||
}
|
||||
|
||||
func matches(items []string, item string) bool {
|
||||
if len(items) == 0 {
|
||||
return true
|
||||
}
|
||||
return slice.ContainsString(items, item)
|
||||
}
|
16
vendor/github.com/rancher/norman/pkg/subscribe/register.go
generated
vendored
16
vendor/github.com/rancher/norman/pkg/subscribe/register.go
generated
vendored
@@ -1,16 +0,0 @@
|
||||
package subscribe
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
func Register(version *types.APIVersion, schemas *types.Schemas) {
|
||||
schemas.MustImportAndCustomize(version, Subscribe{}, func(schema *types.Schema) {
|
||||
schema.CollectionMethods = []string{http.MethodGet}
|
||||
schema.ResourceMethods = []string{}
|
||||
schema.ListHandler = Handler
|
||||
schema.PluralName = "subscribe"
|
||||
})
|
||||
}
|
43
vendor/github.com/rancher/norman/restwatch/rest.go
generated
vendored
43
vendor/github.com/rancher/norman/restwatch/rest.go
generated
vendored
@@ -1,43 +0,0 @@
|
||||
package restwatch
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type WatchClient interface {
|
||||
WatchClient() rest.Interface
|
||||
}
|
||||
|
||||
func UnversionedRESTClientFor(config *rest.Config) (rest.Interface, error) {
|
||||
client, err := rest.UnversionedRESTClientFor(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if config.Timeout == 0 {
|
||||
return client, err
|
||||
}
|
||||
|
||||
newConfig := *config
|
||||
newConfig.Timeout = time.Hour
|
||||
watchClient, err := rest.UnversionedRESTClientFor(&newConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &clientWithWatch{
|
||||
RESTClient: client,
|
||||
watchClient: watchClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type clientWithWatch struct {
|
||||
*rest.RESTClient
|
||||
watchClient *rest.RESTClient
|
||||
}
|
||||
|
||||
func (c *clientWithWatch) WatchClient() rest.Interface {
|
||||
return c.watchClient
|
||||
}
|
28
vendor/github.com/rancher/norman/signal/sigterm.go
generated
vendored
28
vendor/github.com/rancher/norman/signal/sigterm.go
generated
vendored
@@ -1,28 +0,0 @@
|
||||
package signal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func SigTermCancelContext(ctx context.Context) context.Context {
|
||||
term := make(chan os.Signal)
|
||||
signal.Notify(term, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-term:
|
||||
logrus.Infof("Received SIGTERM, cancelling")
|
||||
cancel()
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}()
|
||||
|
||||
return ctx
|
||||
}
|
224
vendor/github.com/rancher/norman/store/crd/init.go
generated
vendored
224
vendor/github.com/rancher/norman/store/crd/init.go
generated
vendored
@@ -1,224 +0,0 @@
|
||||
package crd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rancher/norman/store/proxy"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
"github.com/sirupsen/logrus"
|
||||
apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type Factory struct {
|
||||
wg sync.WaitGroup
|
||||
ClientGetter proxy.ClientGetter
|
||||
}
|
||||
|
||||
func NewFactoryFromClientGetter(clientGetter proxy.ClientGetter) *Factory {
|
||||
return &Factory{
|
||||
ClientGetter: clientGetter,
|
||||
}
|
||||
}
|
||||
|
||||
func NewFactoryFromClient(config rest.Config) (*Factory, error) {
|
||||
getter, err := proxy.NewClientGetterFromConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Factory{
|
||||
ClientGetter: getter,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *Factory) BatchWait() {
|
||||
f.wg.Wait()
|
||||
}
|
||||
|
||||
func (f *Factory) BatchCreateCRDs(ctx context.Context, storageContext types.StorageContext, schemas *types.Schemas, version *types.APIVersion, schemaIDs ...string) {
|
||||
f.wg.Add(1)
|
||||
go func() {
|
||||
defer f.wg.Done()
|
||||
|
||||
var schemasToCreate []*types.Schema
|
||||
|
||||
for _, schemaID := range schemaIDs {
|
||||
s := schemas.Schema(version, schemaID)
|
||||
if s == nil {
|
||||
panic("can not find schema " + schemaID)
|
||||
}
|
||||
schemasToCreate = append(schemasToCreate, s)
|
||||
}
|
||||
|
||||
err := f.AssignStores(ctx, storageContext, schemasToCreate...)
|
||||
if err != nil {
|
||||
panic("creating CRD store " + err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (f *Factory) AssignStores(ctx context.Context, storageContext types.StorageContext, schemas ...*types.Schema) error {
|
||||
schemaStatus, err := f.CreateCRDs(ctx, storageContext, schemas...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, schema := range schemas {
|
||||
crd, ok := schemaStatus[schema]
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to create create/find CRD for %s", schema.ID)
|
||||
}
|
||||
|
||||
schema.Store = proxy.NewProxyStore(ctx, f.ClientGetter,
|
||||
storageContext,
|
||||
[]string{"apis"},
|
||||
crd.Spec.Group,
|
||||
crd.Spec.Version,
|
||||
crd.Status.AcceptedNames.Kind,
|
||||
crd.Status.AcceptedNames.Plural)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Factory) CreateCRDs(ctx context.Context, storageContext types.StorageContext, schemas ...*types.Schema) (map[*types.Schema]*apiext.CustomResourceDefinition, error) {
|
||||
schemaStatus := map[*types.Schema]*apiext.CustomResourceDefinition{}
|
||||
|
||||
apiClient, err := f.ClientGetter.APIExtClient(nil, storageContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ready, err := f.getReadyCRDs(apiClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, schema := range schemas {
|
||||
crd, err := f.createCRD(apiClient, schema, ready)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
schemaStatus[schema] = crd
|
||||
}
|
||||
|
||||
ready, err = f.getReadyCRDs(apiClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for schema, crd := range schemaStatus {
|
||||
if readyCrd, ok := ready[crd.Name]; ok {
|
||||
schemaStatus[schema] = readyCrd
|
||||
} else {
|
||||
if err := f.waitCRD(ctx, apiClient, crd.Name, schema, schemaStatus); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return schemaStatus, nil
|
||||
}
|
||||
|
||||
func (f *Factory) waitCRD(ctx context.Context, apiClient clientset.Interface, crdName string, schema *types.Schema, schemaStatus map[*types.Schema]*apiext.CustomResourceDefinition) error {
|
||||
logrus.Infof("Waiting for CRD %s to become available", crdName)
|
||||
defer logrus.Infof("Done waiting for CRD %s to become available", crdName)
|
||||
|
||||
first := true
|
||||
return wait.Poll(500*time.Millisecond, 60*time.Second, func() (bool, error) {
|
||||
if !first {
|
||||
logrus.Infof("Waiting for CRD %s to become available", crdName)
|
||||
}
|
||||
first = false
|
||||
|
||||
crd, err := apiClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(crdName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, cond := range crd.Status.Conditions {
|
||||
switch cond.Type {
|
||||
case apiext.Established:
|
||||
if cond.Status == apiext.ConditionTrue {
|
||||
schemaStatus[schema] = crd
|
||||
return true, err
|
||||
}
|
||||
case apiext.NamesAccepted:
|
||||
if cond.Status == apiext.ConditionFalse {
|
||||
logrus.Infof("Name conflict on %s: %v\n", crdName, cond.Reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false, ctx.Err()
|
||||
})
|
||||
}
|
||||
|
||||
func (f *Factory) createCRD(apiClient clientset.Interface, schema *types.Schema, ready map[string]*apiext.CustomResourceDefinition) (*apiext.CustomResourceDefinition, error) {
|
||||
plural := strings.ToLower(schema.PluralName)
|
||||
name := strings.ToLower(plural + "." + schema.Version.Group)
|
||||
|
||||
crd, ok := ready[name]
|
||||
if ok {
|
||||
return crd, nil
|
||||
}
|
||||
|
||||
crd = &apiext.CustomResourceDefinition{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
Spec: apiext.CustomResourceDefinitionSpec{
|
||||
Group: schema.Version.Group,
|
||||
Version: schema.Version.Version,
|
||||
Names: apiext.CustomResourceDefinitionNames{
|
||||
Plural: plural,
|
||||
Kind: convert.Capitalize(schema.ID),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if schema.Scope == types.NamespaceScope {
|
||||
crd.Spec.Scope = apiext.NamespaceScoped
|
||||
} else {
|
||||
crd.Spec.Scope = apiext.ClusterScoped
|
||||
}
|
||||
|
||||
logrus.Infof("Creating CRD %s", name)
|
||||
crd, err := apiClient.ApiextensionsV1beta1().CustomResourceDefinitions().Create(crd)
|
||||
if errors.IsAlreadyExists(err) {
|
||||
return crd, nil
|
||||
}
|
||||
return crd, err
|
||||
}
|
||||
|
||||
func (f *Factory) getReadyCRDs(apiClient clientset.Interface) (map[string]*apiext.CustomResourceDefinition, error) {
|
||||
list, err := apiClient.ApiextensionsV1beta1().CustomResourceDefinitions().List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := map[string]*apiext.CustomResourceDefinition{}
|
||||
|
||||
for i, crd := range list.Items {
|
||||
for _, cond := range crd.Status.Conditions {
|
||||
switch cond.Type {
|
||||
case apiext.Established:
|
||||
if cond.Status == apiext.ConditionTrue {
|
||||
result[crd.Name] = &list.Items[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
36
vendor/github.com/rancher/norman/store/empty/empty_store.go
generated
vendored
36
vendor/github.com/rancher/norman/store/empty/empty_store.go
generated
vendored
@@ -1,36 +0,0 @@
|
||||
package empty
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
type Store struct {
|
||||
}
|
||||
|
||||
func (e *Store) Context() types.StorageContext {
|
||||
return types.DefaultStorageContext
|
||||
}
|
||||
|
||||
func (e *Store) Delete(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (e *Store) ByID(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (e *Store) List(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) ([]map[string]interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (e *Store) Create(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}) (map[string]interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (e *Store) Update(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}, id string) (map[string]interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (e *Store) Watch(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) (chan map[string]interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
52
vendor/github.com/rancher/norman/store/proxy/error_wrapper.go
generated
vendored
52
vendor/github.com/rancher/norman/store/proxy/error_wrapper.go
generated
vendored
@@ -1,52 +0,0 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/types"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
)
|
||||
|
||||
type errorStore struct {
|
||||
types.Store
|
||||
}
|
||||
|
||||
func (e *errorStore) ByID(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
|
||||
data, err := e.Store.ByID(apiContext, schema, id)
|
||||
return data, translateError(err)
|
||||
}
|
||||
|
||||
func (e *errorStore) List(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) ([]map[string]interface{}, error) {
|
||||
data, err := e.Store.List(apiContext, schema, opt)
|
||||
return data, translateError(err)
|
||||
}
|
||||
|
||||
func (e *errorStore) Create(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}) (map[string]interface{}, error) {
|
||||
data, err := e.Store.Create(apiContext, schema, data)
|
||||
return data, translateError(err)
|
||||
|
||||
}
|
||||
|
||||
func (e *errorStore) Update(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}, id string) (map[string]interface{}, error) {
|
||||
data, err := e.Store.Update(apiContext, schema, data, id)
|
||||
return data, translateError(err)
|
||||
|
||||
}
|
||||
|
||||
func (e *errorStore) Delete(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
|
||||
data, err := e.Store.Delete(apiContext, schema, id)
|
||||
return data, translateError(err)
|
||||
|
||||
}
|
||||
|
||||
func (e *errorStore) Watch(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) (chan map[string]interface{}, error) {
|
||||
data, err := e.Store.Watch(apiContext, schema, opt)
|
||||
return data, translateError(err)
|
||||
}
|
||||
|
||||
func translateError(err error) error {
|
||||
if apiError, ok := err.(errors.APIStatus); ok {
|
||||
status := apiError.Status()
|
||||
return httperror.NewAPIErrorLong(int(status.Code), string(status.Reason), status.Message)
|
||||
}
|
||||
return err
|
||||
}
|
475
vendor/github.com/rancher/norman/store/proxy/proxy_store.go
generated
vendored
475
vendor/github.com/rancher/norman/store/proxy/proxy_store.go
generated
vendored
@@ -1,475 +0,0 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
ejson "encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/objectclient/dynamic"
|
||||
"github.com/rancher/norman/pkg/broadcast"
|
||||
"github.com/rancher/norman/restwatch"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
"github.com/rancher/norman/types/convert/merge"
|
||||
"github.com/rancher/norman/types/values"
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/rest"
|
||||
restclientwatch "k8s.io/client-go/rest/watch"
|
||||
)
|
||||
|
||||
var (
|
||||
userAuthHeader = "Impersonate-User"
|
||||
authHeaders = []string{
|
||||
userAuthHeader,
|
||||
"Impersonate-Group",
|
||||
}
|
||||
)
|
||||
|
||||
type ClientGetter interface {
|
||||
UnversionedClient(apiContext *types.APIContext, context types.StorageContext) (rest.Interface, error)
|
||||
APIExtClient(apiContext *types.APIContext, context types.StorageContext) (clientset.Interface, error)
|
||||
}
|
||||
|
||||
type simpleClientGetter struct {
|
||||
restConfig rest.Config
|
||||
client rest.Interface
|
||||
apiExtClient clientset.Interface
|
||||
}
|
||||
|
||||
func NewClientGetterFromConfig(config rest.Config) (ClientGetter, error) {
|
||||
dynamicConfig := config
|
||||
if dynamicConfig.NegotiatedSerializer == nil {
|
||||
dynamicConfig.NegotiatedSerializer = dynamic.NegotiatedSerializer
|
||||
}
|
||||
|
||||
unversionedClient, err := rest.UnversionedRESTClientFor(&dynamicConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
apiExtClient, err := clientset.NewForConfig(&dynamicConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &simpleClientGetter{
|
||||
restConfig: config,
|
||||
client: unversionedClient,
|
||||
apiExtClient: apiExtClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *simpleClientGetter) Config(apiContext *types.APIContext, context types.StorageContext) (rest.Config, error) {
|
||||
return s.restConfig, nil
|
||||
}
|
||||
|
||||
func (s *simpleClientGetter) UnversionedClient(apiContext *types.APIContext, context types.StorageContext) (rest.Interface, error) {
|
||||
return s.client, nil
|
||||
}
|
||||
|
||||
func (s *simpleClientGetter) APIExtClient(apiContext *types.APIContext, context types.StorageContext) (clientset.Interface, error) {
|
||||
return s.apiExtClient, nil
|
||||
}
|
||||
|
||||
type Store struct {
|
||||
sync.Mutex
|
||||
|
||||
clientGetter ClientGetter
|
||||
storageContext types.StorageContext
|
||||
prefix []string
|
||||
group string
|
||||
version string
|
||||
kind string
|
||||
resourcePlural string
|
||||
authContext map[string]string
|
||||
close context.Context
|
||||
broadcasters map[rest.Interface]*broadcast.Broadcaster
|
||||
}
|
||||
|
||||
func NewProxyStore(ctx context.Context, clientGetter ClientGetter, storageContext types.StorageContext,
|
||||
prefix []string, group, version, kind, resourcePlural string) types.Store {
|
||||
return &errorStore{
|
||||
Store: &Store{
|
||||
clientGetter: clientGetter,
|
||||
storageContext: storageContext,
|
||||
prefix: prefix,
|
||||
group: group,
|
||||
version: version,
|
||||
kind: kind,
|
||||
resourcePlural: resourcePlural,
|
||||
authContext: map[string]string{
|
||||
"apiGroup": group,
|
||||
"resource": resourcePlural,
|
||||
},
|
||||
close: ctx,
|
||||
broadcasters: map[rest.Interface]*broadcast.Broadcaster{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) getUser(apiContext *types.APIContext) string {
|
||||
return apiContext.Request.Header.Get(userAuthHeader)
|
||||
}
|
||||
|
||||
func (s *Store) doAuthed(apiContext *types.APIContext, request *rest.Request) rest.Result {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
logrus.Debug("GET: ", time.Now().Sub(start), s.resourcePlural)
|
||||
}()
|
||||
|
||||
for _, header := range authHeaders {
|
||||
request.SetHeader(header, apiContext.Request.Header[http.CanonicalHeaderKey(header)]...)
|
||||
}
|
||||
return request.Do()
|
||||
}
|
||||
|
||||
func (s *Store) k8sClient(apiContext *types.APIContext) (rest.Interface, error) {
|
||||
return s.clientGetter.UnversionedClient(apiContext, s.storageContext)
|
||||
}
|
||||
|
||||
func (s *Store) ByID(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
|
||||
splitted := strings.Split(strings.TrimSpace(id), ":")
|
||||
validID := false
|
||||
namespaced := schema.Scope == types.NamespaceScope
|
||||
if namespaced {
|
||||
validID = len(splitted) == 2 && len(strings.TrimSpace(splitted[0])) > 0 && len(strings.TrimSpace(splitted[1])) > 0
|
||||
} else {
|
||||
validID = len(splitted) == 1 && len(strings.TrimSpace(splitted[0])) > 0
|
||||
}
|
||||
if !validID {
|
||||
return nil, httperror.NewAPIError(httperror.NotFound, "failed to find resource by id")
|
||||
}
|
||||
|
||||
_, result, err := s.byID(apiContext, schema, id)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *Store) byID(apiContext *types.APIContext, schema *types.Schema, id string) (string, map[string]interface{}, error) {
|
||||
namespace, id := splitID(id)
|
||||
|
||||
k8sClient, err := s.k8sClient(apiContext)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
req := s.common(namespace, k8sClient.Get()).
|
||||
Name(id)
|
||||
|
||||
return s.singleResult(apiContext, schema, req)
|
||||
}
|
||||
|
||||
func (s *Store) Context() types.StorageContext {
|
||||
return s.storageContext
|
||||
}
|
||||
|
||||
func (s *Store) List(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) ([]map[string]interface{}, error) {
|
||||
namespace := getNamespace(apiContext, opt)
|
||||
|
||||
k8sClient, err := s.k8sClient(apiContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := s.common(namespace, k8sClient.Get())
|
||||
|
||||
resultList := &unstructured.UnstructuredList{}
|
||||
start := time.Now()
|
||||
err = req.Do().Into(resultList)
|
||||
logrus.Debug("LIST: ", time.Now().Sub(start), s.resourcePlural)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []map[string]interface{}
|
||||
|
||||
for _, obj := range resultList.Items {
|
||||
result = append(result, s.fromInternal(apiContext, schema, obj.Object))
|
||||
}
|
||||
|
||||
return apiContext.AccessControl.FilterList(apiContext, schema, result, s.authContext), nil
|
||||
}
|
||||
|
||||
func (s *Store) Watch(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) (chan map[string]interface{}, error) {
|
||||
c, err := s.shareWatch(apiContext, schema, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return convert.Chan(c, func(data map[string]interface{}) map[string]interface{} {
|
||||
return apiContext.AccessControl.Filter(apiContext, schema, data, s.authContext)
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Store) realWatch(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) (chan map[string]interface{}, error) {
|
||||
namespace := getNamespace(apiContext, opt)
|
||||
|
||||
k8sClient, err := s.k8sClient(apiContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if watchClient, ok := k8sClient.(restwatch.WatchClient); ok {
|
||||
k8sClient = watchClient.WatchClient()
|
||||
}
|
||||
|
||||
timeout := int64(60 * 60)
|
||||
req := s.common(namespace, k8sClient.Get())
|
||||
req.VersionedParams(&metav1.ListOptions{
|
||||
Watch: true,
|
||||
TimeoutSeconds: &timeout,
|
||||
ResourceVersion: "0",
|
||||
}, metav1.ParameterCodec)
|
||||
|
||||
body, err := req.Stream()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
framer := json.Framer.NewFrameReader(body)
|
||||
decoder := streaming.NewDecoder(framer, &unstructuredDecoder{})
|
||||
watcher := watch.NewStreamWatcher(restclientwatch.NewDecoder(decoder, &unstructuredDecoder{}))
|
||||
|
||||
watchingContext, cancelWatchingContext := context.WithCancel(apiContext.Request.Context())
|
||||
go func() {
|
||||
<-watchingContext.Done()
|
||||
logrus.Debugf("stopping watcher for %s", schema.ID)
|
||||
watcher.Stop()
|
||||
}()
|
||||
|
||||
result := make(chan map[string]interface{})
|
||||
go func() {
|
||||
for event := range watcher.ResultChan() {
|
||||
data := event.Object.(*unstructured.Unstructured)
|
||||
s.fromInternal(apiContext, schema, data.Object)
|
||||
if event.Type == watch.Deleted && data.Object != nil {
|
||||
data.Object[".removed"] = true
|
||||
}
|
||||
result <- data.Object
|
||||
}
|
||||
logrus.Debugf("closing watcher for %s", schema.ID)
|
||||
close(result)
|
||||
cancelWatchingContext()
|
||||
}()
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type unstructuredDecoder struct {
|
||||
}
|
||||
|
||||
func (d *unstructuredDecoder) Decode(data []byte, defaults *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
|
||||
if into == nil {
|
||||
into = &unstructured.Unstructured{}
|
||||
}
|
||||
return into, defaults, ejson.Unmarshal(data, &into)
|
||||
}
|
||||
|
||||
func getNamespace(apiContext *types.APIContext, opt *types.QueryOptions) string {
|
||||
if val, ok := apiContext.SubContext["namespaces"]; ok {
|
||||
return convert.ToString(val)
|
||||
}
|
||||
|
||||
for _, condition := range opt.Conditions {
|
||||
mod := condition.ToCondition().Modifier
|
||||
if condition.Field == "namespaceId" && condition.Value != "" && mod == types.ModifierEQ {
|
||||
return condition.Value
|
||||
}
|
||||
if condition.Field == "namespace" && condition.Value != "" && mod == types.ModifierEQ {
|
||||
return condition.Value
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *Store) Create(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}) (map[string]interface{}, error) {
|
||||
if err := s.toInternal(schema.Mapper, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
namespace, _ := values.GetValueN(data, "metadata", "namespace").(string)
|
||||
|
||||
values.PutValue(data, s.getUser(apiContext), "metadata", "annotations", "field.cattle.io/creatorId")
|
||||
values.PutValue(data, "norman", "metadata", "labels", "cattle.io/creator")
|
||||
|
||||
name, _ := values.GetValueN(data, "metadata", "name").(string)
|
||||
if name == "" {
|
||||
generated, _ := values.GetValueN(data, "metadata", "generateName").(string)
|
||||
if generated == "" {
|
||||
values.PutValue(data, types.GenerateName(schema.ID), "metadata", "name")
|
||||
}
|
||||
}
|
||||
|
||||
k8sClient, err := s.k8sClient(apiContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := s.common(namespace, k8sClient.Post()).
|
||||
Body(&unstructured.Unstructured{
|
||||
Object: data,
|
||||
})
|
||||
|
||||
_, result, err := s.singleResult(apiContext, schema, req)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *Store) toInternal(mapper types.Mapper, data map[string]interface{}) error {
|
||||
if mapper != nil {
|
||||
if err := mapper.ToInternal(data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s.group == "" {
|
||||
data["apiVersion"] = s.version
|
||||
} else {
|
||||
data["apiVersion"] = s.group + "/" + s.version
|
||||
}
|
||||
data["kind"] = s.kind
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) Update(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}, id string) (map[string]interface{}, error) {
|
||||
var (
|
||||
result map[string]interface{}
|
||||
err error
|
||||
)
|
||||
|
||||
k8sClient, err := s.k8sClient(apiContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
namespace, id := splitID(id)
|
||||
if err := s.toInternal(schema.Mapper, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
req := s.common(namespace, k8sClient.Get()).
|
||||
Name(id)
|
||||
|
||||
resourceVersion, existing, rawErr := s.singleResultRaw(apiContext, schema, req)
|
||||
if rawErr != nil {
|
||||
return nil, rawErr
|
||||
}
|
||||
|
||||
existing = merge.APIUpdateMerge(schema.InternalSchema, apiContext.Schemas, existing, data, apiContext.Option("replace") == "true")
|
||||
|
||||
values.PutValue(existing, resourceVersion, "metadata", "resourceVersion")
|
||||
values.PutValue(existing, namespace, "metadata", "namespace")
|
||||
values.PutValue(existing, id, "metadata", "name")
|
||||
|
||||
req = s.common(namespace, k8sClient.Put()).
|
||||
Body(&unstructured.Unstructured{
|
||||
Object: existing,
|
||||
}).
|
||||
Name(id)
|
||||
|
||||
_, result, err = s.singleResult(apiContext, schema, req)
|
||||
if errors.IsConflict(err) {
|
||||
continue
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *Store) Delete(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
|
||||
k8sClient, err := s.k8sClient(apiContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
namespace, name := splitID(id)
|
||||
|
||||
prop := metav1.DeletePropagationBackground
|
||||
req := s.common(namespace, k8sClient.Delete()).
|
||||
Body(&metav1.DeleteOptions{
|
||||
PropagationPolicy: &prop,
|
||||
}).
|
||||
Name(name)
|
||||
|
||||
err = s.doAuthed(apiContext, req).Error()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
obj, err := s.ByID(apiContext, schema, id)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func (s *Store) singleResult(apiContext *types.APIContext, schema *types.Schema, req *rest.Request) (string, map[string]interface{}, error) {
|
||||
version, data, err := s.singleResultRaw(apiContext, schema, req)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
s.fromInternal(apiContext, schema, data)
|
||||
return version, data, nil
|
||||
}
|
||||
|
||||
func (s *Store) singleResultRaw(apiContext *types.APIContext, schema *types.Schema, req *rest.Request) (string, map[string]interface{}, error) {
|
||||
result := &unstructured.Unstructured{}
|
||||
err := s.doAuthed(apiContext, req).Into(result)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return result.GetResourceVersion(), result.Object, nil
|
||||
}
|
||||
|
||||
func splitID(id string) (string, string) {
|
||||
namespace := ""
|
||||
parts := strings.SplitN(id, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
namespace = parts[0]
|
||||
id = parts[1]
|
||||
}
|
||||
|
||||
return namespace, id
|
||||
}
|
||||
|
||||
func (s *Store) common(namespace string, req *rest.Request) *rest.Request {
|
||||
prefix := append([]string{}, s.prefix...)
|
||||
if s.group != "" {
|
||||
prefix = append(prefix, s.group)
|
||||
}
|
||||
prefix = append(prefix, s.version)
|
||||
req.Prefix(prefix...).
|
||||
Resource(s.resourcePlural)
|
||||
|
||||
if namespace != "" {
|
||||
req.Namespace(namespace)
|
||||
}
|
||||
|
||||
return req
|
||||
}
|
||||
|
||||
func (s *Store) fromInternal(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}) map[string]interface{} {
|
||||
if apiContext.Option("export") == "true" {
|
||||
delete(data, "status")
|
||||
}
|
||||
if schema.Mapper != nil {
|
||||
schema.Mapper.FromInternal(data)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
28
vendor/github.com/rancher/norman/store/proxy/share_watch.go
generated
vendored
28
vendor/github.com/rancher/norman/store/proxy/share_watch.go
generated
vendored
@@ -1,28 +0,0 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/pkg/broadcast"
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
func (s *Store) shareWatch(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) (chan map[string]interface{}, error) {
|
||||
client, err := s.clientGetter.UnversionedClient(apiContext, s.Context())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var b *broadcast.Broadcaster
|
||||
s.Lock()
|
||||
b, ok := s.broadcasters[client]
|
||||
if !ok {
|
||||
b = &broadcast.Broadcaster{}
|
||||
s.broadcasters[client] = b
|
||||
}
|
||||
s.Unlock()
|
||||
|
||||
return b.Subscribe(apiContext.Request.Context(), func() (chan map[string]interface{}, error) {
|
||||
newAPIContext := *apiContext
|
||||
newAPIContext.Request = apiContext.Request.WithContext(s.close)
|
||||
return s.realWatch(&newAPIContext, schema, &types.QueryOptions{})
|
||||
})
|
||||
}
|
140
vendor/github.com/rancher/norman/store/schema/schema_store.go
generated
vendored
140
vendor/github.com/rancher/norman/store/schema/schema_store.go
generated
vendored
@@ -1,140 +0,0 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/store/empty"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/definition"
|
||||
"github.com/rancher/norman/types/slice"
|
||||
)
|
||||
|
||||
type Store struct {
|
||||
empty.Store
|
||||
}
|
||||
|
||||
func NewSchemaStore() types.Store {
|
||||
return &Store{}
|
||||
}
|
||||
|
||||
func (s *Store) ByID(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
|
||||
for _, schema := range apiContext.Schemas.SchemasForVersion(*apiContext.Version) {
|
||||
if strings.EqualFold(schema.ID, id) {
|
||||
schemaData := map[string]interface{}{}
|
||||
|
||||
data, err := json.Marshal(s.modifyForAccessControl(apiContext, *schema))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return schemaData, json.Unmarshal(data, &schemaData)
|
||||
}
|
||||
}
|
||||
return nil, httperror.NewAPIError(httperror.NotFound, "no such schema")
|
||||
}
|
||||
|
||||
func (s *Store) modifyForAccessControl(context *types.APIContext, schema types.Schema) *types.Schema {
|
||||
var resourceMethods []string
|
||||
if slice.ContainsString(schema.ResourceMethods, http.MethodPut) && schema.CanUpdate(context) == nil {
|
||||
resourceMethods = append(resourceMethods, http.MethodPut)
|
||||
}
|
||||
if slice.ContainsString(schema.ResourceMethods, http.MethodDelete) && schema.CanDelete(context) == nil {
|
||||
resourceMethods = append(resourceMethods, http.MethodDelete)
|
||||
}
|
||||
if slice.ContainsString(schema.ResourceMethods, http.MethodGet) && schema.CanGet(context) == nil {
|
||||
resourceMethods = append(resourceMethods, http.MethodGet)
|
||||
}
|
||||
|
||||
var collectionMethods []string
|
||||
if slice.ContainsString(schema.CollectionMethods, http.MethodPost) && schema.CanCreate(context) == nil {
|
||||
collectionMethods = append(collectionMethods, http.MethodPost)
|
||||
}
|
||||
if slice.ContainsString(schema.CollectionMethods, http.MethodGet) && schema.CanList(context) == nil {
|
||||
collectionMethods = append(collectionMethods, http.MethodGet)
|
||||
}
|
||||
|
||||
schema.ResourceMethods = resourceMethods
|
||||
schema.CollectionMethods = collectionMethods
|
||||
|
||||
return &schema
|
||||
}
|
||||
|
||||
func (s *Store) Watch(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) (chan map[string]interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *Store) List(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) ([]map[string]interface{}, error) {
|
||||
schemaMap := apiContext.Schemas.SchemasForVersion(*apiContext.Version)
|
||||
schemas := make([]*types.Schema, 0, len(schemaMap))
|
||||
schemaData := make([]map[string]interface{}, 0, len(schemaMap))
|
||||
|
||||
included := map[string]bool{}
|
||||
|
||||
for _, schema := range schemaMap {
|
||||
if included[schema.ID] {
|
||||
continue
|
||||
}
|
||||
|
||||
if schema.CanList(apiContext) == nil || schema.CanGet(apiContext) == nil {
|
||||
schemas = s.addSchema(apiContext, schema, schemaMap, schemas, included)
|
||||
}
|
||||
}
|
||||
|
||||
data, err := json.Marshal(schemas)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return schemaData, json.Unmarshal(data, &schemaData)
|
||||
}
|
||||
|
||||
func (s *Store) addSchema(apiContext *types.APIContext, schema *types.Schema, schemaMap map[string]*types.Schema, schemas []*types.Schema, included map[string]bool) []*types.Schema {
|
||||
included[schema.ID] = true
|
||||
schemas = s.traverseAndAdd(apiContext, schema, schemaMap, schemas, included)
|
||||
schemas = append(schemas, s.modifyForAccessControl(apiContext, *schema))
|
||||
return schemas
|
||||
}
|
||||
|
||||
func (s *Store) traverseAndAdd(apiContext *types.APIContext, schema *types.Schema, schemaMap map[string]*types.Schema, schemas []*types.Schema, included map[string]bool) []*types.Schema {
|
||||
for _, field := range schema.ResourceFields {
|
||||
t := ""
|
||||
subType := field.Type
|
||||
for subType != t {
|
||||
t = subType
|
||||
subType = definition.SubType(t)
|
||||
}
|
||||
|
||||
if refSchema, ok := schemaMap[t]; ok && !included[t] {
|
||||
schemas = s.addSchema(apiContext, refSchema, schemaMap, schemas, included)
|
||||
}
|
||||
}
|
||||
|
||||
for _, action := range schema.ResourceActions {
|
||||
for _, t := range []string{action.Output, action.Input} {
|
||||
if t == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if refSchema, ok := schemaMap[t]; ok && !included[t] {
|
||||
schemas = s.addSchema(apiContext, refSchema, schemaMap, schemas, included)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, action := range schema.CollectionActions {
|
||||
for _, t := range []string{action.Output, action.Input} {
|
||||
if t == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if refSchema, ok := schemaMap[t]; ok && !included[t] {
|
||||
schemas = s.addSchema(apiContext, refSchema, schemaMap, schemas, included)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return schemas
|
||||
}
|
45
vendor/github.com/rancher/norman/store/subtype/subtype_store.go
generated
vendored
45
vendor/github.com/rancher/norman/store/subtype/subtype_store.go
generated
vendored
@@ -1,45 +0,0 @@
|
||||
package subtype
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
)
|
||||
|
||||
type Store struct {
|
||||
types.Store
|
||||
subType string
|
||||
}
|
||||
|
||||
func NewSubTypeStore(subType string, store types.Store) *Store {
|
||||
return &Store{
|
||||
Store: store,
|
||||
subType: subType,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Store) Create(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}) (map[string]interface{}, error) {
|
||||
if data != nil {
|
||||
data["kind"] = p.subType
|
||||
}
|
||||
return p.Store.Create(apiContext, schema, data)
|
||||
}
|
||||
|
||||
func (p *Store) Update(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}, id string) (map[string]interface{}, error) {
|
||||
if data != nil {
|
||||
data["kind"] = convert.Uncapitalize(strings.Replace(p.subType, "namespaced", "", 1))
|
||||
data["type"] = data["kind"]
|
||||
}
|
||||
return p.Store.Update(apiContext, schema, data, id)
|
||||
}
|
||||
|
||||
func (p *Store) List(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) ([]map[string]interface{}, error) {
|
||||
opt.Conditions = append(opt.Conditions, types.NewConditionFromString("type", types.ModifierEQ, p.subType))
|
||||
return p.Store.List(apiContext, schema, opt)
|
||||
}
|
||||
|
||||
func (p *Store) Watch(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) (chan map[string]interface{}, error) {
|
||||
opt.Conditions = append(opt.Conditions, types.NewConditionFromString("type", types.ModifierEQ, p.subType))
|
||||
return p.Store.Watch(apiContext, schema, opt)
|
||||
}
|
122
vendor/github.com/rancher/norman/store/transform/transform.go
generated
vendored
122
vendor/github.com/rancher/norman/store/transform/transform.go
generated
vendored
@@ -1,122 +0,0 @@
|
||||
package transform
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
)
|
||||
|
||||
type TransformerFunc func(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}, opt *types.QueryOptions) (map[string]interface{}, error)
|
||||
|
||||
type ListTransformerFunc func(apiContext *types.APIContext, schema *types.Schema, data []map[string]interface{}, opt *types.QueryOptions) ([]map[string]interface{}, error)
|
||||
|
||||
type StreamTransformerFunc func(apiContext *types.APIContext, schema *types.Schema, data chan map[string]interface{}, opt *types.QueryOptions) (chan map[string]interface{}, error)
|
||||
|
||||
type Store struct {
|
||||
Store types.Store
|
||||
Transformer TransformerFunc
|
||||
ListTransformer ListTransformerFunc
|
||||
StreamTransformer StreamTransformerFunc
|
||||
}
|
||||
|
||||
func (s *Store) Context() types.StorageContext {
|
||||
return s.Store.Context()
|
||||
}
|
||||
|
||||
func (s *Store) ByID(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
|
||||
data, err := s.Store.ByID(apiContext, schema, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.Transformer == nil {
|
||||
return data, nil
|
||||
}
|
||||
obj, err := s.Transformer(apiContext, schema, data, &types.QueryOptions{
|
||||
Options: map[string]string{
|
||||
"ByID": "true",
|
||||
},
|
||||
})
|
||||
if obj == nil && err == nil {
|
||||
return obj, httperror.NewAPIError(httperror.NotFound, fmt.Sprintf("%s not found", id))
|
||||
}
|
||||
return obj, err
|
||||
}
|
||||
|
||||
func (s *Store) Watch(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) (chan map[string]interface{}, error) {
|
||||
c, err := s.Store.Watch(apiContext, schema, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.StreamTransformer != nil {
|
||||
return s.StreamTransformer(apiContext, schema, c, opt)
|
||||
}
|
||||
|
||||
return convert.Chan(c, func(data map[string]interface{}) map[string]interface{} {
|
||||
item, err := s.Transformer(apiContext, schema, data, opt)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return item
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *Store) List(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) ([]map[string]interface{}, error) {
|
||||
data, err := s.Store.List(apiContext, schema, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.ListTransformer != nil {
|
||||
return s.ListTransformer(apiContext, schema, data, opt)
|
||||
}
|
||||
|
||||
if s.Transformer == nil {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
var result []map[string]interface{}
|
||||
for _, item := range data {
|
||||
item, err := s.Transformer(apiContext, schema, item, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if item != nil {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Store) Create(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}) (map[string]interface{}, error) {
|
||||
data, err := s.Store.Create(apiContext, schema, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.Transformer == nil {
|
||||
return data, nil
|
||||
}
|
||||
return s.Transformer(apiContext, schema, data, nil)
|
||||
}
|
||||
|
||||
func (s *Store) Update(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}, id string) (map[string]interface{}, error) {
|
||||
data, err := s.Store.Update(apiContext, schema, data, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.Transformer == nil {
|
||||
return data, nil
|
||||
}
|
||||
return s.Transformer(apiContext, schema, data, nil)
|
||||
}
|
||||
|
||||
func (s *Store) Delete(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
|
||||
obj, err := s.Store.Delete(apiContext, schema, id)
|
||||
if err != nil || obj == nil {
|
||||
return obj, err
|
||||
}
|
||||
return s.Transformer(apiContext, schema, obj, nil)
|
||||
}
|
115
vendor/github.com/rancher/norman/store/wrapper/wrapper.go
generated
vendored
115
vendor/github.com/rancher/norman/store/wrapper/wrapper.go
generated
vendored
@@ -1,115 +0,0 @@
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/httperror"
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
)
|
||||
|
||||
func Wrap(store types.Store) types.Store {
|
||||
return &StoreWrapper{
|
||||
store: store,
|
||||
}
|
||||
}
|
||||
|
||||
type StoreWrapper struct {
|
||||
store types.Store
|
||||
}
|
||||
|
||||
func (s *StoreWrapper) Context() types.StorageContext {
|
||||
return s.store.Context()
|
||||
}
|
||||
|
||||
func (s *StoreWrapper) ByID(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
|
||||
data, err := s.store.ByID(apiContext, schema, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apiContext.FilterObject(&types.QueryOptions{
|
||||
Conditions: apiContext.SubContextAttributeProvider.Query(apiContext, schema),
|
||||
}, schema, data), nil
|
||||
}
|
||||
|
||||
func (s *StoreWrapper) List(apiContext *types.APIContext, schema *types.Schema, opts *types.QueryOptions) ([]map[string]interface{}, error) {
|
||||
opts.Conditions = append(opts.Conditions, apiContext.SubContextAttributeProvider.Query(apiContext, schema)...)
|
||||
data, err := s.store.List(apiContext, schema, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apiContext.FilterList(opts, schema, data), nil
|
||||
}
|
||||
|
||||
func (s *StoreWrapper) Watch(apiContext *types.APIContext, schema *types.Schema, opt *types.QueryOptions) (chan map[string]interface{}, error) {
|
||||
c, err := s.store.Watch(apiContext, schema, opt)
|
||||
if err != nil || c == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return convert.Chan(c, func(data map[string]interface{}) map[string]interface{} {
|
||||
return apiContext.FilterObject(&types.QueryOptions{
|
||||
Conditions: apiContext.SubContextAttributeProvider.Query(apiContext, schema),
|
||||
}, schema, data)
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (s *StoreWrapper) Create(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}) (map[string]interface{}, error) {
|
||||
for key, value := range apiContext.SubContextAttributeProvider.Create(apiContext, schema) {
|
||||
if data == nil {
|
||||
data = map[string]interface{}{}
|
||||
}
|
||||
data[key] = value
|
||||
}
|
||||
|
||||
data, err := s.store.Create(apiContext, schema, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (s *StoreWrapper) Update(apiContext *types.APIContext, schema *types.Schema, data map[string]interface{}, id string) (map[string]interface{}, error) {
|
||||
err := validateGet(apiContext, schema, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err = s.store.Update(apiContext, schema, data, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apiContext.FilterObject(&types.QueryOptions{
|
||||
Conditions: apiContext.SubContextAttributeProvider.Query(apiContext, schema),
|
||||
}, schema, data), nil
|
||||
}
|
||||
|
||||
func (s *StoreWrapper) Delete(apiContext *types.APIContext, schema *types.Schema, id string) (map[string]interface{}, error) {
|
||||
if err := validateGet(apiContext, schema, id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.store.Delete(apiContext, schema, id)
|
||||
}
|
||||
|
||||
func validateGet(apiContext *types.APIContext, schema *types.Schema, id string) error {
|
||||
store := schema.Store
|
||||
if store == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
existing, err := store.ByID(apiContext, schema, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if apiContext.Filter(&types.QueryOptions{
|
||||
Conditions: apiContext.SubContextAttributeProvider.Query(apiContext, schema),
|
||||
}, schema, existing) == nil {
|
||||
return httperror.NewAPIError(httperror.NotFound, "failed to find "+id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
121
vendor/github.com/rancher/norman/types/condition.go
generated
vendored
121
vendor/github.com/rancher/norman/types/condition.go
generated
vendored
@@ -1,121 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/types/convert"
|
||||
)
|
||||
|
||||
var (
|
||||
CondEQ = QueryConditionType{ModifierEQ, 1}
|
||||
CondNE = QueryConditionType{ModifierNE, 1}
|
||||
CondNull = QueryConditionType{ModifierNull, 0}
|
||||
CondNotNull = QueryConditionType{ModifierNotNull, 0}
|
||||
CondIn = QueryConditionType{ModifierIn, -1}
|
||||
CondNotIn = QueryConditionType{ModifierNotIn, -1}
|
||||
CondOr = QueryConditionType{ModifierType("or"), 1}
|
||||
CondAnd = QueryConditionType{ModifierType("and"), 1}
|
||||
|
||||
mods = map[ModifierType]QueryConditionType{
|
||||
CondEQ.Name: CondEQ,
|
||||
CondNE.Name: CondNE,
|
||||
CondNull.Name: CondNull,
|
||||
CondNotNull.Name: CondNotNull,
|
||||
CondIn.Name: CondIn,
|
||||
CondNotIn.Name: CondNotIn,
|
||||
CondOr.Name: CondOr,
|
||||
CondAnd.Name: CondAnd,
|
||||
}
|
||||
)
|
||||
|
||||
type QueryConditionType struct {
|
||||
Name ModifierType
|
||||
Args int
|
||||
}
|
||||
|
||||
type QueryCondition struct {
|
||||
Field string
|
||||
Value string
|
||||
Values map[string]bool
|
||||
conditionType QueryConditionType
|
||||
left, right *QueryCondition
|
||||
}
|
||||
|
||||
func (q *QueryCondition) Valid(schema *Schema, data map[string]interface{}) bool {
|
||||
switch q.conditionType {
|
||||
case CondAnd:
|
||||
if q.left == nil || q.right == nil {
|
||||
return false
|
||||
}
|
||||
return q.left.Valid(schema, data) && q.right.Valid(schema, data)
|
||||
case CondOr:
|
||||
if q.left == nil || q.right == nil {
|
||||
return false
|
||||
}
|
||||
return q.left.Valid(schema, data) || q.right.Valid(schema, data)
|
||||
case CondEQ:
|
||||
return q.Value == convert.ToString(valueOrDefault(schema, data, q))
|
||||
case CondNE:
|
||||
return q.Value != convert.ToString(valueOrDefault(schema, data, q))
|
||||
case CondIn:
|
||||
return q.Values[convert.ToString(valueOrDefault(schema, data, q))]
|
||||
case CondNotIn:
|
||||
return !q.Values[convert.ToString(valueOrDefault(schema, data, q))]
|
||||
case CondNotNull:
|
||||
return convert.ToString(valueOrDefault(schema, data, q)) != ""
|
||||
case CondNull:
|
||||
return convert.ToString(valueOrDefault(schema, data, q)) == ""
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func valueOrDefault(schema *Schema, data map[string]interface{}, q *QueryCondition) interface{} {
|
||||
value := data[q.Field]
|
||||
if value == nil {
|
||||
value = schema.ResourceFields[q.Field].Default
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func (q *QueryCondition) ToCondition() Condition {
|
||||
cond := Condition{
|
||||
Modifier: q.conditionType.Name,
|
||||
}
|
||||
if q.conditionType.Args == 1 {
|
||||
cond.Value = q.Value
|
||||
} else if q.conditionType.Args == -1 {
|
||||
stringValues := []string{}
|
||||
for val := range q.Values {
|
||||
stringValues = append(stringValues, val)
|
||||
}
|
||||
cond.Value = stringValues
|
||||
}
|
||||
|
||||
return cond
|
||||
}
|
||||
|
||||
func ValidMod(mod ModifierType) bool {
|
||||
_, ok := mods[mod]
|
||||
return ok
|
||||
}
|
||||
|
||||
func EQ(key, value string) *QueryCondition {
|
||||
return NewConditionFromString(key, ModifierEQ, value)
|
||||
}
|
||||
|
||||
func NewConditionFromString(field string, mod ModifierType, values ...string) *QueryCondition {
|
||||
q := &QueryCondition{
|
||||
Field: field,
|
||||
conditionType: mods[mod],
|
||||
Values: map[string]bool{},
|
||||
}
|
||||
|
||||
for i, value := range values {
|
||||
if i == 0 {
|
||||
q.Value = value
|
||||
}
|
||||
q.Values[value] = true
|
||||
}
|
||||
|
||||
return q
|
||||
}
|
254
vendor/github.com/rancher/norman/types/convert/convert.go
generated
vendored
254
vendor/github.com/rancher/norman/types/convert/convert.go
generated
vendored
@@ -1,254 +0,0 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
func Chan(c <-chan map[string]interface{}, f func(map[string]interface{}) map[string]interface{}) chan map[string]interface{} {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
result := make(chan map[string]interface{})
|
||||
go func() {
|
||||
for data := range c {
|
||||
modified := f(data)
|
||||
if modified != nil {
|
||||
result <- modified
|
||||
}
|
||||
}
|
||||
close(result)
|
||||
}()
|
||||
return result
|
||||
}
|
||||
|
||||
func Singular(value interface{}) interface{} {
|
||||
if slice, ok := value.([]string); ok {
|
||||
if len(slice) == 0 {
|
||||
return nil
|
||||
}
|
||||
return slice[0]
|
||||
}
|
||||
if slice, ok := value.([]interface{}); ok {
|
||||
if len(slice) == 0 {
|
||||
return nil
|
||||
}
|
||||
return slice[0]
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func ToStringNoTrim(value interface{}) string {
|
||||
if t, ok := value.(time.Time); ok {
|
||||
return t.Format(time.RFC3339)
|
||||
}
|
||||
single := Singular(value)
|
||||
if single == nil {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprint(single)
|
||||
}
|
||||
|
||||
func ToString(value interface{}) string {
|
||||
return strings.TrimSpace(ToStringNoTrim(value))
|
||||
}
|
||||
|
||||
func ToTimestamp(value interface{}) (int64, error) {
|
||||
str := ToString(value)
|
||||
if str == "" {
|
||||
return 0, errors.New("invalid date")
|
||||
}
|
||||
t, err := time.Parse(time.RFC3339, str)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return t.UnixNano() / 1000000, nil
|
||||
}
|
||||
|
||||
func ToBool(value interface{}) bool {
|
||||
value = Singular(value)
|
||||
|
||||
b, ok := value.(bool)
|
||||
if ok {
|
||||
return b
|
||||
}
|
||||
|
||||
str := strings.ToLower(ToString(value))
|
||||
return str == "true" || str == "t" || str == "yes" || str == "y"
|
||||
}
|
||||
|
||||
func ToNumber(value interface{}) (int64, error) {
|
||||
value = Singular(value)
|
||||
|
||||
i, ok := value.(int64)
|
||||
if ok {
|
||||
return i, nil
|
||||
}
|
||||
f, ok := value.(float64)
|
||||
if ok {
|
||||
return int64(f), nil
|
||||
}
|
||||
if n, ok := value.(json.Number); ok {
|
||||
i, err := n.Int64()
|
||||
if err == nil {
|
||||
return i, nil
|
||||
}
|
||||
f, err := n.Float64()
|
||||
return int64(f), err
|
||||
}
|
||||
return strconv.ParseInt(ToString(value), 10, 64)
|
||||
}
|
||||
|
||||
func Capitalize(s string) string {
|
||||
if len(s) <= 1 {
|
||||
return strings.ToUpper(s)
|
||||
}
|
||||
|
||||
return strings.ToUpper(s[:1]) + s[1:]
|
||||
}
|
||||
|
||||
func Uncapitalize(s string) string {
|
||||
if len(s) <= 1 {
|
||||
return strings.ToLower(s)
|
||||
}
|
||||
|
||||
return strings.ToLower(s[:1]) + s[1:]
|
||||
}
|
||||
|
||||
func LowerTitle(input string) string {
|
||||
runes := []rune(input)
|
||||
for i := 0; i < len(runes); i++ {
|
||||
if unicode.IsUpper(runes[i]) &&
|
||||
(i == 0 ||
|
||||
i == len(runes)-1 ||
|
||||
unicode.IsUpper(runes[i+1])) {
|
||||
runes[i] = unicode.ToLower(runes[i])
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
func IsAPIObjectEmpty(v interface{}) bool {
|
||||
if v == nil || v == "" || v == 0 || v == false {
|
||||
return true
|
||||
}
|
||||
if m, ok := v.(map[string]interface{}); ok {
|
||||
return len(m) == 0
|
||||
}
|
||||
if s, ok := v.([]interface{}); ok {
|
||||
return len(s) == 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ToMapInterface(obj interface{}) map[string]interface{} {
|
||||
v, _ := obj.(map[string]interface{})
|
||||
return v
|
||||
}
|
||||
|
||||
func ToInterfaceSlice(obj interface{}) []interface{} {
|
||||
if v, ok := obj.([]interface{}); ok {
|
||||
return v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ToMapSlice(obj interface{}) []map[string]interface{} {
|
||||
if v, ok := obj.([]map[string]interface{}); ok {
|
||||
return v
|
||||
}
|
||||
vs, _ := obj.([]interface{})
|
||||
var result []map[string]interface{}
|
||||
for _, item := range vs {
|
||||
if v, ok := item.(map[string]interface{}); ok {
|
||||
result = append(result, v)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func ToStringSlice(data interface{}) []string {
|
||||
if v, ok := data.([]string); ok {
|
||||
return v
|
||||
}
|
||||
if v, ok := data.([]interface{}); ok {
|
||||
var result []string
|
||||
for _, item := range v {
|
||||
result = append(result, ToString(item))
|
||||
}
|
||||
return result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ToObj(data interface{}, into interface{}) error {
|
||||
bytes, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(bytes, into)
|
||||
}
|
||||
|
||||
func EncodeToMap(obj interface{}) (map[string]interface{}, error) {
|
||||
if m, ok := obj.(map[string]interface{}); ok {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
b, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := map[string]interface{}{}
|
||||
dec := json.NewDecoder(bytes.NewBuffer(b))
|
||||
dec.UseNumber()
|
||||
return result, dec.Decode(&result)
|
||||
}
|
||||
|
||||
func ToJSONKey(str string) string {
|
||||
parts := strings.Split(str, "_")
|
||||
for i := 1; i < len(parts); i++ {
|
||||
parts[i] = strings.Title(parts[i])
|
||||
}
|
||||
|
||||
return strings.Join(parts, "")
|
||||
}
|
||||
|
||||
func ToYAMLKey(str string) string {
|
||||
var result []rune
|
||||
cap := false
|
||||
|
||||
for i, r := range []rune(str) {
|
||||
if i == 0 {
|
||||
if unicode.IsUpper(r) {
|
||||
cap = true
|
||||
}
|
||||
result = append(result, unicode.ToLower(r))
|
||||
continue
|
||||
}
|
||||
|
||||
if unicode.IsUpper(r) {
|
||||
if cap {
|
||||
result = append(result, unicode.ToLower(r))
|
||||
} else {
|
||||
result = append(result, '_', unicode.ToLower(r))
|
||||
}
|
||||
} else {
|
||||
cap = false
|
||||
result = append(result, r)
|
||||
}
|
||||
}
|
||||
|
||||
return string(result)
|
||||
}
|
156
vendor/github.com/rancher/norman/types/convert/merge/merge.go
generated
vendored
156
vendor/github.com/rancher/norman/types/convert/merge/merge.go
generated
vendored
@@ -1,156 +0,0 @@
|
||||
package merge
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
"github.com/rancher/norman/types/definition"
|
||||
)
|
||||
|
||||
func APIUpdateMerge(schema *types.Schema, schemas *types.Schemas, dest, src map[string]interface{}, replace bool) map[string]interface{} {
|
||||
result := UpdateMerge(schema, schemas, dest, src, replace)
|
||||
if s, ok := dest["status"]; ok {
|
||||
result["status"] = s
|
||||
}
|
||||
if m, ok := dest["metadata"]; ok {
|
||||
result["metadata"] = mergeMetadata(convert.ToMapInterface(m), convert.ToMapInterface(src["metadata"]))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func UpdateMerge(schema *types.Schema, schemas *types.Schemas, dest, src map[string]interface{}, replace bool) map[string]interface{} {
|
||||
return mergeMaps("", nil, schema, schemas, replace, dest, src)
|
||||
}
|
||||
|
||||
func isProtected(k string) bool {
|
||||
if !strings.Contains(k, "cattle.io/") || (isField(k) && k != "field.cattle.io/creatorId") {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isField(k string) bool {
|
||||
return strings.HasPrefix(k, "field.cattle.io/")
|
||||
}
|
||||
|
||||
func mergeProtected(dest, src map[string]interface{}) map[string]interface{} {
|
||||
if src == nil {
|
||||
return dest
|
||||
}
|
||||
|
||||
result := copyMap(dest)
|
||||
|
||||
for k, v := range src {
|
||||
if isProtected(k) {
|
||||
continue
|
||||
}
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
for k := range dest {
|
||||
if isProtected(k) || isField(k) {
|
||||
continue
|
||||
}
|
||||
if _, ok := src[k]; !ok {
|
||||
delete(result, k)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func mergeMetadata(dest map[string]interface{}, src map[string]interface{}) map[string]interface{} {
|
||||
result := copyMap(dest)
|
||||
|
||||
labels := convert.ToMapInterface(dest["labels"])
|
||||
srcLabels := convert.ToMapInterface(src["labels"])
|
||||
labels = mergeProtected(labels, srcLabels)
|
||||
|
||||
annotations := convert.ToMapInterface(dest["annotations"])
|
||||
srcAnnotation := convert.ToMapInterface(src["annotations"])
|
||||
annotations = mergeProtected(annotations, srcAnnotation)
|
||||
|
||||
result["labels"] = labels
|
||||
result["annotations"] = annotations
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func merge(field, fieldType string, parentSchema, schema *types.Schema, schemas *types.Schemas, replace bool, dest, src interface{}) interface{} {
|
||||
if isMap(field, schema, schemas) {
|
||||
return src
|
||||
}
|
||||
|
||||
sm, smOk := src.(map[string]interface{})
|
||||
dm, dmOk := dest.(map[string]interface{})
|
||||
if smOk && dmOk {
|
||||
fieldType, fieldSchema := getSchema(field, fieldType, parentSchema, schema, schemas)
|
||||
return mergeMaps(fieldType, schema, fieldSchema, schemas, replace, dm, sm)
|
||||
}
|
||||
return src
|
||||
}
|
||||
|
||||
func getSchema(field, parentFieldType string, parentSchema, schema *types.Schema, schemas *types.Schemas) (string, *types.Schema) {
|
||||
if schema == nil {
|
||||
if definition.IsMapType(parentFieldType) && parentSchema != nil {
|
||||
subType := definition.SubType(parentFieldType)
|
||||
s := schemas.Schema(&parentSchema.Version, subType)
|
||||
if s != nil && s.InternalSchema != nil {
|
||||
s = s.InternalSchema
|
||||
}
|
||||
return subType, s
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
fieldType := schema.ResourceFields[field].Type
|
||||
s := schemas.Schema(&schema.Version, fieldType)
|
||||
if s != nil && s.InternalSchema != nil {
|
||||
return fieldType, s.InternalSchema
|
||||
}
|
||||
return fieldType, s
|
||||
}
|
||||
|
||||
func isMap(field string, schema *types.Schema, schemas *types.Schemas) bool {
|
||||
if schema == nil {
|
||||
return false
|
||||
}
|
||||
f := schema.ResourceFields[field]
|
||||
mapType := definition.IsMapType(f.Type)
|
||||
if !mapType {
|
||||
return false
|
||||
}
|
||||
|
||||
subType := definition.SubType(f.Type)
|
||||
return schemas.Schema(&schema.Version, subType) == nil
|
||||
}
|
||||
|
||||
func mergeMaps(fieldType string, parentSchema, schema *types.Schema, schemas *types.Schemas, replace bool, dest map[string]interface{}, src map[string]interface{}) map[string]interface{} {
|
||||
result := copyMapReplace(schema, dest, replace)
|
||||
for k, v := range src {
|
||||
result[k] = merge(k, fieldType, parentSchema, schema, schemas, replace, dest[k], v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func copyMap(src map[string]interface{}) map[string]interface{} {
|
||||
result := map[string]interface{}{}
|
||||
for k, v := range src {
|
||||
result[k] = v
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func copyMapReplace(schema *types.Schema, src map[string]interface{}, replace bool) map[string]interface{} {
|
||||
result := map[string]interface{}{}
|
||||
for k, v := range src {
|
||||
if replace && schema != nil {
|
||||
f := schema.ResourceFields[k]
|
||||
if f.Update {
|
||||
continue
|
||||
}
|
||||
}
|
||||
result[k] = v
|
||||
}
|
||||
return result
|
||||
}
|
11
vendor/github.com/rancher/norman/types/convert/ref.go
generated
vendored
11
vendor/github.com/rancher/norman/types/convert/ref.go
generated
vendored
@@ -1,11 +0,0 @@
|
||||
package convert
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ToReference(typeName string) string {
|
||||
return fmt.Sprintf("reference[%s]", typeName)
|
||||
}
|
||||
|
||||
func ToFullReference(path, typeName string) string {
|
||||
return fmt.Sprintf("reference[%s/schemas/%s]", path, typeName)
|
||||
}
|
29
vendor/github.com/rancher/norman/types/convert/schemaconvert/schema.go
generated
vendored
29
vendor/github.com/rancher/norman/types/convert/schemaconvert/schema.go
generated
vendored
@@ -1,29 +0,0 @@
|
||||
package schemaconvert
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
)
|
||||
|
||||
func InternalToInternal(from interface{}, fromSchema *types.Schema, toSchema *types.Schema, target interface{}) error {
|
||||
data, err := convert.EncodeToMap(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fromSchema.Mapper.FromInternal(data)
|
||||
if err := toSchema.Mapper.ToInternal(data); err != nil {
|
||||
return err
|
||||
}
|
||||
return convert.ToObj(data, target)
|
||||
}
|
||||
|
||||
func ToInternal(from interface{}, schema *types.Schema, target interface{}) error {
|
||||
data, err := convert.EncodeToMap(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := schema.Mapper.ToInternal(data); err != nil {
|
||||
return err
|
||||
}
|
||||
return convert.ToObj(data, target)
|
||||
}
|
45
vendor/github.com/rancher/norman/types/convert/transform.go
generated
vendored
45
vendor/github.com/rancher/norman/types/convert/transform.go
generated
vendored
@@ -1,45 +0,0 @@
|
||||
package convert
|
||||
|
||||
const (
|
||||
ArrayKey = "{ARRAY}"
|
||||
MapKey = "{MAP}"
|
||||
)
|
||||
|
||||
type TransformerFunc func(input interface{}) interface{}
|
||||
|
||||
func Transform(data map[string]interface{}, path []string, transformer TransformerFunc) {
|
||||
if len(path) == 0 || len(data) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
key := path[0]
|
||||
path = path[1:]
|
||||
value := data[key]
|
||||
|
||||
if value == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(path) == 0 {
|
||||
data[key] = transformer(value)
|
||||
return
|
||||
}
|
||||
|
||||
// You can't end a path with ARRAY/MAP. Not supported right now
|
||||
if len(path) > 1 {
|
||||
switch path[0] {
|
||||
case ArrayKey:
|
||||
for _, valueMap := range ToMapSlice(value) {
|
||||
Transform(valueMap, path[1:], transformer)
|
||||
}
|
||||
return
|
||||
case MapKey:
|
||||
for _, valueMap := range ToMapInterface(value) {
|
||||
Transform(ToMapInterface(valueMap), path[1:], transformer)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Transform(ToMapInterface(value), path, transformer)
|
||||
}
|
18
vendor/github.com/rancher/norman/types/convert/value_set_string.go
generated
vendored
18
vendor/github.com/rancher/norman/types/convert/value_set_string.go
generated
vendored
@@ -1,18 +0,0 @@
|
||||
package convert
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
splitRegexp = regexp.MustCompile("[[:space:]]*,[[:space:]]*")
|
||||
)
|
||||
|
||||
func ToValuesSlice(value string) []string {
|
||||
value = strings.TrimSpace(value)
|
||||
if strings.HasPrefix(value, "(") && strings.HasSuffix(value, ")") {
|
||||
return splitRegexp.Split(value[1:len(value)-1], -1)
|
||||
}
|
||||
return []string{value}
|
||||
}
|
45
vendor/github.com/rancher/norman/types/definition/definition.go
generated
vendored
45
vendor/github.com/rancher/norman/types/definition/definition.go
generated
vendored
@@ -1,45 +0,0 @@
|
||||
package definition
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/norman/types/convert"
|
||||
)
|
||||
|
||||
func IsMapType(fieldType string) bool {
|
||||
return strings.HasPrefix(fieldType, "map[") && strings.HasSuffix(fieldType, "]")
|
||||
}
|
||||
|
||||
func IsArrayType(fieldType string) bool {
|
||||
return strings.HasPrefix(fieldType, "array[") && strings.HasSuffix(fieldType, "]")
|
||||
}
|
||||
|
||||
func IsReferenceType(fieldType string) bool {
|
||||
return strings.HasPrefix(fieldType, "reference[") && strings.HasSuffix(fieldType, "]")
|
||||
}
|
||||
|
||||
func HasReferenceType(fieldType string) bool {
|
||||
return strings.Contains(fieldType, "reference[")
|
||||
}
|
||||
|
||||
func SubType(fieldType string) string {
|
||||
i := strings.Index(fieldType, "[")
|
||||
if i <= 0 || i >= len(fieldType)-1 {
|
||||
return fieldType
|
||||
}
|
||||
|
||||
return fieldType[i+1 : len(fieldType)-1]
|
||||
}
|
||||
|
||||
func GetType(data map[string]interface{}) string {
|
||||
return GetShortTypeFromFull(GetFullType(data))
|
||||
}
|
||||
|
||||
func GetShortTypeFromFull(fullType string) string {
|
||||
parts := strings.Split(fullType, "/")
|
||||
return parts[len(parts)-1]
|
||||
}
|
||||
|
||||
func GetFullType(data map[string]interface{}) string {
|
||||
return convert.ToString(data["type"])
|
||||
}
|
32
vendor/github.com/rancher/norman/types/encoder.go
generated
vendored
32
vendor/github.com/rancher/norman/types/encoder.go
generated
vendored
@@ -1,32 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"regexp"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
)
|
||||
|
||||
var (
|
||||
commenter = regexp.MustCompile("(?m)^( *)zzz#\\((.*)\\)\\((.*)\\)([a-z]+.*):(.*)")
|
||||
)
|
||||
|
||||
func JSONEncoder(writer io.Writer, v interface{}) error {
|
||||
return json.NewEncoder(writer).Encode(v)
|
||||
}
|
||||
|
||||
func YAMLEncoder(writer io.Writer, v interface{}) error {
|
||||
data, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf, err := yaml.JSONToYAML(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//buf = commenter.ReplaceAll(buf, []byte("${1}# ${2}type: ${3}\n${1}# ${4}:${5}"))
|
||||
buf = commenter.ReplaceAll(buf, []byte("${1}# ${4}:${5}"))
|
||||
_, err = writer.Write(buf)
|
||||
return err
|
||||
}
|
23
vendor/github.com/rancher/norman/types/factory/schemas.go
generated
vendored
23
vendor/github.com/rancher/norman/types/factory/schemas.go
generated
vendored
@@ -1,23 +0,0 @@
|
||||
package factory
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/mapper"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func Schemas(version *types.APIVersion) *types.Schemas {
|
||||
s := types.NewSchemas()
|
||||
s.DefaultMappers = func() []types.Mapper {
|
||||
return []types.Mapper{
|
||||
mapper.NewObject(),
|
||||
}
|
||||
}
|
||||
s.DefaultPostMappers = func() []types.Mapper {
|
||||
return []types.Mapper{
|
||||
&mapper.RenameReference{},
|
||||
}
|
||||
}
|
||||
s.AddMapperForType(version, v1.ObjectMeta{}, mapper.NewMetadataMapper())
|
||||
return s
|
||||
}
|
19
vendor/github.com/rancher/norman/types/id.go
generated
vendored
19
vendor/github.com/rancher/norman/types/id.go
generated
vendored
@@ -1,19 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
utilrand "k8s.io/apimachinery/pkg/util/rand"
|
||||
)
|
||||
|
||||
var (
|
||||
lowerChars = regexp.MustCompile("[a-z]+")
|
||||
)
|
||||
|
||||
func GenerateName(typeName string) string {
|
||||
base := typeName[0:1] + lowerChars.ReplaceAllString(typeName[1:], "")
|
||||
last := utilrand.String(5)
|
||||
return fmt.Sprintf("%s-%s", strings.ToLower(base), last)
|
||||
}
|
178
vendor/github.com/rancher/norman/types/mapper.go
generated
vendored
178
vendor/github.com/rancher/norman/types/mapper.go
generated
vendored
@@ -1,178 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/rancher/norman/types/convert"
|
||||
"github.com/rancher/norman/types/definition"
|
||||
"github.com/rancher/norman/types/values"
|
||||
)
|
||||
|
||||
type Mapper interface {
|
||||
FromInternal(data map[string]interface{})
|
||||
ToInternal(data map[string]interface{}) error
|
||||
ModifySchema(schema *Schema, schemas *Schemas) error
|
||||
}
|
||||
|
||||
type Mappers []Mapper
|
||||
|
||||
func (m Mappers) FromInternal(data map[string]interface{}) {
|
||||
for _, mapper := range m {
|
||||
mapper.FromInternal(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (m Mappers) ToInternal(data map[string]interface{}) error {
|
||||
var errors []error
|
||||
for i := len(m) - 1; i >= 0; i-- {
|
||||
errors = append(errors, m[i].ToInternal(data))
|
||||
}
|
||||
return NewErrors(errors...)
|
||||
}
|
||||
|
||||
func (m Mappers) ModifySchema(schema *Schema, schemas *Schemas) error {
|
||||
for _, mapper := range m {
|
||||
if err := mapper.ModifySchema(schema, schemas); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type typeMapper struct {
|
||||
Mappers []Mapper
|
||||
root bool
|
||||
typeName string
|
||||
subSchemas map[string]*Schema
|
||||
subArraySchemas map[string]*Schema
|
||||
subMapSchemas map[string]*Schema
|
||||
}
|
||||
|
||||
func (t *typeMapper) FromInternal(data map[string]interface{}) {
|
||||
name, _ := values.GetValueN(data, "metadata", "name").(string)
|
||||
namespace, _ := values.GetValueN(data, "metadata", "namespace").(string)
|
||||
|
||||
for fieldName, schema := range t.subSchemas {
|
||||
if schema.Mapper == nil {
|
||||
continue
|
||||
}
|
||||
fieldData, _ := data[fieldName].(map[string]interface{})
|
||||
schema.Mapper.FromInternal(fieldData)
|
||||
}
|
||||
|
||||
for fieldName, schema := range t.subMapSchemas {
|
||||
if schema.Mapper == nil {
|
||||
continue
|
||||
}
|
||||
datas, _ := data[fieldName].(map[string]interface{})
|
||||
for _, fieldData := range datas {
|
||||
mapFieldData, _ := fieldData.(map[string]interface{})
|
||||
schema.Mapper.FromInternal(mapFieldData)
|
||||
}
|
||||
}
|
||||
|
||||
for fieldName, schema := range t.subArraySchemas {
|
||||
if schema.Mapper == nil {
|
||||
continue
|
||||
}
|
||||
datas, _ := data[fieldName].([]interface{})
|
||||
for _, fieldData := range datas {
|
||||
mapFieldData, _ := fieldData.(map[string]interface{})
|
||||
schema.Mapper.FromInternal(mapFieldData)
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := data["type"]; !ok && data != nil {
|
||||
data["type"] = t.typeName
|
||||
}
|
||||
|
||||
Mappers(t.Mappers).FromInternal(data)
|
||||
|
||||
if data != nil && t.root {
|
||||
if _, ok := data["id"]; ok {
|
||||
if namespace != "" {
|
||||
id, _ := data["id"].(string)
|
||||
data["id"] = namespace + ":" + id
|
||||
}
|
||||
} else {
|
||||
if name != "" {
|
||||
if namespace == "" {
|
||||
data["id"] = name
|
||||
} else {
|
||||
data["id"] = namespace + ":" + name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := data["type"]; !ok && data != nil {
|
||||
if _, ok := data["id"]; ok {
|
||||
data["type"] = t.typeName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *typeMapper) ToInternal(data map[string]interface{}) error {
|
||||
errors := Errors{}
|
||||
errors.Add(Mappers(t.Mappers).ToInternal(data))
|
||||
|
||||
for fieldName, schema := range t.subArraySchemas {
|
||||
if schema.Mapper == nil {
|
||||
continue
|
||||
}
|
||||
datas, _ := data[fieldName].([]interface{})
|
||||
for _, fieldData := range datas {
|
||||
errors.Add(schema.Mapper.ToInternal(convert.ToMapInterface(fieldData)))
|
||||
}
|
||||
}
|
||||
|
||||
for fieldName, schema := range t.subMapSchemas {
|
||||
if schema.Mapper == nil {
|
||||
continue
|
||||
}
|
||||
datas, _ := data[fieldName].(map[string]interface{})
|
||||
for _, fieldData := range datas {
|
||||
errors.Add(schema.Mapper.ToInternal(convert.ToMapInterface(fieldData)))
|
||||
}
|
||||
}
|
||||
|
||||
for fieldName, schema := range t.subSchemas {
|
||||
if schema.Mapper == nil {
|
||||
continue
|
||||
}
|
||||
fieldData, _ := data[fieldName].(map[string]interface{})
|
||||
errors.Add(schema.Mapper.ToInternal(fieldData))
|
||||
}
|
||||
|
||||
return errors.Err()
|
||||
}
|
||||
|
||||
func (t *typeMapper) ModifySchema(schema *Schema, schemas *Schemas) error {
|
||||
t.subSchemas = map[string]*Schema{}
|
||||
t.subArraySchemas = map[string]*Schema{}
|
||||
t.subMapSchemas = map[string]*Schema{}
|
||||
t.typeName = fmt.Sprintf("%s/schemas/%s", schema.Version.Path, schema.ID)
|
||||
|
||||
mapperSchema := schema
|
||||
if schema.InternalSchema != nil {
|
||||
mapperSchema = schema.InternalSchema
|
||||
}
|
||||
for name, field := range mapperSchema.ResourceFields {
|
||||
fieldType := field.Type
|
||||
targetMap := t.subSchemas
|
||||
if definition.IsArrayType(fieldType) {
|
||||
fieldType = definition.SubType(fieldType)
|
||||
targetMap = t.subArraySchemas
|
||||
} else if definition.IsMapType(fieldType) {
|
||||
fieldType = definition.SubType(fieldType)
|
||||
targetMap = t.subMapSchemas
|
||||
}
|
||||
|
||||
schema := schemas.Schema(&schema.Version, fieldType)
|
||||
if schema != nil {
|
||||
targetMap[name] = schema
|
||||
}
|
||||
}
|
||||
|
||||
return Mappers(t.Mappers).ModifySchema(schema, schemas)
|
||||
}
|
38
vendor/github.com/rancher/norman/types/mapper/access.go
generated
vendored
38
vendor/github.com/rancher/norman/types/mapper/access.go
generated
vendored
@@ -1,38 +0,0 @@
|
||||
package mapper
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
type Access struct {
|
||||
Fields map[string]string
|
||||
Optional bool
|
||||
}
|
||||
|
||||
func (e Access) FromInternal(data map[string]interface{}) {
|
||||
}
|
||||
|
||||
func (e Access) ToInternal(data map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e Access) ModifySchema(schema *types.Schema, schemas *types.Schemas) error {
|
||||
for name, access := range e.Fields {
|
||||
if err := ValidateField(name, schema); err != nil {
|
||||
if e.Optional {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
field := schema.ResourceFields[name]
|
||||
field.Create = strings.Contains(access, "c")
|
||||
field.Update = strings.Contains(access, "u")
|
||||
field.WriteOnly = strings.Contains(access, "o")
|
||||
|
||||
schema.ResourceFields[name] = field
|
||||
}
|
||||
return nil
|
||||
}
|
58
vendor/github.com/rancher/norman/types/mapper/annotation_field.go
generated
vendored
58
vendor/github.com/rancher/norman/types/mapper/annotation_field.go
generated
vendored
@@ -1,58 +0,0 @@
|
||||
package mapper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
"github.com/rancher/norman/types/values"
|
||||
)
|
||||
|
||||
type AnnotationField struct {
|
||||
Field string
|
||||
Object bool
|
||||
List bool
|
||||
IgnoreDefinition bool
|
||||
}
|
||||
|
||||
func (e AnnotationField) FromInternal(data map[string]interface{}) {
|
||||
v, ok := values.RemoveValue(data, "annotations", "field.cattle.io/"+e.Field)
|
||||
if ok {
|
||||
if e.Object {
|
||||
data := map[string]interface{}{}
|
||||
//ignore error
|
||||
if err := json.Unmarshal([]byte(convert.ToString(v)), &data); err == nil {
|
||||
v = data
|
||||
}
|
||||
}
|
||||
if e.List {
|
||||
var data []interface{}
|
||||
if err := json.Unmarshal([]byte(convert.ToString(v)), &data); err == nil {
|
||||
v = data
|
||||
}
|
||||
}
|
||||
|
||||
data[e.Field] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (e AnnotationField) ToInternal(data map[string]interface{}) error {
|
||||
v, ok := data[e.Field]
|
||||
if ok {
|
||||
if e.Object || e.List {
|
||||
if bytes, err := json.Marshal(v); err == nil {
|
||||
v = string(bytes)
|
||||
}
|
||||
}
|
||||
values.PutValue(data, convert.ToString(v), "annotations", "field.cattle.io/"+e.Field)
|
||||
}
|
||||
values.RemoveValue(data, e.Field)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e AnnotationField) ModifySchema(schema *types.Schema, schemas *types.Schemas) error {
|
||||
if e.IgnoreDefinition {
|
||||
return nil
|
||||
}
|
||||
return ValidateField(e.Field, schema)
|
||||
}
|
35
vendor/github.com/rancher/norman/types/mapper/apigroup.go
generated
vendored
35
vendor/github.com/rancher/norman/types/mapper/apigroup.go
generated
vendored
@@ -1,35 +0,0 @@
|
||||
package mapper
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
)
|
||||
|
||||
type APIGroup struct {
|
||||
apiVersion string
|
||||
kind string
|
||||
}
|
||||
|
||||
func (a *APIGroup) FromInternal(data map[string]interface{}) {
|
||||
}
|
||||
|
||||
func (a *APIGroup) ToInternal(data map[string]interface{}) error {
|
||||
_, ok := data["apiVersion"]
|
||||
if !ok && data != nil {
|
||||
data["apiVersion"] = a.apiVersion
|
||||
}
|
||||
|
||||
_, ok = data["kind"]
|
||||
if !ok && data != nil {
|
||||
data["kind"] = a.kind
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *APIGroup) ModifySchema(schema *types.Schema, schemas *types.Schemas) error {
|
||||
a.apiVersion = schema.Version.Group + "/" + schema.Version.Version
|
||||
a.kind = convert.Capitalize(schema.ID)
|
||||
|
||||
return nil
|
||||
}
|
63
vendor/github.com/rancher/norman/types/mapper/base64.go
generated
vendored
63
vendor/github.com/rancher/norman/types/mapper/base64.go
generated
vendored
@@ -1,63 +0,0 @@
|
||||
package mapper
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
"github.com/rancher/norman/types/convert"
|
||||
"github.com/rancher/norman/types/values"
|
||||
)
|
||||
|
||||
type Base64 struct {
|
||||
Field string
|
||||
IgnoreDefinition bool
|
||||
Separator string
|
||||
}
|
||||
|
||||
func (m Base64) FromInternal(data map[string]interface{}) {
|
||||
if v, ok := values.RemoveValue(data, strings.Split(m.Field, m.getSep())...); ok {
|
||||
str := convert.ToString(v)
|
||||
if str == "" {
|
||||
return
|
||||
}
|
||||
|
||||
newData, err := base64.StdEncoding.DecodeString(str)
|
||||
if err != nil {
|
||||
log.Errorf("failed to base64 decode data")
|
||||
}
|
||||
|
||||
values.PutValue(data, string(newData), strings.Split(m.Field, m.getSep())...)
|
||||
}
|
||||
}
|
||||
|
||||
func (m Base64) ToInternal(data map[string]interface{}) error {
|
||||
if v, ok := values.RemoveValue(data, strings.Split(m.Field, m.getSep())...); ok {
|
||||
str := convert.ToString(v)
|
||||
if str == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
newData := base64.StdEncoding.EncodeToString([]byte(str))
|
||||
values.PutValue(data, newData, strings.Split(m.Field, m.getSep())...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Base64) ModifySchema(s *types.Schema, schemas *types.Schemas) error {
|
||||
if !m.IgnoreDefinition {
|
||||
if err := ValidateField(m.Field, s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Base64) getSep() string {
|
||||
if m.Separator == "" {
|
||||
return "/"
|
||||
}
|
||||
return m.Separator
|
||||
}
|
48
vendor/github.com/rancher/norman/types/mapper/batchmove.go
generated
vendored
48
vendor/github.com/rancher/norman/types/mapper/batchmove.go
generated
vendored
@@ -1,48 +0,0 @@
|
||||
package mapper
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
type BatchMove struct {
|
||||
From []string
|
||||
To string
|
||||
DestDefined bool
|
||||
NoDeleteFromField bool
|
||||
moves []Move
|
||||
}
|
||||
|
||||
func (b *BatchMove) FromInternal(data map[string]interface{}) {
|
||||
for _, m := range b.moves {
|
||||
m.FromInternal(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BatchMove) ToInternal(data map[string]interface{}) error {
|
||||
errors := types.Errors{}
|
||||
for i := len(b.moves) - 1; i >= 0; i-- {
|
||||
errors.Add(b.moves[i].ToInternal(data))
|
||||
}
|
||||
return errors.Err()
|
||||
}
|
||||
|
||||
func (b *BatchMove) ModifySchema(s *types.Schema, schemas *types.Schemas) error {
|
||||
for _, from := range b.From {
|
||||
b.moves = append(b.moves, Move{
|
||||
From: from,
|
||||
To: path.Join(b.To, from),
|
||||
DestDefined: b.DestDefined,
|
||||
NoDeleteFromField: b.NoDeleteFromField,
|
||||
})
|
||||
}
|
||||
|
||||
for _, m := range b.moves {
|
||||
if err := m.ModifySchema(s, schemas); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
28
vendor/github.com/rancher/norman/types/mapper/changetype.go
generated
vendored
28
vendor/github.com/rancher/norman/types/mapper/changetype.go
generated
vendored
@@ -1,28 +0,0 @@
|
||||
package mapper
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
type ChangeType struct {
|
||||
Field string
|
||||
Type string
|
||||
}
|
||||
|
||||
func (c ChangeType) FromInternal(data map[string]interface{}) {
|
||||
}
|
||||
|
||||
func (c ChangeType) ToInternal(data map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c ChangeType) ModifySchema(schema *types.Schema, schemas *types.Schemas) error {
|
||||
if err := ValidateField(c.Field, schema); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f := schema.ResourceFields[c.Field]
|
||||
f.Type = c.Type
|
||||
schema.ResourceFields[c.Field] = f
|
||||
return nil
|
||||
}
|
15
vendor/github.com/rancher/norman/types/mapper/check.go
generated
vendored
15
vendor/github.com/rancher/norman/types/mapper/check.go
generated
vendored
@@ -1,15 +0,0 @@
|
||||
package mapper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
func ValidateField(field string, schema *types.Schema) error {
|
||||
if _, ok := schema.ResourceFields[field]; !ok {
|
||||
return fmt.Errorf("field %s missing on schema %s", field, schema.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
28
vendor/github.com/rancher/norman/types/mapper/condition.go
generated
vendored
28
vendor/github.com/rancher/norman/types/mapper/condition.go
generated
vendored
@@ -1,28 +0,0 @@
|
||||
package mapper
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
type Condition struct {
|
||||
Field string
|
||||
Value interface{}
|
||||
Mapper types.Mapper
|
||||
}
|
||||
|
||||
func (m Condition) FromInternal(data map[string]interface{}) {
|
||||
if data[m.Field] == m.Value {
|
||||
m.Mapper.FromInternal(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (m Condition) ToInternal(data map[string]interface{}) error {
|
||||
if data[m.Field] == m.Value {
|
||||
return m.Mapper.ToInternal(data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Condition) ModifySchema(s *types.Schema, schemas *types.Schemas) error {
|
||||
return m.Mapper.ModifySchema(s, schemas)
|
||||
}
|
44
vendor/github.com/rancher/norman/types/mapper/copy.go
generated
vendored
44
vendor/github.com/rancher/norman/types/mapper/copy.go
generated
vendored
@@ -1,44 +0,0 @@
|
||||
package mapper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
type Copy struct {
|
||||
From, To string
|
||||
}
|
||||
|
||||
func (c Copy) FromInternal(data map[string]interface{}) {
|
||||
if data == nil {
|
||||
return
|
||||
}
|
||||
v, ok := data[c.From]
|
||||
if ok {
|
||||
data[c.To] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (c Copy) ToInternal(data map[string]interface{}) error {
|
||||
if data == nil {
|
||||
return nil
|
||||
}
|
||||
t, tok := data[c.To]
|
||||
_, fok := data[c.From]
|
||||
if tok && !fok {
|
||||
data[c.From] = t
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Copy) ModifySchema(s *types.Schema, schemas *types.Schemas) error {
|
||||
f, ok := s.ResourceFields[c.From]
|
||||
if !ok {
|
||||
return fmt.Errorf("field %s missing on schema %s", c.From, s.ID)
|
||||
}
|
||||
|
||||
s.ResourceFields[c.To] = f
|
||||
return nil
|
||||
}
|
29
vendor/github.com/rancher/norman/types/mapper/display_name.go
generated
vendored
29
vendor/github.com/rancher/norman/types/mapper/display_name.go
generated
vendored
@@ -1,29 +0,0 @@
|
||||
package mapper
|
||||
|
||||
import (
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
var displayNameMappers = types.Mappers{
|
||||
&Move{From: "name", To: "id"},
|
||||
&Move{From: "displayName", To: "name"},
|
||||
Access{Fields: map[string]string{
|
||||
"id": "",
|
||||
"name": "cru",
|
||||
}},
|
||||
}
|
||||
|
||||
type DisplayName struct {
|
||||
}
|
||||
|
||||
func (d DisplayName) FromInternal(data map[string]interface{}) {
|
||||
displayNameMappers.FromInternal(data)
|
||||
}
|
||||
|
||||
func (d DisplayName) ToInternal(data map[string]interface{}) error {
|
||||
return displayNameMappers.ToInternal(data)
|
||||
}
|
||||
|
||||
func (d DisplayName) ModifySchema(schema *types.Schema, schemas *types.Schemas) error {
|
||||
return displayNameMappers.ModifySchema(schema, schemas)
|
||||
}
|
31
vendor/github.com/rancher/norman/types/mapper/drop.go
generated
vendored
31
vendor/github.com/rancher/norman/types/mapper/drop.go
generated
vendored
@@ -1,31 +0,0 @@
|
||||
package mapper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/rancher/norman/types"
|
||||
)
|
||||
|
||||
type Drop struct {
|
||||
Field string
|
||||
IgnoreDefinition bool
|
||||
}
|
||||
|
||||
func (d Drop) FromInternal(data map[string]interface{}) {
|
||||
delete(data, d.Field)
|
||||
}
|
||||
|
||||
func (d Drop) ToInternal(data map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d Drop) ModifySchema(schema *types.Schema, schemas *types.Schemas) error {
|
||||
if _, ok := schema.ResourceFields[d.Field]; !ok {
|
||||
if !d.IgnoreDefinition {
|
||||
return fmt.Errorf("can not drop missing field %s on %s", d.Field, schema.ID)
|
||||
}
|
||||
}
|
||||
|
||||
delete(schema.ResourceFields, d.Field)
|
||||
return nil
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user