refactor(serving): KnClient interface for single point of cluster access (#134)

* fix(serving): Remove hardcoded GVK and look it up from schema

Fixes #133.

* chore(serving): Add test for "WaitForService()"

* refactor(service): Add listRoutes() to client + generic way for list options

* chore(serving): Fixing rebase conflicts
This commit is contained in:
Roland Huß 2019-07-08 19:08:34 +02:00 committed by Knative Prow Robot
parent 0cbc4e1b18
commit 98184eafbc
44 changed files with 1745 additions and 617 deletions

25
go.mod
View File

@ -2,25 +2,23 @@ module github.com/knative/client
require (
github.com/cpuguy83/go-md2man v1.0.10 // indirect
github.com/evanphx/json-patch v4.2.0+incompatible // indirect
github.com/evanphx/json-patch v4.5.0+incompatible // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/gogo/protobuf v1.2.1 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/golang/protobuf v1.3.1 // indirect
github.com/google/btree v1.0.0 // indirect
github.com/google/go-cmp v0.3.0 // indirect
github.com/google/go-containerregistry v0.0.0-20190503220729-1c6c7f61e8a5 // indirect
github.com/google/go-containerregistry v0.0.0-20190623150931-ca8b66cb1b79 // indirect
github.com/google/gofuzz v1.0.0 // indirect
github.com/google/licenseclassifier v0.0.0-20190501212618-47b603fe1b8c // indirect
github.com/googleapis/gnostic v0.2.0 // indirect
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect
github.com/googleapis/gnostic v0.3.0 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/hashicorp/golang-lru v0.5.1 // indirect
github.com/imdario/mergo v0.3.7 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/json-iterator/go v1.1.6 // indirect
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 // indirect
github.com/knative/build v0.6.0 // indirect
github.com/knative/pkg v0.0.0-20190518173526-34792a92cec2
github.com/knative/build v0.7.0 // indirect
github.com/knative/pkg v0.0.0-20190617142447-13b093adc272
github.com/knative/serving v0.6.0
github.com/knative/test-infra v0.0.0-20190702025031-91d37e4abc30
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a // indirect
@ -31,20 +29,15 @@ require (
github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.3
github.com/spf13/viper v1.3.1
github.com/stretchr/objx v0.2.0 // indirect
go.uber.org/atomic v1.4.0 // indirect
go.uber.org/multierr v1.1.0 // indirect
go.uber.org/zap v1.10.0 // indirect
golang.org/x/net v0.0.0-20190514140710-3ec191127204 // indirect
golang.org/x/oauth2 v0.0.0-20190517181255-950ef44c6e07 // indirect
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 // indirect
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
golang.org/x/tools v0.0.0-20190628034336-212fb13d595e // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gotest.tools v2.2.0+incompatible
k8s.io/api v0.0.0-20190226173710-145d52631d00
k8s.io/apimachinery v0.0.0-20190221084156-01f179d85dbc
k8s.io/cli-runtime v0.0.0-20190325194458-f2b4781c3ae1
k8s.io/client-go v0.0.0-20190226174127-78295b709ec6
k8s.io/kube-openapi v0.0.0-20190510232812-a01b7d5d6c22 // indirect
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 // indirect
sigs.k8s.io/yaml v1.1.0
)

19
go.sum
View File

@ -47,6 +47,8 @@ github.com/evanphx/json-patch v4.1.0+incompatible h1:K1MDoo4AZ4wU0GIU/fPmtZg7Vpz
github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 h1:ZktWZesgun21uEDrwW7iEV1zPCGQldM2atlJZ3TdvVM=
@ -93,6 +95,8 @@ github.com/google/go-containerregistry v0.0.0-20190424210018-7d6d1d3cd63b h1:3Kv
github.com/google/go-containerregistry v0.0.0-20190424210018-7d6d1d3cd63b/go.mod h1:yZAFP63pRshzrEYLXLGPmUt0Ay+2zdjmMN1loCnRLUk=
github.com/google/go-containerregistry v0.0.0-20190503220729-1c6c7f61e8a5 h1:wXZCVr9/0naJbZhAzKDzj/sgnduf8qn9ldjkI/CND9k=
github.com/google/go-containerregistry v0.0.0-20190503220729-1c6c7f61e8a5/go.mod h1:yZAFP63pRshzrEYLXLGPmUt0Ay+2zdjmMN1loCnRLUk=
github.com/google/go-containerregistry v0.0.0-20190623150931-ca8b66cb1b79 h1:iObax0KHGJG3zG66UocaycSspWe9P7OT0SA9dL759sM=
github.com/google/go-containerregistry v0.0.0-20190623150931-ca8b66cb1b79/go.mod h1:yZAFP63pRshzrEYLXLGPmUt0Ay+2zdjmMN1loCnRLUk=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@ -105,10 +109,14 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g=
github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0=
github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc h1:f8eY6cV/x1x+HLjOp4r72s/31/V2aTUtg5oKRRPf8/Q=
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.8.5 h1:2+KSC78XiO6Qy0hIjfc1OD9H+hsaJdJlb8Kqsd41CTE=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
@ -137,10 +145,14 @@ github.com/knative/build v0.5.0 h1:q2W4+BmT3jEOSOXZ44UXndJUAHLWUd20QtMQAFGWzsU=
github.com/knative/build v0.5.0/go.mod h1:/sU74ZQkwlYA5FwYDJhYTy61i/Kn+5eWfln2jDbw3Qo=
github.com/knative/build v0.6.0 h1:tAhqGbRL3/wFOfEc4srO8XDNV8DxUE+z6TzKW0JPWsE=
github.com/knative/build v0.6.0/go.mod h1:/sU74ZQkwlYA5FwYDJhYTy61i/Kn+5eWfln2jDbw3Qo=
github.com/knative/build v0.7.0 h1:YqqiShED6wILhPRZyUJjTX2B6OgbgEqWe1WNrAcDclw=
github.com/knative/build v0.7.0/go.mod h1:/sU74ZQkwlYA5FwYDJhYTy61i/Kn+5eWfln2jDbw3Qo=
github.com/knative/pkg v0.0.0-20190329155329-916205998db9 h1:DnGe2nwEq+ibifGZt4HoD4akmX1K9Tcx3CjNwFpSZow=
github.com/knative/pkg v0.0.0-20190329155329-916205998db9/go.mod h1:7Ijfhw7rfB+H9VtosIsDYvZQ+qYTz7auK3fHW/5z4ww=
github.com/knative/pkg v0.0.0-20190518173526-34792a92cec2 h1:OA4f02os85BMZbC6DxNL5gbGHRxPgjQW+IDENES7QFc=
github.com/knative/pkg v0.0.0-20190518173526-34792a92cec2/go.mod h1:7Ijfhw7rfB+H9VtosIsDYvZQ+qYTz7auK3fHW/5z4ww=
github.com/knative/pkg v0.0.0-20190617142447-13b093adc272 h1:8reWGJv6V0UUy8XFclP1uHEypLKPGvN9wEk4uhQVGAg=
github.com/knative/pkg v0.0.0-20190617142447-13b093adc272/go.mod h1:7Ijfhw7rfB+H9VtosIsDYvZQ+qYTz7auK3fHW/5z4ww=
github.com/knative/serving v0.5.2 h1:jsmeIN7B6oDHrK0jmtFRf7hWWr+KrjXVHuArK8jo5Nw=
github.com/knative/serving v0.5.2/go.mod h1:ljvMfwQy2qanaM/8xnBSK4Mz3Vv2NawC2fo5kFRJS1A=
github.com/knative/serving v0.6.0 h1:2SOr1jAvrUPO1y0mJvpiTe3bJTSMd2tKXflmHCM0MAA=
@ -290,6 +302,8 @@ golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6 h1:FP8hkuE6yUEaJnK7O2eTuejKW
golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190514140710-3ec191127204 h1:4yG6GqBtw9C+UrLp6s2wtSniayy/Vd/3F7ffLE427XI=
golang.org/x/net v0.0.0-20190514140710-3ec191127204/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -297,6 +311,8 @@ golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190517181255-950ef44c6e07 h1:XC1K3wNjuz44KaI+cj85C9TW85w/46RH7J+DTXNH5Wk=
golang.org/x/oauth2 v0.0.0-20190517181255-950ef44c6e07/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
@ -385,7 +401,10 @@ k8s.io/kube-openapi v0.0.0-20190418160015-6b3d3b2d5666 h1:hlzz2EvLPcefAcG/j0tOZp
k8s.io/kube-openapi v0.0.0-20190418160015-6b3d3b2d5666/go.mod h1:jqYp7BKXW0Jl+F1dWXBieUmcHKMPpGHGWA0uqfpOZZ4=
k8s.io/kube-openapi v0.0.0-20190510232812-a01b7d5d6c22 h1:f0BTap/vrgs21vVbJ1ySdsNtcivpA1x4ut6Wla9HKKw=
k8s.io/kube-openapi v0.0.0-20190510232812-a01b7d5d6c22/go.mod h1:iU+ZGYsNlvU9XKUSso6SQfKTCCw7lFduMZy26Mgr2Fw=
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 h1:5sW+fEHvlJI3Ngolx30CmubFulwH28DhKjGf70Xmtco=
k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4=
sigs.k8s.io/structured-merge-diff v0.0.0-20181214233322-d43a45b8663b/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/structured-merge-diff v0.0.0-20190426204423-ea680f03cc65/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@ -40,7 +40,7 @@ func AddNamespaceFlags(flags *pflag.FlagSet, allowAll bool) {
}
// GetNamespace returns namespace from command specified by flag
func (kn *KnParams) GetNamespace(cmd *cobra.Command) (string, error) {
func (params *KnParams) GetNamespace(cmd *cobra.Command) (string, error) {
namespace := cmd.Flag("namespace").Value.String()
// check value of all-namepace only if its defined
if cmd.Flags().Lookup("all-namespaces") != nil {
@ -55,10 +55,21 @@ func (kn *KnParams) GetNamespace(cmd *cobra.Command) (string, error) {
// if all-namepaces=False or namespace not given, use default namespace
if namespace == "" {
var err error
namespace, err = kn.NamespaceFactory()
namespace, err = params.CurrentNamespace()
if err != nil {
return "", err
}
}
return namespace, nil
}
func (params *KnParams) CurrentNamespace() (string, error) {
if params.fixedCurrentNamespace != "" {
return params.fixedCurrentNamespace, nil
}
if params.ClientConfig == nil {
params.ClientConfig = params.GetClientConfig()
}
name, _, err := params.ClientConfig.Namespace()
return name, err
}

View File

@ -37,7 +37,7 @@ func TestGetNamespaceSample(t *testing.T) {
expectedNamespace := "test1"
testCmd.SetArgs([]string{"--namespace", expectedNamespace})
testCmd.Execute()
kp := &KnParams{NamespaceFactory: func() (string, error) { return FakeNamespace, nil }}
kp := &KnParams{fixedCurrentNamespace: FakeNamespace}
actualNamespace, err := kp.GetNamespace(testCmd)
if err != nil {
t.Fatal(err)
@ -52,7 +52,7 @@ func TestGetNamespaceDefault(t *testing.T) {
testCmd := testCommandGenerator(true)
expectedNamespace := "current"
testCmd.Execute()
kp := &KnParams{NamespaceFactory: func() (string, error) { return FakeNamespace, nil }}
kp := &KnParams{fixedCurrentNamespace: FakeNamespace}
actualNamespace, err := kp.GetNamespace(testCmd)
if err != nil {
t.Fatal(err)
@ -70,7 +70,7 @@ func TestGetNamespaceAllNamespacesSet(t *testing.T) {
sampleNamespace := "test1"
testCmd.SetArgs([]string{"--namespace", sampleNamespace, "--all-namespaces"})
testCmd.Execute()
kp := &KnParams{NamespaceFactory: func() (string, error) { return FakeNamespace, nil }}
kp := &KnParams{fixedCurrentNamespace: FakeNamespace}
actualNamespace, err := kp.GetNamespace(testCmd)
if err != nil {
t.Fatal(err)
@ -87,7 +87,7 @@ func TestGetNamespaceDefaultAllNamespacesUnset(t *testing.T) {
expectedNamespace := ""
testCmd.SetArgs([]string{"--all-namespaces"})
testCmd.Execute()
kp := &KnParams{NamespaceFactory: func() (string, error) { return FakeNamespace, nil }}
kp := &KnParams{fixedCurrentNamespace: FakeNamespace}
actualNamespace, err := kp.GetNamespace(testCmd)
if err != nil {
t.Fatal(err)
@ -103,7 +103,7 @@ func TestGetNamespaceAllNamespacesNotDefined(t *testing.T) {
expectedNamespace := "test1"
testCmd.SetArgs([]string{"--namespace", expectedNamespace})
testCmd.Execute()
kp := &KnParams{NamespaceFactory: func() (string, error) { return FakeNamespace, nil }}
kp := &KnParams{fixedCurrentNamespace: FakeNamespace}
actualNamespace, err := kp.GetNamespace(testCmd)
if err != nil {
t.Fatal(err)

View File

@ -18,9 +18,9 @@ import (
"errors"
"fmt"
"github.com/knative/client/pkg/kn/commands"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/knative/client/pkg/kn/commands"
)
// NewRevisionDeleteCommand represent 'revision delete' command
@ -35,18 +35,15 @@ func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command {
if len(args) != 1 {
return errors.New("'revision delete' requires the revision name given as single argument")
}
client, err := p.ServingFactory()
if err != nil {
return err
}
namespace, err := p.GetNamespace(cmd)
if err != nil {
return err
}
err = client.Revisions(namespace).Delete(
args[0],
&metav1.DeleteOptions{},
)
client, err := p.NewClient(namespace)
if err != nil {
return err
}
err = client.DeleteRevision(args[0])
if err != nil {
return err
}

View File

@ -19,8 +19,6 @@ import (
"github.com/knative/client/pkg/kn/commands"
"github.com/spf13/cobra"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
)
@ -34,16 +32,16 @@ func NewRevisionDescribeCommand(p *commands.KnParams) *cobra.Command {
return errors.New("requires the revision name.")
}
client, err := p.ServingFactory()
if err != nil {
return err
}
namespace, err := p.GetNamespace(cmd)
if err != nil {
return err
}
revision, err := client.Revisions(namespace).Get(args[0], v1.GetOptions{})
client, err := p.NewClient(namespace)
if err != nil {
return err
}
revision, err := client.GetRevision(args[0])
if err != nil {
return err
}
@ -52,10 +50,7 @@ func NewRevisionDescribeCommand(p *commands.KnParams) *cobra.Command {
if err != nil {
return err
}
revision.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{
Group: "knative.dev",
Version: "v1alpha1",
Kind: "Revision"})
err = printer.PrintObj(revision, cmd.OutOrStdout())
if err != nil {
return err

View File

@ -17,12 +17,11 @@ package revision
import (
"fmt"
"github.com/knative/client/pkg/kn/commands"
"github.com/knative/serving/pkg/apis/serving"
"github.com/knative/serving/pkg/apis/serving/v1alpha1"
"github.com/spf13/cobra"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/knative/client/pkg/kn/commands"
v1alpha12 "github.com/knative/client/pkg/serving/v1alpha1"
)
// NewRevisionListCommand represents 'kn revision list' command
@ -40,42 +39,47 @@ func NewRevisionListCommand(p *commands.KnParams) *cobra.Command {
# List revisions for a service 'svc1' in namespace 'myapp'
kn revision list -s svc1 -n myapp`,
RunE: func(cmd *cobra.Command, args []string) error {
client, err := p.ServingFactory()
if err != nil {
return err
}
namespace, err := p.GetNamespace(cmd)
if err != nil {
return err
}
listOptions := v1.ListOptions{}
if cmd.Flags().Changed("service") {
service := cmd.Flag("service").Value.String()
// Ensure requested service exist
_, err := client.Services(namespace).Get(service, v1.GetOptions{})
if err != nil {
return err
}
listOptions.LabelSelector = labels.Set(
map[string]string{serving.ServiceLabelKey: service}).String()
}
revision, err := client.Revisions(namespace).List(listOptions)
client, err := p.NewClient(namespace)
if err != nil {
return err
}
if len(revision.Items) == 0 {
fmt.Fprintf(cmd.OutOrStdout(), "No resources found.\n")
return nil
var revisionList *v1alpha1.RevisionList
if cmd.Flags().Changed("service") {
serviceName := cmd.Flag("service").Value.String()
// Verify that service exists
_, err := client.GetService(serviceName)
if err != nil {
return err
}
revisionList, err = client.ListRevisions(v1alpha12.WithService(serviceName))
if err != nil {
return err
}
if len(revisionList.Items) == 0 {
fmt.Fprintf(cmd.OutOrStdout(), "No revisions found for service '%s'.\n", serviceName)
return nil
}
} else {
revisionList, err = client.ListRevisions()
if err != nil {
return err
}
if len(revisionList.Items) == 0 {
fmt.Fprintf(cmd.OutOrStdout(), "No revisions found.\n")
return nil
}
}
revision.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{
Group: "knative.dev",
Version: "v1alpha1",
Kind: "revision"})
printer, err := revisionListFlags.ToPrinter()
if err != nil {
return err
}
err = printer.PrintObj(revision, cmd.OutOrStdout())
err = printer.PrintObj(revisionList, cmd.OutOrStdout())
if err != nil {
return err
}

View File

@ -18,14 +18,15 @@ import (
"strings"
"testing"
"github.com/knative/client/pkg/kn/commands"
"github.com/knative/client/pkg/util"
serving "github.com/knative/serving/pkg/apis/serving"
v1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1"
"github.com/knative/serving/pkg/apis/serving"
"github.com/knative/serving/pkg/apis/serving/v1alpha1"
"gotest.tools/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
client_testing "k8s.io/client-go/testing"
"github.com/knative/client/pkg/kn/commands"
"github.com/knative/client/pkg/util"
)
func fakeRevisionList(args []string, response *v1alpha1.RevisionList) (action client_testing.Action, output []string, err error) {
@ -55,7 +56,7 @@ func TestRevisionListEmpty(t *testing.T) {
t.Errorf("No action")
} else if !action.Matches("list", "revisions") {
t.Errorf("Bad action %v", action)
} else if output[0] != "No resources found." {
} else if output[0] != "No revisions found." {
t.Errorf("Bad output %s", output[0])
}
}
@ -115,11 +116,11 @@ func TestRevisionListForService(t *testing.T) {
}
if action == nil {
t.Errorf("No action")
} else if !action.Matches("list", "revisions") {
t.Errorf("Bad action %v", action)
} else if !strings.Contains(output[0], "No resources found.") {
t.Errorf("Bad output %s", output[0])
}
if !action.Matches("list", "revisions") {
t.Errorf("Bad action %v", action)
}
assert.Assert(t, util.ContainsAll(output[0], "No", "revisions", "svc3"), "no revisions")
}
func createMockRevisionWithParams(name, svcName string) *v1alpha1.Revision {

View File

@ -18,10 +18,10 @@ import (
"fmt"
"github.com/knative/client/pkg/kn/commands"
v1alpha12 "github.com/knative/client/pkg/serving/v1alpha1"
"github.com/knative/serving/pkg/apis/serving/v1alpha1"
"github.com/spf13/cobra"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// NewrouteListCommand represents 'kn route list' command
@ -40,41 +40,37 @@ func NewRouteListCommand(p *commands.KnParams) *cobra.Command {
# List all routes in yaml format
kn route list -o yaml`,
RunE: func(cmd *cobra.Command, args []string) error {
client, err := p.ServingFactory()
if err != nil {
return err
}
namespace, err := p.GetNamespace(cmd)
if err != nil {
return err
}
var listOptions v1.ListOptions
switch len(args) {
case 0:
listOptions = v1.ListOptions{}
case 1:
listOptions.FieldSelector = fields.Set(map[string]string{"metadata.name": args[0]}).String()
default:
return fmt.Errorf("'kn route list' accepts maximum 1 argument.")
}
route, err := client.Routes(namespace).List(listOptions)
client, err := p.NewClient(namespace)
if err != nil {
return err
}
if len(route.Items) == 0 {
var routeList *v1alpha1.RouteList
switch len(args) {
case 0:
routeList, err = client.ListRoutes()
case 1:
routeList, err = client.ListRoutes(v1alpha12.WithName(args[0]))
default:
return fmt.Errorf("'kn route list' accepts maximum 1 argument.")
}
if err != nil {
return err
}
if len(routeList.Items) == 0 {
fmt.Fprintf(cmd.OutOrStdout(), "No resources found.\n")
return nil
}
route.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{
Group: "knative.dev",
Version: "v1alpha1",
Kind: "route",
})
printer, err := routeListFlags.ToPrinter()
if err != nil {
return err
}
err = printer.PrintObj(route, cmd.OutOrStdout())
err = printer.PrintObj(routeList, cmd.OutOrStdout())
if err != nil {
return err
}

View File

@ -21,14 +21,14 @@ import (
"time"
"github.com/knative/client/pkg/kn/commands"
"github.com/knative/client/pkg/serving/v1alpha1"
serving_v1alpha1_api "github.com/knative/serving/pkg/apis/serving/v1alpha1"
serving_v1alpha1_client "github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
api_errors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command {
@ -79,7 +79,7 @@ func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command {
return err
}
client, err := p.ServingFactory()
client, err := p.NewClient(namespace)
if err != nil {
return err
}
@ -104,8 +104,7 @@ func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command {
}
if !waitFlags.Async {
waitForReady := newServiceWaitForReady(client, namespace)
err := waitForReady.Wait(name, time.Duration(waitFlags.TimeoutInSeconds)*time.Second, cmd.OutOrStdout())
err := client.WaitForService(name, time.Duration(waitFlags.TimeoutInSeconds)*time.Second, cmd.OutOrStdout())
if err != nil {
return err
}
@ -121,8 +120,8 @@ func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command {
return serviceCreateCommand
}
func createService(client serving_v1alpha1_client.ServingV1alpha1Interface, service *serving_v1alpha1_api.Service, namespace string, out io.Writer) error {
_, err := client.Services(namespace).Create(service)
func createService(client v1alpha1.KnClient, service *serving_v1alpha1_api.Service, namespace string, out io.Writer) error {
err := client.CreateService(service)
if err != nil {
return err
}
@ -130,13 +129,13 @@ func createService(client serving_v1alpha1_client.ServingV1alpha1Interface, serv
return nil
}
func replaceService(client serving_v1alpha1_client.ServingV1alpha1Interface, service *serving_v1alpha1_api.Service, namespace string, out io.Writer) error {
existingService, err := client.Services(namespace).Get(service.Name, v1.GetOptions{})
func replaceService(client v1alpha1.KnClient, service *serving_v1alpha1_api.Service, namespace string, out io.Writer) error {
existingService, err := client.GetService(service.Name)
if err != nil {
return err
}
service.ResourceVersion = existingService.ResourceVersion
_, err = client.Services(namespace).Update(service)
err = client.UpdateService(service)
if err != nil {
return err
}
@ -144,8 +143,8 @@ func replaceService(client serving_v1alpha1_client.ServingV1alpha1Interface, ser
return nil
}
func serviceExists(client serving_v1alpha1_client.ServingV1alpha1Interface, name string, namespace string) (bool, error) {
_, err := client.Services(namespace).Get(name, v1.GetOptions{})
func serviceExists(client v1alpha1.KnClient, name string, namespace string) (bool, error) {
_, err := client.GetService(name)
if api_errors.IsNotFound(err) {
return false, nil
}
@ -184,8 +183,8 @@ func constructService(cmd *cobra.Command, editFlags ConfigurationEditFlags, name
return &service, nil
}
func showUrl(client serving_v1alpha1_client.ServingV1alpha1Interface, serviceName string, namespace string, out io.Writer) error {
service, err := client.Services(namespace).Get(serviceName, v1.GetOptions{})
func showUrl(client v1alpha1.KnClient, serviceName string, namespace string, out io.Writer) error {
service, err := client.GetService(serviceName)
if err != nil {
return fmt.Errorf("cannot fetch service '%s' in namespace '%s' for extracting the URL: %v", serviceName, namespace, err)
}

View File

@ -86,7 +86,7 @@ func fakeServiceCreate(args []string, withExistingService bool, sync bool) (
if !found {
return true, nil, errors.New("no field selector on metadata.name found")
}
w := wait.NewFakeWatch(getServiceEvents())
w := wait.NewFakeWatch(getServiceEvents("test-service"))
w.Start()
return true, w, nil
})
@ -105,11 +105,11 @@ func fakeServiceCreate(args []string, withExistingService bool, sync bool) (
return
}
func getServiceEvents() []watch.Event {
func getServiceEvents(name string) []watch.Event {
return []watch.Event{
{watch.Added, wait.CreateTestServiceWithConditions(corev1.ConditionUnknown, corev1.ConditionUnknown, "")},
{watch.Modified, wait.CreateTestServiceWithConditions(corev1.ConditionUnknown, corev1.ConditionTrue, "")},
{watch.Modified, wait.CreateTestServiceWithConditions(corev1.ConditionTrue, corev1.ConditionTrue, "")},
{watch.Added, wait.CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionUnknown, "")},
{watch.Modified, wait.CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionTrue, "")},
{watch.Modified, wait.CreateTestServiceWithConditions(name, corev1.ConditionTrue, corev1.ConditionTrue, "")},
}
}

View File

@ -20,7 +20,6 @@ import (
"github.com/knative/client/pkg/kn/commands"
"github.com/spf13/cobra"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// NewServiceDeleteCommand represent 'service delete' command
@ -39,19 +38,16 @@ func NewServiceDeleteCommand(p *commands.KnParams) *cobra.Command {
if len(args) != 1 {
return errors.New("requires the service name.")
}
client, err := p.ServingFactory()
if err != nil {
return err
}
namespace, err := p.GetNamespace(cmd)
if err != nil {
return err
}
client, err := p.NewClient(namespace)
if err != nil {
return err
}
err = client.Services(namespace).Delete(
args[0],
&v1.DeleteOptions{},
)
err = client.DeleteService(args[0])
if err != nil {
return err
}

View File

@ -19,8 +19,6 @@ import (
"github.com/knative/client/pkg/kn/commands"
"github.com/spf13/cobra"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
)
@ -33,16 +31,17 @@ func NewServiceDescribeCommand(p *commands.KnParams) *cobra.Command {
if len(args) < 1 {
return errors.New("requires the service name.")
}
client, err := p.ServingFactory()
if err != nil {
return err
}
namespace, err := p.GetNamespace(cmd)
if err != nil {
return err
}
describeService, err := client.Services(namespace).Get(args[0], v1.GetOptions{})
client, err := p.NewClient(namespace)
if err != nil {
return err
}
describeService, err := client.GetService(args[0])
if err != nil {
return err
}
@ -51,10 +50,6 @@ func NewServiceDescribeCommand(p *commands.KnParams) *cobra.Command {
if err != nil {
return err
}
describeService.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{
Group: "knative.dev",
Version: "v1alpha1",
Kind: "Service"})
err = printer.PrintObj(describeService, cmd.OutOrStdout())
if err != nil {
return err

View File

@ -19,8 +19,6 @@ import (
"github.com/knative/client/pkg/kn/commands"
"github.com/spf13/cobra"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// NewServiceListCommand represents 'kn service list' command
@ -31,33 +29,28 @@ func NewServiceListCommand(p *commands.KnParams) *cobra.Command {
Use: "list",
Short: "List available services.",
RunE: func(cmd *cobra.Command, args []string) error {
client, err := p.ServingFactory()
if err != nil {
return err
}
namespace, err := p.GetNamespace(cmd)
if err != nil {
return err
}
service, err := client.Services(namespace).List(v1.ListOptions{})
client, err := p.NewClient(namespace)
if err != nil {
return err
}
if len(service.Items) == 0 {
serviceList, err := client.ListServices()
if err != nil {
return err
}
if len(serviceList.Items) == 0 {
fmt.Fprintf(cmd.OutOrStdout(), "No resources found.\n")
return nil
}
service.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{
Group: "knative.dev",
Version: "v1alpha1",
Kind: "Service"})
printer, err := serviceListFlags.ToPrinter()
if err != nil {
return err
}
err = printer.PrintObj(service, cmd.OutOrStdout())
err = printer.PrintObj(serviceList, cmd.OutOrStdout())
if err != nil {
return err
}

View File

@ -21,7 +21,7 @@ import (
"github.com/knative/client/pkg/kn/commands"
"github.com/knative/client/pkg/util"
duckv1beta1 "github.com/knative/pkg/apis/duck/v1beta1"
v1alpha1 "github.com/knative/serving/pkg/apis/serving/v1alpha1"
"github.com/knative/serving/pkg/apis/serving/v1alpha1"
"gotest.tools/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"

View File

@ -20,7 +20,6 @@ import (
"github.com/knative/client/pkg/kn/commands"
"github.com/spf13/cobra"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func NewServiceUpdateCommand(p *commands.KnParams) *cobra.Command {
@ -48,12 +47,12 @@ func NewServiceUpdateCommand(p *commands.KnParams) *cobra.Command {
return err
}
client, err := p.ServingFactory()
client, err := p.NewClient(namespace)
if err != nil {
return err
}
service, err := client.Services(namespace).Get(args[0], v1.GetOptions{})
service, err := client.GetService(args[0])
if err != nil {
return err
}
@ -64,7 +63,7 @@ func NewServiceUpdateCommand(p *commands.KnParams) *cobra.Command {
return err
}
_, err = client.Services(namespace).Update(service)
err = client.UpdateService(service)
if err != nil {
return err
}

View File

@ -18,7 +18,7 @@ import (
"bytes"
"flag"
serving "github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1"
"github.com/knative/client/pkg/serving/v1alpha1"
"github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake"
"github.com/spf13/cobra"
client_testing "k8s.io/client-go/testing"
@ -30,8 +30,10 @@ func CreateTestKnCommand(cmd *cobra.Command, knParams *KnParams) (*cobra.Command
buf := new(bytes.Buffer)
fakeServing := &fake.FakeServingV1alpha1{&client_testing.Fake{}}
knParams.Output = buf
knParams.ServingFactory = func() (serving.ServingV1alpha1Interface, error) { return fakeServing, nil }
knParams.NamespaceFactory = func() (string, error) { return FakeNamespace, nil }
knParams.NewClient = func(namespace string) (v1alpha1.KnClient, error) {
return v1alpha1.NewKnServingClient(fakeServing, namespace), nil
}
knParams.fixedCurrentNamespace = FakeNamespace
knCommand := newKnCommand(cmd, knParams)
return knCommand, fakeServing, buf
}

View File

@ -17,7 +17,9 @@ package commands
import (
"io"
serving "github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1"
serving_kn_v1alpha1 "github.com/knative/client/pkg/serving/v1alpha1"
serving_v1alpha1_client "github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1"
"k8s.io/client-go/tools/clientcmd"
)
@ -26,51 +28,45 @@ var CfgFile string
// Parameters for creating commands. Useful for inserting mocks for testing.
type KnParams struct {
Output io.Writer
ServingFactory func() (serving.ServingV1alpha1Interface, error)
NamespaceFactory func() (string, error)
Output io.Writer
KubeCfgPath string
ClientConfig clientcmd.ClientConfig
NewClient func(namespace string) (serving_kn_v1alpha1.KnClient, error)
// Set this if you want to nail down the namespace
fixedCurrentNamespace string
}
func (c *KnParams) Initialize() {
if c.ServingFactory == nil {
c.ServingFactory = c.GetConfig
}
if c.NamespaceFactory == nil {
c.NamespaceFactory = c.CurrentNamespace
func (params *KnParams) Initialize() {
if params.NewClient == nil {
params.NewClient = params.newClient
}
}
func (c *KnParams) CurrentNamespace() (string, error) {
if c.ClientConfig == nil {
c.ClientConfig = c.GetClientConfig()
func (params *KnParams) newClient(namespace string) (serving_kn_v1alpha1.KnClient, error) {
client, err := params.GetConfig()
if err != nil {
return nil, err
}
name, _, err := c.ClientConfig.Namespace()
return name, err
return serving_kn_v1alpha1.NewKnServingClient(client, namespace), nil
}
func (c *KnParams) GetConfig() (serving.ServingV1alpha1Interface, error) {
if c.ClientConfig == nil {
c.ClientConfig = c.GetClientConfig()
func (params *KnParams) GetConfig() (serving_v1alpha1_client.ServingV1alpha1Interface, error) {
if params.ClientConfig == nil {
params.ClientConfig = params.GetClientConfig()
}
var err error
config, err := c.ClientConfig.ClientConfig()
config, err := params.ClientConfig.ClientConfig()
if err != nil {
return nil, err
}
client, err := serving.NewForConfig(config)
if err != nil {
return nil, err
}
return client, nil
return serving_v1alpha1_client.NewForConfig(config)
}
func (c *KnParams) GetClientConfig() clientcmd.ClientConfig {
func (params *KnParams) GetClientConfig() clientcmd.ClientConfig {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
if len(c.KubeCfgPath) > 0 {
loadingRules.ExplicitPath = c.KubeCfgPath
if len(params.KubeCfgPath) > 0 {
loadingRules.ExplicitPath = params.KubeCfgPath
}
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
}

View File

@ -25,13 +25,16 @@ import (
"github.com/knative/client/pkg/kn/commands/revision"
"github.com/knative/client/pkg/kn/commands/route"
"github.com/knative/client/pkg/kn/commands/service"
homedir "github.com/mitchellh/go-homedir"
"github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
)
var cfgFile string
var kubeCfgFile string
// NewKnCommand creates new rootCmd represents the base command when called without any subcommands
func NewKnCommand(params ...commands.KnParams) *cobra.Command {
var p *commands.KnParams

View File

@ -0,0 +1,48 @@
// Copyright © 2019 The Knative Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package serving
import (
"errors"
"fmt"
"github.com/knative/serving/pkg/client/clientset/versioned/scheme"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// Update the GVK on the given object, based on the GVK registered in into the serving scheme
// for the given GroupVersion
func UpdateGroupVersionKind(obj runtime.Object, gv schema.GroupVersion) error {
gvk, err := GetGroupVersionKind(obj, gv)
if err != nil {
return err
}
obj.GetObjectKind().SetGroupVersionKind(*gvk)
return nil
}
func GetGroupVersionKind(obj runtime.Object, gv schema.GroupVersion) (*schema.GroupVersionKind, error) {
gvks, _, err := scheme.Scheme.ObjectKinds(obj)
if err != nil {
return nil, err
}
for _, gvk := range gvks {
if gvk.GroupVersion() == gv {
return &gvk, nil
}
}
return nil, errors.New(fmt.Sprintf("no group version %s registered in %s", gv, scheme.Scheme.Name()))
}

View File

@ -0,0 +1,44 @@
// Copyright © 2019 The Knative Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package serving
import (
"testing"
"github.com/knative/serving/pkg/apis/serving/v1alpha1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func TestGVKUpdate(t *testing.T) {
service := v1alpha1.Service{}
err := UpdateGroupVersionKind(&service, v1alpha1.SchemeGroupVersion)
if err != nil {
t.Fatalf("cannot update GVK to a service %v", err)
}
if service.Kind != "Service" {
t.Fatalf("wrong kind '%s'", service.Kind)
}
if service.APIVersion != v1alpha1.SchemeGroupVersion.Group+"/"+v1alpha1.SchemeGroupVersion.Version {
t.Fatalf("wrong version '%s'", service.APIVersion)
}
}
func TestGVKUpdateNegative(t *testing.T) {
service := v1alpha1.Service{}
err := UpdateGroupVersionKind(&service, schema.GroupVersion{Group: "bla", Version: "blub"})
if err == nil {
t.Fatal("expect an error for an unregistered group version")
}
}

View File

@ -0,0 +1,295 @@
// Copyright © 2019 The Knative Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package v1alpha1
import (
"fmt"
"io"
"time"
"github.com/knative/pkg/apis"
"k8s.io/apimachinery/pkg/fields"
"github.com/knative/client/pkg/serving"
"github.com/knative/client/pkg/wait"
api_serving "github.com/knative/serving/pkg/apis/serving"
"github.com/knative/serving/pkg/apis/serving/v1alpha1"
client_v1alpha1 "github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
)
// Kn interface to serving. All methods are relative to the
// namespace specified during construction
type KnClient interface {
// Get a service by its unique name
GetService(name string) (*v1alpha1.Service, error)
// List services
ListServices(opts ...ListConfig) (*v1alpha1.ServiceList, error)
// Create a new service
CreateService(service *v1alpha1.Service) error
// Update the given service
UpdateService(service *v1alpha1.Service) error
// Delete a service by name
DeleteService(name string) error
// Wait for a service to become ready, but not longer than provided timeout
WaitForService(name string, timeout time.Duration, out io.Writer) error
// Get a revision by name
GetRevision(name string) (*v1alpha1.Revision, error)
// List revisions
ListRevisions(opts ...ListConfig) (*v1alpha1.RevisionList, error)
// Delete a revision
DeleteRevision(name string) error
// List routes
ListRoutes(opts ...ListConfig) (*v1alpha1.RouteList, error)
}
type listConfig struct {
// Labels to filter on
Labels labels.Set
// Labels to filter on
Fields fields.Set
}
// Config function for builder pattern
type ListConfig func(config *listConfig)
type ListConfigs []ListConfig
// add selectors to a list options
func (opts ListConfigs) toListOptions() v1.ListOptions {
listConfig := listConfig{labels.Set{}, fields.Set{}}
for _, f := range opts {
f(&listConfig)
}
options := v1.ListOptions{}
if len(listConfig.Fields) > 0 {
options.FieldSelector = listConfig.Fields.String()
}
if len(listConfig.Labels) > 0 {
options.LabelSelector = listConfig.Labels.String()
}
return options
}
// Filter list on the provided name
func WithName(name string) ListConfig {
return func(lo *listConfig) {
lo.Fields["metadata.name"] = name
}
}
// Filter on the service name
func WithService(service string) ListConfig {
return func(lo *listConfig) {
lo.Labels[api_serving.ServiceLabelKey] = service
}
}
type knClient struct {
client client_v1alpha1.ServingV1alpha1Interface
namespace string
}
// Create a new client facade for the provided namespace
func NewKnServingClient(client client_v1alpha1.ServingV1alpha1Interface, namespace string) KnClient {
return &knClient{
client: client,
namespace: namespace,
}
}
// Get a service by its unique name
func (cl *knClient) GetService(name string) (*v1alpha1.Service, error) {
service, err := cl.client.Services(cl.namespace).Get(name, v1.GetOptions{})
if err != nil {
return nil, err
}
err = serving.UpdateGroupVersionKind(service, v1alpha1.SchemeGroupVersion)
if err != nil {
return nil, err
}
return service, nil
}
// List services
func (cl *knClient) ListServices(config ...ListConfig) (*v1alpha1.ServiceList, error) {
serviceList, err := cl.client.Services(cl.namespace).List(ListConfigs(config).toListOptions())
if err != nil {
return nil, err
}
serviceListNew := serviceList.DeepCopy()
err = updateServingGvk(serviceListNew)
if err != nil {
return nil, err
}
serviceListNew.Items = make([]v1alpha1.Service, len(serviceList.Items))
for idx, service := range serviceList.Items {
serviceClone := service.DeepCopy()
err := updateServingGvk(serviceClone)
if err != nil {
return nil, err
}
serviceListNew.Items[idx] = *serviceClone
}
return serviceListNew, nil
}
// Create a new service
func (cl *knClient) CreateService(service *v1alpha1.Service) error {
_, err := cl.client.Services(cl.namespace).Create(service)
if err != nil {
return err
}
return updateServingGvk(service)
}
// Update the given service
func (cl *knClient) UpdateService(service *v1alpha1.Service) error {
_, err := cl.client.Services(cl.namespace).Update(service)
if err != nil {
return err
}
return updateServingGvk(service)
}
// Delete a service by name
func (cl *knClient) DeleteService(serviceName string) error {
return cl.client.Services(cl.namespace).Delete(
serviceName,
&v1.DeleteOptions{},
)
}
// Wait for a service to become ready, but not longer than provided timeout
func (cl *knClient) WaitForService(name string, timeout time.Duration, out io.Writer) error {
waitForReady := newServiceWaitForReady(cl.client.Services(cl.namespace).Watch)
return waitForReady.Wait(name, timeout, out)
}
// Get a revision by name
func (cl *knClient) GetRevision(name string) (*v1alpha1.Revision, error) {
revision, err := cl.client.Revisions(cl.namespace).Get(name, v1.GetOptions{})
if err != nil {
return nil, err
}
err = updateServingGvk(revision)
if err != nil {
return nil, err
}
return revision, nil
}
// Delete a revision by name
func (cl *knClient) DeleteRevision(name string) error {
return cl.client.Revisions(cl.namespace).Delete(name, &v1.DeleteOptions{})
}
// List revisions
func (cl *knClient) ListRevisions(config ...ListConfig) (*v1alpha1.RevisionList, error) {
revisionList, err := cl.client.Revisions(cl.namespace).List(ListConfigs(config).toListOptions())
if err != nil {
return nil, err
}
return updateServingGvkForRevisionList(revisionList)
}
// List routes
func (cl *knClient) ListRoutes(config ...ListConfig) (*v1alpha1.RouteList, error) {
routeList, err := cl.client.Routes(cl.namespace).List(ListConfigs(config).toListOptions())
if err != nil {
return nil, err
}
return updateServingGvkForRouteList(routeList)
}
// update all the list + all items contained in the list with
// the proper GroupVersionKind specific to Knative serving
func updateServingGvkForRevisionList(revisionList *v1alpha1.RevisionList) (*v1alpha1.RevisionList, error) {
revisionListNew := revisionList.DeepCopy()
err := updateServingGvk(revisionListNew)
if err != nil {
return nil, err
}
revisionListNew.Items = make([]v1alpha1.Revision, len(revisionList.Items))
for idx := range revisionList.Items {
revision := revisionList.Items[idx].DeepCopy()
err := updateServingGvk(revision)
if err != nil {
return nil, err
}
revisionListNew.Items[idx] = *revision
}
return revisionListNew, nil
}
// update all the list + all items contained in the list with
// the proper GroupVersionKind specific to Knative serving
func updateServingGvkForRouteList(routeList *v1alpha1.RouteList) (*v1alpha1.RouteList, error) {
routeListNew := routeList.DeepCopy()
err := updateServingGvk(routeListNew)
if err != nil {
return nil, err
}
routeListNew.Items = make([]v1alpha1.Route, len(routeList.Items))
for idx := range routeList.Items {
revision := routeList.Items[idx].DeepCopy()
err := updateServingGvk(revision)
if err != nil {
return nil, err
}
routeListNew.Items[idx] = *revision
}
return routeListNew, nil
}
// update with the v1alpha1 group + version
func updateServingGvk(obj runtime.Object) error {
return serving.UpdateGroupVersionKind(obj, v1alpha1.SchemeGroupVersion)
}
// Create wait arguments for a Knative service which can be used to wait for
// a create/update options to be finished
// Can be used by `service_create` and `service_update`, hence this extra file
func newServiceWaitForReady(watch wait.WatchFunc) wait.WaitForReady {
return wait.NewWaitForReady(
"service",
watch,
serviceConditionExtractor)
}
func serviceConditionExtractor(obj runtime.Object) (apis.Conditions, error) {
service, ok := obj.(*v1alpha1.Service)
if !ok {
return nil, fmt.Errorf("%v is not a service", obj)
}
return apis.Conditions(service.Status.Conditions), nil
}

View File

@ -0,0 +1,399 @@
// Copyright © 2019 The Knative Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package v1alpha1
import (
"bytes"
"fmt"
"testing"
"time"
"gotest.tools/assert"
"gotest.tools/assert/cmp"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/watch"
serving_api "github.com/knative/serving/pkg/apis/serving"
"github.com/knative/serving/pkg/apis/serving/v1alpha1"
"github.com/knative/serving/pkg/client/clientset/versioned/typed/serving/v1alpha1/fake"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
client_testing "k8s.io/client-go/testing"
"github.com/knative/client/pkg/serving"
"github.com/knative/client/pkg/wait"
)
var testNamespace = "test-ns"
func setup() (serving fake.FakeServingV1alpha1, client KnClient) {
serving = fake.FakeServingV1alpha1{Fake: &client_testing.Fake{}}
client = NewKnServingClient(&serving, testNamespace)
return
}
func TestGetService(t *testing.T) {
serving, client := setup()
serviceName := "test-service"
serving.AddReactor("get", "services",
func(a client_testing.Action) (bool, runtime.Object, error) {
service := newService(serviceName)
name := a.(client_testing.GetAction).GetName()
// Sanity check
assert.Assert(t, name != "")
assert.Equal(t, testNamespace, a.GetNamespace())
if name == serviceName {
return true, service, nil
}
return true, nil, errors.NewNotFound(v1alpha1.Resource("service"), name)
})
t.Run("get known service by name returns service", func(t *testing.T) {
service, err := client.GetService(serviceName)
assert.NilError(t, err)
assert.Equal(t, serviceName, service.Name, "service name should be equal")
validateGroupVersionKind(t, service)
})
t.Run("get unknown service name returns error", func(t *testing.T) {
nonExistingServiceName := "service-that-does-not-exist"
service, err := client.GetService(nonExistingServiceName)
assert.Assert(t, service == nil, "no service should be returned")
assert.ErrorContains(t, err, "not found")
assert.ErrorContains(t, err, nonExistingServiceName)
})
}
func TestListService(t *testing.T) {
serving, client := setup()
t.Run("list service returns a list of services", func(t *testing.T) {
service1 := newService("service-1")
service2 := newService("service-2")
serving.AddReactor("list", "services",
func(a client_testing.Action) (bool, runtime.Object, error) {
assert.Equal(t, testNamespace, a.GetNamespace())
return true, &v1alpha1.ServiceList{Items: []v1alpha1.Service{*service1, *service2}}, nil
})
listServices, err := client.ListServices()
assert.NilError(t, err)
assert.Assert(t, len(listServices.Items) == 2)
assert.Equal(t, listServices.Items[0].Name, "service-1")
assert.Equal(t, listServices.Items[1].Name, "service-2")
validateGroupVersionKind(t, listServices)
validateGroupVersionKind(t, &listServices.Items[0])
validateGroupVersionKind(t, &listServices.Items[1])
})
}
func TestCreateService(t *testing.T) {
serving, client := setup()
serviceNew := newService("new-service")
serving.AddReactor("create", "services",
func(a client_testing.Action) (bool, runtime.Object, error) {
assert.Equal(t, testNamespace, a.GetNamespace())
name := a.(client_testing.CreateAction).GetObject().(metav1.Object).GetName()
if name == serviceNew.Name {
serviceNew.Generation = 2
return true, serviceNew, nil
}
return true, nil, fmt.Errorf("error while creating service %s", name)
})
t.Run("create service without error creates a new service", func(t *testing.T) {
err := client.CreateService(serviceNew)
assert.NilError(t, err)
assert.Equal(t, serviceNew.Generation, int64(2))
validateGroupVersionKind(t, serviceNew)
})
t.Run("create service with an error returns an error object", func(t *testing.T) {
err := client.CreateService(newService("unknown"))
assert.ErrorContains(t, err, "unknown")
})
}
func TestUpdateService(t *testing.T) {
serving, client := setup()
serviceUpdate := newService("update-service")
serving.AddReactor("update", "services",
func(a client_testing.Action) (bool, runtime.Object, error) {
assert.Equal(t, testNamespace, a.GetNamespace())
name := a.(client_testing.UpdateAction).GetObject().(metav1.Object).GetName()
if name == serviceUpdate.Name {
serviceUpdate.Generation = 3
return true, serviceUpdate, nil
}
return true, nil, fmt.Errorf("error while updating service %s", name)
})
t.Run("updating a service without error", func(t *testing.T) {
err := client.UpdateService(serviceUpdate)
assert.NilError(t, err)
assert.Equal(t, int64(3), serviceUpdate.Generation)
validateGroupVersionKind(t, serviceUpdate)
})
t.Run("updating a service with error", func(t *testing.T) {
err := client.UpdateService(newService("unknown"))
assert.ErrorContains(t, err, "unknown")
})
}
func TestDeleteService(t *testing.T) {
serving, client := setup()
const (
serviceName = "test-service"
nonExistingServiceName = "no-service"
)
serving.AddReactor("delete", "services",
func(a client_testing.Action) (bool, runtime.Object, error) {
name := a.(client_testing.DeleteAction).GetName()
// Sanity check
assert.Assert(t, name != "")
assert.Equal(t, testNamespace, a.GetNamespace())
if name == serviceName {
return true, nil, nil
}
return true, nil, errors.NewNotFound(v1alpha1.Resource("service"), name)
})
t.Run("delete existing service returns no error", func(t *testing.T) {
err := client.DeleteService(serviceName)
assert.NilError(t, err)
})
t.Run("trying to delete non-existing service returns error", func(t *testing.T) {
err := client.DeleteService(nonExistingServiceName)
assert.ErrorContains(t, err, "not found")
assert.ErrorContains(t, err, nonExistingServiceName)
})
}
func TestGetRevision(t *testing.T) {
serving, client := setup()
const (
revisionName = "test-revision"
notExistingRevisionName = "no-revision"
)
serving.AddReactor("get", "revisions",
func(a client_testing.Action) (bool, runtime.Object, error) {
revision := newRevision(revisionName)
name := a.(client_testing.GetAction).GetName()
// Sanity check
assert.Assert(t, name != "")
assert.Equal(t, testNamespace, a.GetNamespace())
if name == revisionName {
return true, revision, nil
}
return true, nil, errors.NewNotFound(v1alpha1.Resource("revision"), name)
})
t.Run("get existing revision returns revision and no error", func(t *testing.T) {
revision, err := client.GetRevision(revisionName)
assert.NilError(t, err)
assert.Equal(t, revisionName, revision.Name)
validateGroupVersionKind(t, revision)
})
t.Run("trying to get a revision with a name that does not exist returns an error", func(t *testing.T) {
revision, err := client.GetRevision(notExistingRevisionName)
assert.Assert(t, revision == nil)
assert.ErrorContains(t, err, notExistingRevisionName)
assert.ErrorContains(t, err, "not found")
})
}
func TestListRevisions(t *testing.T) {
serving, client := setup()
revisions := []v1alpha1.Revision{*newRevision("revision-1"), *newRevision("revision-2")}
serving.AddReactor("list", "revisions",
func(a client_testing.Action) (bool, runtime.Object, error) {
assert.Equal(t, testNamespace, a.GetNamespace())
return true, &v1alpha1.RevisionList{Items: revisions}, nil
})
t.Run("list revisions returns a list of revisions and no error", func(t *testing.T) {
revisions, err := client.ListRevisions()
assert.NilError(t, err)
assert.Assert(t, len(revisions.Items) == 2)
assert.Equal(t, revisions.Items[0].Name, "revision-1")
assert.Equal(t, revisions.Items[1].Name, "revision-2")
validateGroupVersionKind(t, revisions)
validateGroupVersionKind(t, &revisions.Items[0])
validateGroupVersionKind(t, &revisions.Items[1])
})
}
func TestListRevisionForService(t *testing.T) {
serving, client := setup()
serviceName := "service"
serving.AddReactor("list", "revisions",
func(a client_testing.Action) (bool, runtime.Object, error) {
revisions := []v1alpha1.Revision{
*newRevision("revision-1", serving_api.ServiceLabelKey, "service"),
*newRevision("revision-2"),
}
lAction := a.(client_testing.ListAction)
assert.Equal(t, testNamespace, a.GetNamespace())
restrictions := lAction.GetListRestrictions()
assert.Check(t, restrictions.Fields.Empty())
servicesLabels := labels.Set{serving_api.ServiceLabelKey: serviceName}
assert.Check(t, restrictions.Labels.Matches(servicesLabels))
return true, &v1alpha1.RevisionList{Items: revisions}, nil
})
t.Run("list revisions for a service returns a list of revisions associated with this this service and no error",
func(t *testing.T) {
revisions, err := client.ListRevisions(WithService(serviceName))
assert.NilError(t, err)
assert.Assert(t, cmp.Len(revisions.Items, 1))
assert.Equal(t, revisions.Items[0].Name, "revision-1")
assert.Equal(t, revisions.Items[0].Labels[serving_api.ServiceLabelKey], "service")
validateGroupVersionKind(t, revisions)
validateGroupVersionKind(t, &revisions.Items[0])
})
}
func TestListRoutes(t *testing.T) {
serving, client := setup()
singleRouteName := "route-2"
singleRoute := *newRoute(singleRouteName)
routes := []v1alpha1.Route{*newRoute("route-1"), singleRoute, *newRoute("route-3")}
serving.AddReactor("list", "routes",
func(a client_testing.Action) (bool, runtime.Object, error) {
assert.Equal(t, testNamespace, a.GetNamespace())
lAction := a.(client_testing.ListAction)
restrictions := lAction.GetListRestrictions()
assert.Assert(t, restrictions.Labels.Empty())
if !restrictions.Fields.Empty() {
nameField := fields.Set{"metadata.name": singleRouteName}
assert.Check(t, restrictions.Labels.Matches(nameField))
return true, &v1alpha1.RouteList{Items: []v1alpha1.Route{singleRoute}}, nil
}
return true, &v1alpha1.RouteList{Items: routes}, nil
})
t.Run("list routes returns a list of routes and no error", func(t *testing.T) {
routes, err := client.ListRoutes()
assert.NilError(t, err)
assert.Assert(t, len(routes.Items) == 3)
assert.Equal(t, routes.Items[0].Name, "route-1")
assert.Equal(t, routes.Items[1].Name, singleRouteName)
assert.Equal(t, routes.Items[2].Name, "route-3")
validateGroupVersionKind(t, routes)
for i := 0; i < len(routes.Items); i++ {
validateGroupVersionKind(t, &routes.Items[i])
}
})
t.Run("list routes with a name filter a list with one route and no error", func(t *testing.T) {
routes, err := client.ListRoutes(WithName(singleRouteName))
assert.NilError(t, err)
assert.Assert(t, len(routes.Items) == 1)
assert.Equal(t, routes.Items[0].Name, singleRouteName)
validateGroupVersionKind(t, routes)
validateGroupVersionKind(t, &routes.Items[0])
})
}
func TestWaitForService(t *testing.T) {
serving, client := setup()
serviceName := "test-service"
serving.AddWatchReactor("services",
func(a client_testing.Action) (bool, watch.Interface, error) {
watchAction := a.(client_testing.WatchAction)
_, found := watchAction.GetWatchRestrictions().Fields.RequiresExactMatch("metadata.name")
if !found {
return true, nil, fmt.Errorf("no field selector on metadata.name found")
}
w := wait.NewFakeWatch(getServiceEvents(serviceName))
w.Start()
return true, w, nil
})
serving.AddReactor("get", "services",
func(a client_testing.Action) (bool, runtime.Object, error) {
getAction := a.(client_testing.GetAction)
assert.Equal(t, getAction.GetName(), serviceName)
return true, newService(serviceName), nil
})
t.Run("wait on a service to become ready with success", func(t *testing.T) {
buf := new(bytes.Buffer)
err := client.WaitForService(serviceName, 60*time.Second, buf)
assert.NilError(t, err)
})
}
func validateGroupVersionKind(t *testing.T, obj runtime.Object) {
gvkExpected, err := serving.GetGroupVersionKind(obj, v1alpha1.SchemeGroupVersion)
assert.NilError(t, err)
gvkGiven := obj.GetObjectKind().GroupVersionKind()
assert.Equal(t, *gvkExpected, gvkGiven, "GVK should be the same")
}
func newService(name string) *v1alpha1.Service {
return &v1alpha1.Service{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: testNamespace}}
}
func newRevision(name string, labels ...string) *v1alpha1.Revision {
rev := &v1alpha1.Revision{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: testNamespace}}
labelMap := make(map[string]string)
if len(labels) > 0 {
for i := 0; i < len(labels); i += 2 {
labelMap[labels[i]] = labels[i+1]
}
rev.Labels = labelMap
}
return rev
}
func newRoute(name string) *v1alpha1.Route {
return &v1alpha1.Route{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: testNamespace}}
}
func getServiceEvents(name string) []watch.Event {
return []watch.Event{
{watch.Added, wait.CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionUnknown, "")},
{watch.Modified, wait.CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionTrue, "")},
{watch.Modified, wait.CreateTestServiceWithConditions(name, corev1.ConditionTrue, corev1.ConditionTrue, "")},
}
}

View File

@ -0,0 +1,15 @@
// Copyright © 2019 The Knative Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package v1alpha1

View File

@ -18,6 +18,7 @@ import (
"github.com/knative/pkg/apis"
"github.com/knative/serving/pkg/apis/serving/v1alpha1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
)
@ -61,9 +62,9 @@ func (f *FakeWatch) fireEvents() {
}
}
// Create a service skeletion with a given ConditionReady status and all other statuses set to otherReadyStatus. Optionally a single generation can be added.
func CreateTestServiceWithConditions(readyStatus corev1.ConditionStatus, otherReadyStatus corev1.ConditionStatus, reason string, generations ...int64) runtime.Object {
service := v1alpha1.Service{}
// Create a service skeleton with a given ConditionReady status and all other statuses set to otherReadyStatus. Optionally a single generation can be added.
func CreateTestServiceWithConditions(name string, readyStatus corev1.ConditionStatus, otherReadyStatus corev1.ConditionStatus, reason string, generations ...int64) runtime.Object {
service := v1alpha1.Service{ObjectMeta: metav1.ObjectMeta{Name: name}}
if len(generations) == 2 {
service.Generation = generations[0]
service.Status.ObservedGeneration = generations[1]

View File

@ -37,7 +37,7 @@ type waitForReadyTestCase struct {
func TestAddWaitForReady(t *testing.T) {
for i, tc := range prepareTestCases() {
for i, tc := range prepareTestCases("test-service") {
fakeWatchApi := NewFakeWatch(tc.events)
outBuffer := new(bytes.Buffer)
@ -79,41 +79,41 @@ func TestAddWaitForReady(t *testing.T) {
}
// Test cases which consists of a series of events to send and the expected behaviour.
func prepareTestCases() []waitForReadyTestCase {
func prepareTestCases(name string) []waitForReadyTestCase {
return []waitForReadyTestCase{
{peNormal(), time.Second, false, []string{"OK", "foobar", "blub"}},
{peError(), time.Second, true, []string{"FakeError"}},
{peTimeout(), time.Second, true, []string{"timeout"}},
{peWrongGeneration(), time.Second, true, []string{"timeout"}},
{peNormal(name), time.Second, false, []string{"OK", "foobar", "blub"}},
{peError(name), time.Second, true, []string{"FakeError"}},
{peTimeout(name), time.Second, true, []string{"timeout"}},
{peWrongGeneration(name), time.Second, true, []string{"timeout"}},
}
}
// =============================================================================
func peNormal() []watch.Event {
func peNormal(name string) []watch.Event {
return []watch.Event{
{watch.Added, CreateTestServiceWithConditions(corev1.ConditionUnknown, corev1.ConditionUnknown, "")},
{watch.Modified, CreateTestServiceWithConditions(corev1.ConditionUnknown, corev1.ConditionTrue, "")},
{watch.Modified, CreateTestServiceWithConditions(corev1.ConditionTrue, corev1.ConditionTrue, "")},
{watch.Added, CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionUnknown, "")},
{watch.Modified, CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionTrue, "")},
{watch.Modified, CreateTestServiceWithConditions(name, corev1.ConditionTrue, corev1.ConditionTrue, "")},
}
}
func peError() []watch.Event {
func peError(name string) []watch.Event {
return []watch.Event{
{watch.Added, CreateTestServiceWithConditions(corev1.ConditionUnknown, corev1.ConditionUnknown, "")},
{watch.Modified, CreateTestServiceWithConditions(corev1.ConditionFalse, corev1.ConditionTrue, "FakeError")},
{watch.Added, CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionUnknown, "")},
{watch.Modified, CreateTestServiceWithConditions(name, corev1.ConditionFalse, corev1.ConditionTrue, "FakeError")},
}
}
func peTimeout() []watch.Event {
func peTimeout(name string) []watch.Event {
return []watch.Event{
{watch.Added, CreateTestServiceWithConditions(corev1.ConditionUnknown, corev1.ConditionUnknown, "")},
{watch.Added, CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionUnknown, "")},
}
}
func peWrongGeneration() []watch.Event {
func peWrongGeneration(name string) []watch.Event {
return []watch.Event{
{watch.Added, CreateTestServiceWithConditions(corev1.ConditionUnknown, corev1.ConditionUnknown, "")},
{watch.Modified, CreateTestServiceWithConditions(corev1.ConditionTrue, corev1.ConditionTrue, "", 1, 2)},
{watch.Added, CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionUnknown, "")},
{watch.Modified, CreateTestServiceWithConditions(name, corev1.ConditionTrue, corev1.ConditionTrue, "", 1, 2)},
}
}

View File

@ -118,7 +118,7 @@ func testServiceDescribe(t *testing.T, k kn, serviceName string) {
t.Fatalf(fmt.Sprintf("Error executing 'kn service describe' command. Error: %s", err.Error()))
}
expectedOutputHeader := `apiVersion: knative.dev/v1alpha1
expectedOutputHeader := `apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:`
if !strings.Contains(out, expectedOutputHeader) {

View File

@ -6,6 +6,8 @@ import (
"fmt"
"strconv"
"strings"
"github.com/pkg/errors"
)
const (
@ -24,6 +26,14 @@ var (
AccumulatedCopySizeLimit int64 = 0
)
var (
ErrTestFailed = errors.New("test failed")
ErrMissing = errors.New("missing value")
ErrUnknownType = errors.New("unknown object type")
ErrInvalid = errors.New("invalid state detected")
ErrInvalidIndex = errors.New("invalid index referenced")
)
type lazyNode struct {
raw *json.RawMessage
doc partialDoc
@ -31,10 +41,11 @@ type lazyNode struct {
which int
}
type operation map[string]*json.RawMessage
// Operation is a single JSON-Patch step, such as a single 'add' operation.
type Operation map[string]*json.RawMessage
// Patch is an ordered collection of operations.
type Patch []operation
// Patch is an ordered collection of Operations.
type Patch []Operation
type partialDoc map[string]*lazyNode
type partialArray []*lazyNode
@ -59,7 +70,7 @@ func (n *lazyNode) MarshalJSON() ([]byte, error) {
case eAry:
return json.Marshal(n.ary)
default:
return nil, fmt.Errorf("Unknown type")
return nil, ErrUnknownType
}
}
@ -91,7 +102,7 @@ func (n *lazyNode) intoDoc() (*partialDoc, error) {
}
if n.raw == nil {
return nil, fmt.Errorf("Unable to unmarshal nil pointer as partial document")
return nil, ErrInvalid
}
err := json.Unmarshal(*n.raw, &n.doc)
@ -110,7 +121,7 @@ func (n *lazyNode) intoAry() (*partialArray, error) {
}
if n.raw == nil {
return nil, fmt.Errorf("Unable to unmarshal nil pointer as partial array")
return nil, ErrInvalid
}
err := json.Unmarshal(*n.raw, &n.ary)
@ -227,7 +238,8 @@ func (n *lazyNode) equal(o *lazyNode) bool {
return true
}
func (o operation) kind() string {
// Kind reads the "op" field of the Operation.
func (o Operation) Kind() string {
if obj, ok := o["op"]; ok && obj != nil {
var op string
@ -243,39 +255,41 @@ func (o operation) kind() string {
return "unknown"
}
func (o operation) path() string {
// Path reads the "path" field of the Operation.
func (o Operation) Path() (string, error) {
if obj, ok := o["path"]; ok && obj != nil {
var op string
err := json.Unmarshal(*obj, &op)
if err != nil {
return "unknown"
return "unknown", err
}
return op
return op, nil
}
return "unknown"
return "unknown", errors.Wrapf(ErrMissing, "operation missing path field")
}
func (o operation) from() string {
// From reads the "from" field of the Operation.
func (o Operation) From() (string, error) {
if obj, ok := o["from"]; ok && obj != nil {
var op string
err := json.Unmarshal(*obj, &op)
if err != nil {
return "unknown"
return "unknown", err
}
return op
return op, nil
}
return "unknown"
return "unknown", errors.Wrapf(ErrMissing, "operation, missing from field")
}
func (o operation) value() *lazyNode {
func (o Operation) value() *lazyNode {
if obj, ok := o["value"]; ok {
return newLazyNode(obj)
}
@ -283,6 +297,23 @@ func (o operation) value() *lazyNode {
return nil
}
// ValueInterface decodes the operation value into an interface.
func (o Operation) ValueInterface() (interface{}, error) {
if obj, ok := o["value"]; ok && obj != nil {
var v interface{}
err := json.Unmarshal(*obj, &v)
if err != nil {
return nil, err
}
return v, nil
}
return nil, errors.Wrapf(ErrMissing, "operation, missing value field")
}
func isArray(buf []byte) bool {
Loop:
for _, c := range buf {
@ -359,7 +390,7 @@ func (d *partialDoc) get(key string) (*lazyNode, error) {
func (d *partialDoc) remove(key string) error {
_, ok := (*d)[key]
if !ok {
return fmt.Errorf("Unable to remove nonexistent key: %s", key)
return errors.Wrapf(ErrMissing, "Unable to remove nonexistent key: %s", key)
}
delete(*d, key)
@ -385,7 +416,7 @@ func (d *partialArray) add(key string, val *lazyNode) error {
idx, err := strconv.Atoi(key)
if err != nil {
return err
return errors.Wrapf(err, "value was not a proper array index: '%s'", key)
}
sz := len(*d) + 1
@ -395,12 +426,12 @@ func (d *partialArray) add(key string, val *lazyNode) error {
cur := *d
if idx >= len(ary) {
return fmt.Errorf("Unable to access invalid index: %d", idx)
return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
}
if SupportNegativeIndices {
if idx < -len(ary) {
return fmt.Errorf("Unable to access invalid index: %d", idx)
return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
}
if idx < 0 {
@ -424,7 +455,7 @@ func (d *partialArray) get(key string) (*lazyNode, error) {
}
if idx >= len(*d) {
return nil, fmt.Errorf("Unable to access invalid index: %d", idx)
return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
}
return (*d)[idx], nil
@ -439,12 +470,12 @@ func (d *partialArray) remove(key string) error {
cur := *d
if idx >= len(cur) {
return fmt.Errorf("Unable to access invalid index: %d", idx)
return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
}
if SupportNegativeIndices {
if idx < -len(cur) {
return fmt.Errorf("Unable to access invalid index: %d", idx)
return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
}
if idx < 0 {
@ -462,140 +493,189 @@ func (d *partialArray) remove(key string) error {
}
func (p Patch) add(doc *container, op operation) error {
path := op.path()
con, key := findObject(doc, path)
if con == nil {
return fmt.Errorf("jsonpatch add operation does not apply: doc is missing path: \"%s\"", path)
}
return con.add(key, op.value())
}
func (p Patch) remove(doc *container, op operation) error {
path := op.path()
con, key := findObject(doc, path)
if con == nil {
return fmt.Errorf("jsonpatch remove operation does not apply: doc is missing path: \"%s\"", path)
}
return con.remove(key)
}
func (p Patch) replace(doc *container, op operation) error {
path := op.path()
con, key := findObject(doc, path)
if con == nil {
return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing path: %s", path)
}
_, ok := con.get(key)
if ok != nil {
return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing key: %s", path)
}
return con.set(key, op.value())
}
func (p Patch) move(doc *container, op operation) error {
from := op.from()
con, key := findObject(doc, from)
if con == nil {
return fmt.Errorf("jsonpatch move operation does not apply: doc is missing from path: %s", from)
}
val, err := con.get(key)
func (p Patch) add(doc *container, op Operation) error {
path, err := op.Path()
if err != nil {
return err
return errors.Wrapf(ErrMissing, "add operation failed to decode path")
}
con, key := findObject(doc, path)
if con == nil {
return errors.Wrapf(ErrMissing, "add operation does not apply: doc is missing path: \"%s\"", path)
}
err = con.add(key, op.value())
if err != nil {
return errors.Wrapf(err, "error in add for path: '%s'", path)
}
return nil
}
func (p Patch) remove(doc *container, op Operation) error {
path, err := op.Path()
if err != nil {
return errors.Wrapf(ErrMissing, "remove operation failed to decode path")
}
con, key := findObject(doc, path)
if con == nil {
return errors.Wrapf(ErrMissing, "remove operation does not apply: doc is missing path: \"%s\"", path)
}
err = con.remove(key)
if err != nil {
return err
return errors.Wrapf(err, "error in remove for path: '%s'", path)
}
path := op.path()
con, key = findObject(doc, path)
if con == nil {
return fmt.Errorf("jsonpatch move operation does not apply: doc is missing destination path: %s", path)
}
return con.add(key, val)
return nil
}
func (p Patch) test(doc *container, op operation) error {
path := op.path()
func (p Patch) replace(doc *container, op Operation) error {
path, err := op.Path()
if err != nil {
return errors.Wrapf(err, "replace operation failed to decode path")
}
con, key := findObject(doc, path)
if con == nil {
return fmt.Errorf("jsonpatch test operation does not apply: is missing path: %s", path)
return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing path: %s", path)
}
_, ok := con.get(key)
if ok != nil {
return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing key: %s", path)
}
err = con.set(key, op.value())
if err != nil {
return errors.Wrapf(err, "error in remove for path: '%s'", path)
}
return nil
}
func (p Patch) move(doc *container, op Operation) error {
from, err := op.From()
if err != nil {
return errors.Wrapf(err, "move operation failed to decode from")
}
con, key := findObject(doc, from)
if con == nil {
return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing from path: %s", from)
}
val, err := con.get(key)
if err != nil {
return err
return errors.Wrapf(err, "error in move for path: '%s'", key)
}
err = con.remove(key)
if err != nil {
return errors.Wrapf(err, "error in move for path: '%s'", key)
}
path, err := op.Path()
if err != nil {
return errors.Wrapf(err, "move operation failed to decode path")
}
con, key = findObject(doc, path)
if con == nil {
return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing destination path: %s", path)
}
err = con.add(key, val)
if err != nil {
return errors.Wrapf(err, "error in move for path: '%s'", path)
}
return nil
}
func (p Patch) test(doc *container, op Operation) error {
path, err := op.Path()
if err != nil {
return errors.Wrapf(err, "test operation failed to decode path")
}
con, key := findObject(doc, path)
if con == nil {
return errors.Wrapf(ErrMissing, "test operation does not apply: is missing path: %s", path)
}
val, err := con.get(key)
if err != nil {
return errors.Wrapf(err, "error in test for path: '%s'", path)
}
if val == nil {
if op.value().raw == nil {
return nil
}
return fmt.Errorf("Testing value %s failed", path)
return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
} else if op.value() == nil {
return fmt.Errorf("Testing value %s failed", path)
return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
}
if val.equal(op.value()) {
return nil
}
return fmt.Errorf("Testing value %s failed", path)
return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
}
func (p Patch) copy(doc *container, op operation, accumulatedCopySize *int64) error {
from := op.from()
func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64) error {
from, err := op.From()
if err != nil {
return errors.Wrapf(err, "copy operation failed to decode from")
}
con, key := findObject(doc, from)
if con == nil {
return fmt.Errorf("jsonpatch copy operation does not apply: doc is missing from path: %s", from)
return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing from path: %s", from)
}
val, err := con.get(key)
if err != nil {
return err
return errors.Wrapf(err, "error in copy for from: '%s'", from)
}
path := op.path()
path, err := op.Path()
if err != nil {
return errors.Wrapf(ErrMissing, "copy operation failed to decode path")
}
con, key = findObject(doc, path)
if con == nil {
return fmt.Errorf("jsonpatch copy operation does not apply: doc is missing destination path: %s", path)
return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing destination path: %s", path)
}
valCopy, sz, err := deepCopy(val)
if err != nil {
return err
return errors.Wrapf(err, "error while performing deep copy")
}
(*accumulatedCopySize) += int64(sz)
if AccumulatedCopySizeLimit > 0 && *accumulatedCopySize > AccumulatedCopySizeLimit {
return NewAccumulatedCopySizeError(AccumulatedCopySizeLimit, *accumulatedCopySize)
}
return con.add(key, valCopy)
err = con.add(key, valCopy)
if err != nil {
return errors.Wrapf(err, "error while adding value during copy")
}
return nil
}
// Equal indicates if 2 JSON documents have the same structural equality.
@ -651,7 +731,7 @@ func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) {
var accumulatedCopySize int64
for _, op := range p {
switch op.kind() {
switch op.Kind() {
case "add":
err = p.add(&pd, op)
case "remove":
@ -665,7 +745,7 @@ func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) {
case "copy":
err = p.copy(&pd, op, &accumulatedCopySize)
default:
err = fmt.Errorf("Unexpected kind: %s", op.kind())
err = fmt.Errorf("Unexpected kind: %s", op.Kind())
}
if err != nil {

View File

@ -7105,15 +7105,15 @@ func (m *Any) ToRawInfo() interface{} {
// ToRawInfo returns a description of ApiKeySecurity suitable for JSON or YAML export.
func (m *ApiKeySecurity) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.Type != "" {
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}
if m.In != "" {
info = append(info, yaml.MapItem{Key: "in", Value: m.In})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
// always include this required field.
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
// always include this required field.
info = append(info, yaml.MapItem{Key: "in", Value: m.In})
if m.Description != "" {
info = append(info, yaml.MapItem{Key: "description", Value: m.Description})
}
@ -7129,9 +7129,11 @@ func (m *ApiKeySecurity) ToRawInfo() interface{} {
// ToRawInfo returns a description of BasicAuthenticationSecurity suitable for JSON or YAML export.
func (m *BasicAuthenticationSecurity) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.Type != "" {
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
if m.Description != "" {
info = append(info, yaml.MapItem{Key: "description", Value: m.Description})
}
@ -7147,21 +7149,21 @@ func (m *BasicAuthenticationSecurity) ToRawInfo() interface{} {
// ToRawInfo returns a description of BodyParameter suitable for JSON or YAML export.
func (m *BodyParameter) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Description != "" {
info = append(info, yaml.MapItem{Key: "description", Value: m.Description})
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}
if m.In != "" {
info = append(info, yaml.MapItem{Key: "in", Value: m.In})
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
// always include this required field.
info = append(info, yaml.MapItem{Key: "in", Value: m.In})
if m.Required != false {
info = append(info, yaml.MapItem{Key: "required", Value: m.Required})
}
if m.Schema != nil {
info = append(info, yaml.MapItem{Key: "schema", Value: m.Schema.ToRawInfo()})
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "schema", Value: m.Schema.ToRawInfo()})
// &{Name:schema Type:Schema StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:}
if m.VendorExtension != nil {
for _, item := range m.VendorExtension {
@ -7175,6 +7177,9 @@ func (m *BodyParameter) ToRawInfo() interface{} {
// ToRawInfo returns a description of Contact suitable for JSON or YAML export.
func (m *Contact) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}
@ -7196,6 +7201,9 @@ func (m *Contact) ToRawInfo() interface{} {
// ToRawInfo returns a description of Default suitable for JSON or YAML export.
func (m *Default) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.AdditionalProperties != nil {
for _, item := range m.AdditionalProperties {
info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()})
@ -7208,6 +7216,9 @@ func (m *Default) ToRawInfo() interface{} {
// ToRawInfo returns a description of Definitions suitable for JSON or YAML export.
func (m *Definitions) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.AdditionalProperties != nil {
for _, item := range m.AdditionalProperties {
info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()})
@ -7220,12 +7231,13 @@ func (m *Definitions) ToRawInfo() interface{} {
// ToRawInfo returns a description of Document suitable for JSON or YAML export.
func (m *Document) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.Swagger != "" {
info = append(info, yaml.MapItem{Key: "swagger", Value: m.Swagger})
}
if m.Info != nil {
info = append(info, yaml.MapItem{Key: "info", Value: m.Info.ToRawInfo()})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "swagger", Value: m.Swagger})
// always include this required field.
info = append(info, yaml.MapItem{Key: "info", Value: m.Info.ToRawInfo()})
// &{Name:info Type:Info StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:}
if m.Host != "" {
info = append(info, yaml.MapItem{Key: "host", Value: m.Host})
@ -7242,9 +7254,8 @@ func (m *Document) ToRawInfo() interface{} {
if len(m.Produces) != 0 {
info = append(info, yaml.MapItem{Key: "produces", Value: m.Produces})
}
if m.Paths != nil {
info = append(info, yaml.MapItem{Key: "paths", Value: m.Paths.ToRawInfo()})
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "paths", Value: m.Paths.ToRawInfo()})
// &{Name:paths Type:Paths StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:}
if m.Definitions != nil {
info = append(info, yaml.MapItem{Key: "definitions", Value: m.Definitions.ToRawInfo()})
@ -7294,6 +7305,9 @@ func (m *Document) ToRawInfo() interface{} {
// ToRawInfo returns a description of Examples suitable for JSON or YAML export.
func (m *Examples) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.AdditionalProperties != nil {
for _, item := range m.AdditionalProperties {
info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()})
@ -7306,12 +7320,14 @@ func (m *Examples) ToRawInfo() interface{} {
// ToRawInfo returns a description of ExternalDocs suitable for JSON or YAML export.
func (m *ExternalDocs) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Description != "" {
info = append(info, yaml.MapItem{Key: "description", Value: m.Description})
}
if m.Url != "" {
info = append(info, yaml.MapItem{Key: "url", Value: m.Url})
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "url", Value: m.Url})
if m.VendorExtension != nil {
for _, item := range m.VendorExtension {
info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()})
@ -7324,6 +7340,9 @@ func (m *ExternalDocs) ToRawInfo() interface{} {
// ToRawInfo returns a description of FileSchema suitable for JSON or YAML export.
func (m *FileSchema) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Format != "" {
info = append(info, yaml.MapItem{Key: "format", Value: m.Format})
}
@ -7340,9 +7359,8 @@ func (m *FileSchema) ToRawInfo() interface{} {
if len(m.Required) != 0 {
info = append(info, yaml.MapItem{Key: "required", Value: m.Required})
}
if m.Type != "" {
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
if m.ReadOnly != false {
info = append(info, yaml.MapItem{Key: "readOnly", Value: m.ReadOnly})
}
@ -7366,6 +7384,9 @@ func (m *FileSchema) ToRawInfo() interface{} {
// ToRawInfo returns a description of FormDataParameterSubSchema suitable for JSON or YAML export.
func (m *FormDataParameterSubSchema) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Required != false {
info = append(info, yaml.MapItem{Key: "required", Value: m.Required})
}
@ -7451,9 +7472,11 @@ func (m *FormDataParameterSubSchema) ToRawInfo() interface{} {
// ToRawInfo returns a description of Header suitable for JSON or YAML export.
func (m *Header) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.Type != "" {
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
if m.Format != "" {
info = append(info, yaml.MapItem{Key: "format", Value: m.Format})
}
@ -7524,6 +7547,9 @@ func (m *Header) ToRawInfo() interface{} {
// ToRawInfo returns a description of HeaderParameterSubSchema suitable for JSON or YAML export.
func (m *HeaderParameterSubSchema) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Required != false {
info = append(info, yaml.MapItem{Key: "required", Value: m.Required})
}
@ -7606,6 +7632,9 @@ func (m *HeaderParameterSubSchema) ToRawInfo() interface{} {
// ToRawInfo returns a description of Headers suitable for JSON or YAML export.
func (m *Headers) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.AdditionalProperties != nil {
for _, item := range m.AdditionalProperties {
info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()})
@ -7618,12 +7647,13 @@ func (m *Headers) ToRawInfo() interface{} {
// ToRawInfo returns a description of Info suitable for JSON or YAML export.
func (m *Info) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.Title != "" {
info = append(info, yaml.MapItem{Key: "title", Value: m.Title})
}
if m.Version != "" {
info = append(info, yaml.MapItem{Key: "version", Value: m.Version})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "title", Value: m.Title})
// always include this required field.
info = append(info, yaml.MapItem{Key: "version", Value: m.Version})
if m.Description != "" {
info = append(info, yaml.MapItem{Key: "description", Value: m.Description})
}
@ -7650,6 +7680,9 @@ func (m *Info) ToRawInfo() interface{} {
// ToRawInfo returns a description of ItemsItem suitable for JSON or YAML export.
func (m *ItemsItem) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if len(m.Schema) != 0 {
items := make([]interface{}, 0)
for _, item := range m.Schema {
@ -7664,9 +7697,11 @@ func (m *ItemsItem) ToRawInfo() interface{} {
// ToRawInfo returns a description of JsonReference suitable for JSON or YAML export.
func (m *JsonReference) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.XRef != "" {
info = append(info, yaml.MapItem{Key: "$ref", Value: m.XRef})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "$ref", Value: m.XRef})
if m.Description != "" {
info = append(info, yaml.MapItem{Key: "description", Value: m.Description})
}
@ -7676,9 +7711,11 @@ func (m *JsonReference) ToRawInfo() interface{} {
// ToRawInfo returns a description of License suitable for JSON or YAML export.
func (m *License) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
if m.Url != "" {
info = append(info, yaml.MapItem{Key: "url", Value: m.Url})
}
@ -7694,6 +7731,9 @@ func (m *License) ToRawInfo() interface{} {
// ToRawInfo returns a description of NamedAny suitable for JSON or YAML export.
func (m *NamedAny) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}
@ -7704,6 +7744,9 @@ func (m *NamedAny) ToRawInfo() interface{} {
// ToRawInfo returns a description of NamedHeader suitable for JSON or YAML export.
func (m *NamedHeader) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}
@ -7714,6 +7757,9 @@ func (m *NamedHeader) ToRawInfo() interface{} {
// ToRawInfo returns a description of NamedParameter suitable for JSON or YAML export.
func (m *NamedParameter) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}
@ -7724,6 +7770,9 @@ func (m *NamedParameter) ToRawInfo() interface{} {
// ToRawInfo returns a description of NamedPathItem suitable for JSON or YAML export.
func (m *NamedPathItem) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}
@ -7734,6 +7783,9 @@ func (m *NamedPathItem) ToRawInfo() interface{} {
// ToRawInfo returns a description of NamedResponse suitable for JSON or YAML export.
func (m *NamedResponse) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}
@ -7744,6 +7796,9 @@ func (m *NamedResponse) ToRawInfo() interface{} {
// ToRawInfo returns a description of NamedResponseValue suitable for JSON or YAML export.
func (m *NamedResponseValue) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}
@ -7754,6 +7809,9 @@ func (m *NamedResponseValue) ToRawInfo() interface{} {
// ToRawInfo returns a description of NamedSchema suitable for JSON or YAML export.
func (m *NamedSchema) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}
@ -7764,6 +7822,9 @@ func (m *NamedSchema) ToRawInfo() interface{} {
// ToRawInfo returns a description of NamedSecurityDefinitionsItem suitable for JSON or YAML export.
func (m *NamedSecurityDefinitionsItem) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}
@ -7774,6 +7835,9 @@ func (m *NamedSecurityDefinitionsItem) ToRawInfo() interface{} {
// ToRawInfo returns a description of NamedString suitable for JSON or YAML export.
func (m *NamedString) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}
@ -7786,6 +7850,9 @@ func (m *NamedString) ToRawInfo() interface{} {
// ToRawInfo returns a description of NamedStringArray suitable for JSON or YAML export.
func (m *NamedStringArray) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}
@ -7823,22 +7890,21 @@ func (m *NonBodyParameter) ToRawInfo() interface{} {
// ToRawInfo returns a description of Oauth2AccessCodeSecurity suitable for JSON or YAML export.
func (m *Oauth2AccessCodeSecurity) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.Type != "" {
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
}
if m.Flow != "" {
info = append(info, yaml.MapItem{Key: "flow", Value: m.Flow})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
// always include this required field.
info = append(info, yaml.MapItem{Key: "flow", Value: m.Flow})
if m.Scopes != nil {
info = append(info, yaml.MapItem{Key: "scopes", Value: m.Scopes.ToRawInfo()})
}
// &{Name:scopes Type:Oauth2Scopes StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:}
if m.AuthorizationUrl != "" {
info = append(info, yaml.MapItem{Key: "authorizationUrl", Value: m.AuthorizationUrl})
}
if m.TokenUrl != "" {
info = append(info, yaml.MapItem{Key: "tokenUrl", Value: m.TokenUrl})
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "authorizationUrl", Value: m.AuthorizationUrl})
// always include this required field.
info = append(info, yaml.MapItem{Key: "tokenUrl", Value: m.TokenUrl})
if m.Description != "" {
info = append(info, yaml.MapItem{Key: "description", Value: m.Description})
}
@ -7854,19 +7920,19 @@ func (m *Oauth2AccessCodeSecurity) ToRawInfo() interface{} {
// ToRawInfo returns a description of Oauth2ApplicationSecurity suitable for JSON or YAML export.
func (m *Oauth2ApplicationSecurity) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.Type != "" {
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
}
if m.Flow != "" {
info = append(info, yaml.MapItem{Key: "flow", Value: m.Flow})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
// always include this required field.
info = append(info, yaml.MapItem{Key: "flow", Value: m.Flow})
if m.Scopes != nil {
info = append(info, yaml.MapItem{Key: "scopes", Value: m.Scopes.ToRawInfo()})
}
// &{Name:scopes Type:Oauth2Scopes StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:}
if m.TokenUrl != "" {
info = append(info, yaml.MapItem{Key: "tokenUrl", Value: m.TokenUrl})
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "tokenUrl", Value: m.TokenUrl})
if m.Description != "" {
info = append(info, yaml.MapItem{Key: "description", Value: m.Description})
}
@ -7882,19 +7948,19 @@ func (m *Oauth2ApplicationSecurity) ToRawInfo() interface{} {
// ToRawInfo returns a description of Oauth2ImplicitSecurity suitable for JSON or YAML export.
func (m *Oauth2ImplicitSecurity) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.Type != "" {
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
}
if m.Flow != "" {
info = append(info, yaml.MapItem{Key: "flow", Value: m.Flow})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
// always include this required field.
info = append(info, yaml.MapItem{Key: "flow", Value: m.Flow})
if m.Scopes != nil {
info = append(info, yaml.MapItem{Key: "scopes", Value: m.Scopes.ToRawInfo()})
}
// &{Name:scopes Type:Oauth2Scopes StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:}
if m.AuthorizationUrl != "" {
info = append(info, yaml.MapItem{Key: "authorizationUrl", Value: m.AuthorizationUrl})
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "authorizationUrl", Value: m.AuthorizationUrl})
if m.Description != "" {
info = append(info, yaml.MapItem{Key: "description", Value: m.Description})
}
@ -7910,19 +7976,19 @@ func (m *Oauth2ImplicitSecurity) ToRawInfo() interface{} {
// ToRawInfo returns a description of Oauth2PasswordSecurity suitable for JSON or YAML export.
func (m *Oauth2PasswordSecurity) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.Type != "" {
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
}
if m.Flow != "" {
info = append(info, yaml.MapItem{Key: "flow", Value: m.Flow})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
// always include this required field.
info = append(info, yaml.MapItem{Key: "flow", Value: m.Flow})
if m.Scopes != nil {
info = append(info, yaml.MapItem{Key: "scopes", Value: m.Scopes.ToRawInfo()})
}
// &{Name:scopes Type:Oauth2Scopes StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:}
if m.TokenUrl != "" {
info = append(info, yaml.MapItem{Key: "tokenUrl", Value: m.TokenUrl})
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "tokenUrl", Value: m.TokenUrl})
if m.Description != "" {
info = append(info, yaml.MapItem{Key: "description", Value: m.Description})
}
@ -7938,6 +8004,9 @@ func (m *Oauth2PasswordSecurity) ToRawInfo() interface{} {
// ToRawInfo returns a description of Oauth2Scopes suitable for JSON or YAML export.
func (m *Oauth2Scopes) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
// &{Name:additionalProperties Type:NamedString StringEnumValues:[] MapType:string Repeated:true Pattern: Implicit:true Description:}
return info
}
@ -7945,6 +8014,9 @@ func (m *Oauth2Scopes) ToRawInfo() interface{} {
// ToRawInfo returns a description of Operation suitable for JSON or YAML export.
func (m *Operation) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if len(m.Tags) != 0 {
info = append(info, yaml.MapItem{Key: "tags", Value: m.Tags})
}
@ -7975,9 +8047,8 @@ func (m *Operation) ToRawInfo() interface{} {
info = append(info, yaml.MapItem{Key: "parameters", Value: items})
}
// &{Name:parameters Type:ParametersItem StringEnumValues:[] MapType: Repeated:true Pattern: Implicit:false Description:The parameters needed to send a valid API call.}
if m.Responses != nil {
info = append(info, yaml.MapItem{Key: "responses", Value: m.Responses.ToRawInfo()})
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "responses", Value: m.Responses.ToRawInfo()})
// &{Name:responses Type:Responses StringEnumValues:[] MapType: Repeated:false Pattern: Implicit:false Description:}
if len(m.Schemes) != 0 {
info = append(info, yaml.MapItem{Key: "schemes", Value: m.Schemes})
@ -8022,6 +8093,9 @@ func (m *Parameter) ToRawInfo() interface{} {
// ToRawInfo returns a description of ParameterDefinitions suitable for JSON or YAML export.
func (m *ParameterDefinitions) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.AdditionalProperties != nil {
for _, item := range m.AdditionalProperties {
info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()})
@ -8051,6 +8125,9 @@ func (m *ParametersItem) ToRawInfo() interface{} {
// ToRawInfo returns a description of PathItem suitable for JSON or YAML export.
func (m *PathItem) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.XRef != "" {
info = append(info, yaml.MapItem{Key: "$ref", Value: m.XRef})
}
@ -8102,9 +8179,11 @@ func (m *PathItem) ToRawInfo() interface{} {
// ToRawInfo returns a description of PathParameterSubSchema suitable for JSON or YAML export.
func (m *PathParameterSubSchema) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.Required != false {
info = append(info, yaml.MapItem{Key: "required", Value: m.Required})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "required", Value: m.Required})
if m.In != "" {
info = append(info, yaml.MapItem{Key: "in", Value: m.In})
}
@ -8184,6 +8263,9 @@ func (m *PathParameterSubSchema) ToRawInfo() interface{} {
// ToRawInfo returns a description of Paths suitable for JSON or YAML export.
func (m *Paths) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.VendorExtension != nil {
for _, item := range m.VendorExtension {
info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()})
@ -8202,6 +8284,9 @@ func (m *Paths) ToRawInfo() interface{} {
// ToRawInfo returns a description of PrimitivesItems suitable for JSON or YAML export.
func (m *PrimitivesItems) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Type != "" {
info = append(info, yaml.MapItem{Key: "type", Value: m.Type})
}
@ -8272,6 +8357,9 @@ func (m *PrimitivesItems) ToRawInfo() interface{} {
// ToRawInfo returns a description of Properties suitable for JSON or YAML export.
func (m *Properties) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.AdditionalProperties != nil {
for _, item := range m.AdditionalProperties {
info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()})
@ -8284,6 +8372,9 @@ func (m *Properties) ToRawInfo() interface{} {
// ToRawInfo returns a description of QueryParameterSubSchema suitable for JSON or YAML export.
func (m *QueryParameterSubSchema) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Required != false {
info = append(info, yaml.MapItem{Key: "required", Value: m.Required})
}
@ -8369,9 +8460,11 @@ func (m *QueryParameterSubSchema) ToRawInfo() interface{} {
// ToRawInfo returns a description of Response suitable for JSON or YAML export.
func (m *Response) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.Description != "" {
info = append(info, yaml.MapItem{Key: "description", Value: m.Description})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "description", Value: m.Description})
if m.Schema != nil {
info = append(info, yaml.MapItem{Key: "schema", Value: m.Schema.ToRawInfo()})
}
@ -8396,6 +8489,9 @@ func (m *Response) ToRawInfo() interface{} {
// ToRawInfo returns a description of ResponseDefinitions suitable for JSON or YAML export.
func (m *ResponseDefinitions) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.AdditionalProperties != nil {
for _, item := range m.AdditionalProperties {
info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()})
@ -8425,6 +8521,9 @@ func (m *ResponseValue) ToRawInfo() interface{} {
// ToRawInfo returns a description of Responses suitable for JSON or YAML export.
func (m *Responses) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.ResponseCode != nil {
for _, item := range m.ResponseCode {
info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()})
@ -8443,6 +8542,9 @@ func (m *Responses) ToRawInfo() interface{} {
// ToRawInfo returns a description of Schema suitable for JSON or YAML export.
func (m *Schema) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.XRef != "" {
info = append(info, yaml.MapItem{Key: "$ref", Value: m.XRef})
}
@ -8588,6 +8690,9 @@ func (m *SchemaItem) ToRawInfo() interface{} {
// ToRawInfo returns a description of SecurityDefinitions suitable for JSON or YAML export.
func (m *SecurityDefinitions) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.AdditionalProperties != nil {
for _, item := range m.AdditionalProperties {
info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()})
@ -8637,6 +8742,9 @@ func (m *SecurityDefinitionsItem) ToRawInfo() interface{} {
// ToRawInfo returns a description of SecurityRequirement suitable for JSON or YAML export.
func (m *SecurityRequirement) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.AdditionalProperties != nil {
for _, item := range m.AdditionalProperties {
info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()})
@ -8654,9 +8762,11 @@ func (m *StringArray) ToRawInfo() interface{} {
// ToRawInfo returns a description of Tag suitable for JSON or YAML export.
func (m *Tag) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
if m == nil {
return info
}
// always include this required field.
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
if m.Description != "" {
info = append(info, yaml.MapItem{Key: "description", Value: m.Description})
}
@ -8676,6 +8786,9 @@ func (m *Tag) ToRawInfo() interface{} {
// ToRawInfo returns a description of TypeItem suitable for JSON or YAML export.
func (m *TypeItem) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if len(m.Value) != 0 {
info = append(info, yaml.MapItem{Key: "value", Value: m.Value})
}
@ -8685,6 +8798,9 @@ func (m *TypeItem) ToRawInfo() interface{} {
// ToRawInfo returns a description of VendorExtension suitable for JSON or YAML export.
func (m *VendorExtension) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.AdditionalProperties != nil {
for _, item := range m.AdditionalProperties {
info = append(info, yaml.MapItem{Key: item.Name, Value: item.Value.ToRawInfo()})
@ -8697,6 +8813,9 @@ func (m *VendorExtension) ToRawInfo() interface{} {
// ToRawInfo returns a description of Xml suitable for JSON or YAML export.
func (m *Xml) ToRawInfo() interface{} {
info := yaml.MapSlice{}
if m == nil {
return info
}
if m.Name != "" {
info = append(info, yaml.MapItem{Key: "name", Value: m.Name})
}

View File

@ -17,13 +17,14 @@ package compiler
import (
"errors"
"fmt"
"gopkg.in/yaml.v2"
"io/ioutil"
"log"
"net/http"
"net/url"
"path/filepath"
"strings"
yaml "gopkg.in/yaml.v2"
)
var fileCache map[string][]byte
@ -31,6 +32,8 @@ var infoCache map[string]interface{}
var count int64
var verboseReader = false
var fileCacheEnable = true
var infoCacheEnable = true
func initializeFileCache() {
if fileCache == nil {
@ -44,29 +47,56 @@ func initializeInfoCache() {
}
}
func DisableFileCache() {
fileCacheEnable = false
}
func DisableInfoCache() {
infoCacheEnable = false
}
func RemoveFromFileCache(fileurl string) {
if !fileCacheEnable {
return
}
initializeFileCache()
delete(fileCache, fileurl)
}
func RemoveFromInfoCache(filename string) {
if !infoCacheEnable {
return
}
initializeInfoCache()
delete(infoCache, filename)
}
// FetchFile gets a specified file from the local filesystem or a remote location.
func FetchFile(fileurl string) ([]byte, error) {
var bytes []byte
initializeFileCache()
bytes, ok := fileCache[fileurl]
if ok {
if verboseReader {
log.Printf("Cache hit %s", fileurl)
if fileCacheEnable {
bytes, ok := fileCache[fileurl]
if ok {
if verboseReader {
log.Printf("Cache hit %s", fileurl)
}
return bytes, nil
}
if verboseReader {
log.Printf("Fetching %s", fileurl)
}
return bytes, nil
}
if verboseReader {
log.Printf("Fetching %s", fileurl)
}
response, err := http.Get(fileurl)
if err != nil {
return nil, err
}
defer response.Body.Close()
if response.StatusCode != 200 {
return nil, errors.New(fmt.Sprintf("Error downloading %s: %s", fileurl, response.Status))
}
defer response.Body.Close()
bytes, err = ioutil.ReadAll(response.Body)
if err == nil {
if fileCacheEnable && err == nil {
fileCache[fileurl] = bytes
}
return bytes, err
@ -95,22 +125,24 @@ func ReadBytesForFile(filename string) ([]byte, error) {
// ReadInfoFromBytes unmarshals a file as a yaml.MapSlice.
func ReadInfoFromBytes(filename string, bytes []byte) (interface{}, error) {
initializeInfoCache()
cachedInfo, ok := infoCache[filename]
if ok {
if verboseReader {
log.Printf("Cache hit info for file %s", filename)
if infoCacheEnable {
cachedInfo, ok := infoCache[filename]
if ok {
if verboseReader {
log.Printf("Cache hit info for file %s", filename)
}
return cachedInfo, nil
}
if verboseReader {
log.Printf("Reading info for file %s", filename)
}
return cachedInfo, nil
}
if verboseReader {
log.Printf("Reading info for file %s", filename)
}
var info yaml.MapSlice
err := yaml.Unmarshal(bytes, &info)
if err != nil {
return nil, err
}
if len(filename) > 0 {
if infoCacheEnable && len(filename) > 0 {
infoCache[filename] = info
}
return info, nil
@ -119,7 +151,7 @@ func ReadInfoFromBytes(filename string, bytes []byte) (interface{}, error) {
// ReadInfoForRef reads a file and return the fragment needed to resolve a $ref.
func ReadInfoForRef(basefile string, ref string) (interface{}, error) {
initializeInfoCache()
{
if infoCacheEnable {
info, ok := infoCache[ref]
if ok {
if verboseReader {
@ -127,9 +159,9 @@ func ReadInfoForRef(basefile string, ref string) (interface{}, error) {
}
return info, nil
}
}
if verboseReader {
log.Printf("Reading info for ref %s#%s", basefile, ref)
if verboseReader {
log.Printf("Reading info for ref %s#%s", basefile, ref)
}
}
count = count + 1
basedir, _ := filepath.Split(basefile)
@ -170,6 +202,8 @@ func ReadInfoForRef(basefile string, ref string) (interface{}, error) {
}
}
}
infoCache[ref] = info
if infoCacheEnable {
infoCache[ref] = info
}
return info, nil
}

View File

@ -1,24 +1,12 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: extension.proto
/*
Package openapiextension_v1 is a generated protocol buffer package.
It is generated from these files:
extension.proto
It has these top-level messages:
Version
ExtensionHandlerRequest
ExtensionHandlerResponse
Wrapper
*/
package openapiextension_v1
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import google_protobuf "github.com/golang/protobuf/ptypes/any"
import any "github.com/golang/protobuf/ptypes/any"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
@ -33,18 +21,40 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// The version number of OpenAPI compiler.
type Version struct {
Major int32 `protobuf:"varint,1,opt,name=major" json:"major,omitempty"`
Minor int32 `protobuf:"varint,2,opt,name=minor" json:"minor,omitempty"`
Patch int32 `protobuf:"varint,3,opt,name=patch" json:"patch,omitempty"`
Major int32 `protobuf:"varint,1,opt,name=major,proto3" json:"major,omitempty"`
Minor int32 `protobuf:"varint,2,opt,name=minor,proto3" json:"minor,omitempty"`
Patch int32 `protobuf:"varint,3,opt,name=patch,proto3" json:"patch,omitempty"`
// A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should
// be empty for mainline stable releases.
Suffix string `protobuf:"bytes,4,opt,name=suffix" json:"suffix,omitempty"`
Suffix string `protobuf:"bytes,4,opt,name=suffix,proto3" json:"suffix,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Version) Reset() { *m = Version{} }
func (m *Version) String() string { return proto.CompactTextString(m) }
func (*Version) ProtoMessage() {}
func (*Version) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Version) Reset() { *m = Version{} }
func (m *Version) String() string { return proto.CompactTextString(m) }
func (*Version) ProtoMessage() {}
func (*Version) Descriptor() ([]byte, []int) {
return fileDescriptor_extension_d25f09c742c58c90, []int{0}
}
func (m *Version) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Version.Unmarshal(m, b)
}
func (m *Version) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Version.Marshal(b, m, deterministic)
}
func (dst *Version) XXX_Merge(src proto.Message) {
xxx_messageInfo_Version.Merge(dst, src)
}
func (m *Version) XXX_Size() int {
return xxx_messageInfo_Version.Size(m)
}
func (m *Version) XXX_DiscardUnknown() {
xxx_messageInfo_Version.DiscardUnknown(m)
}
var xxx_messageInfo_Version proto.InternalMessageInfo
func (m *Version) GetMajor() int32 {
if m != nil {
@ -78,15 +88,37 @@ func (m *Version) GetSuffix() string {
type ExtensionHandlerRequest struct {
// The OpenAPI descriptions that were explicitly listed on the command line.
// The specifications will appear in the order they are specified to gnostic.
Wrapper *Wrapper `protobuf:"bytes,1,opt,name=wrapper" json:"wrapper,omitempty"`
Wrapper *Wrapper `protobuf:"bytes,1,opt,name=wrapper,proto3" json:"wrapper,omitempty"`
// The version number of openapi compiler.
CompilerVersion *Version `protobuf:"bytes,3,opt,name=compiler_version,json=compilerVersion" json:"compiler_version,omitempty"`
CompilerVersion *Version `protobuf:"bytes,3,opt,name=compiler_version,json=compilerVersion,proto3" json:"compiler_version,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ExtensionHandlerRequest) Reset() { *m = ExtensionHandlerRequest{} }
func (m *ExtensionHandlerRequest) String() string { return proto.CompactTextString(m) }
func (*ExtensionHandlerRequest) ProtoMessage() {}
func (*ExtensionHandlerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *ExtensionHandlerRequest) Reset() { *m = ExtensionHandlerRequest{} }
func (m *ExtensionHandlerRequest) String() string { return proto.CompactTextString(m) }
func (*ExtensionHandlerRequest) ProtoMessage() {}
func (*ExtensionHandlerRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_extension_d25f09c742c58c90, []int{1}
}
func (m *ExtensionHandlerRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ExtensionHandlerRequest.Unmarshal(m, b)
}
func (m *ExtensionHandlerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ExtensionHandlerRequest.Marshal(b, m, deterministic)
}
func (dst *ExtensionHandlerRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ExtensionHandlerRequest.Merge(dst, src)
}
func (m *ExtensionHandlerRequest) XXX_Size() int {
return xxx_messageInfo_ExtensionHandlerRequest.Size(m)
}
func (m *ExtensionHandlerRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ExtensionHandlerRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ExtensionHandlerRequest proto.InternalMessageInfo
func (m *ExtensionHandlerRequest) GetWrapper() *Wrapper {
if m != nil {
@ -105,7 +137,7 @@ func (m *ExtensionHandlerRequest) GetCompilerVersion() *Version {
// The extensions writes an encoded ExtensionHandlerResponse to stdout.
type ExtensionHandlerResponse struct {
// true if the extension is handled by the extension handler; false otherwise
Handled bool `protobuf:"varint,1,opt,name=handled" json:"handled,omitempty"`
Handled bool `protobuf:"varint,1,opt,name=handled,proto3" json:"handled,omitempty"`
// Error message. If non-empty, the extension handling failed.
// The extension handler process should exit with status code zero
// even if it reports an error in this way.
@ -115,15 +147,37 @@ type ExtensionHandlerResponse struct {
// itself -- such as the input Document being unparseable -- should be
// reported by writing a message to stderr and exiting with a non-zero
// status code.
Error []string `protobuf:"bytes,2,rep,name=error" json:"error,omitempty"`
Error []string `protobuf:"bytes,2,rep,name=error,proto3" json:"error,omitempty"`
// text output
Value *google_protobuf.Any `protobuf:"bytes,3,opt,name=value" json:"value,omitempty"`
Value *any.Any `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ExtensionHandlerResponse) Reset() { *m = ExtensionHandlerResponse{} }
func (m *ExtensionHandlerResponse) String() string { return proto.CompactTextString(m) }
func (*ExtensionHandlerResponse) ProtoMessage() {}
func (*ExtensionHandlerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *ExtensionHandlerResponse) Reset() { *m = ExtensionHandlerResponse{} }
func (m *ExtensionHandlerResponse) String() string { return proto.CompactTextString(m) }
func (*ExtensionHandlerResponse) ProtoMessage() {}
func (*ExtensionHandlerResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_extension_d25f09c742c58c90, []int{2}
}
func (m *ExtensionHandlerResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ExtensionHandlerResponse.Unmarshal(m, b)
}
func (m *ExtensionHandlerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ExtensionHandlerResponse.Marshal(b, m, deterministic)
}
func (dst *ExtensionHandlerResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ExtensionHandlerResponse.Merge(dst, src)
}
func (m *ExtensionHandlerResponse) XXX_Size() int {
return xxx_messageInfo_ExtensionHandlerResponse.Size(m)
}
func (m *ExtensionHandlerResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ExtensionHandlerResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ExtensionHandlerResponse proto.InternalMessageInfo
func (m *ExtensionHandlerResponse) GetHandled() bool {
if m != nil {
@ -139,7 +193,7 @@ func (m *ExtensionHandlerResponse) GetError() []string {
return nil
}
func (m *ExtensionHandlerResponse) GetValue() *google_protobuf.Any {
func (m *ExtensionHandlerResponse) GetValue() *any.Any {
if m != nil {
return m.Value
}
@ -148,17 +202,39 @@ func (m *ExtensionHandlerResponse) GetValue() *google_protobuf.Any {
type Wrapper struct {
// version of the OpenAPI specification in which this extension was written.
Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"`
Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
// Name of the extension
ExtensionName string `protobuf:"bytes,2,opt,name=extension_name,json=extensionName" json:"extension_name,omitempty"`
ExtensionName string `protobuf:"bytes,2,opt,name=extension_name,json=extensionName,proto3" json:"extension_name,omitempty"`
// Must be a valid yaml for the proto
Yaml string `protobuf:"bytes,3,opt,name=yaml" json:"yaml,omitempty"`
Yaml string `protobuf:"bytes,3,opt,name=yaml,proto3" json:"yaml,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Wrapper) Reset() { *m = Wrapper{} }
func (m *Wrapper) String() string { return proto.CompactTextString(m) }
func (*Wrapper) ProtoMessage() {}
func (*Wrapper) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *Wrapper) Reset() { *m = Wrapper{} }
func (m *Wrapper) String() string { return proto.CompactTextString(m) }
func (*Wrapper) ProtoMessage() {}
func (*Wrapper) Descriptor() ([]byte, []int) {
return fileDescriptor_extension_d25f09c742c58c90, []int{3}
}
func (m *Wrapper) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Wrapper.Unmarshal(m, b)
}
func (m *Wrapper) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Wrapper.Marshal(b, m, deterministic)
}
func (dst *Wrapper) XXX_Merge(src proto.Message) {
xxx_messageInfo_Wrapper.Merge(dst, src)
}
func (m *Wrapper) XXX_Size() int {
return xxx_messageInfo_Wrapper.Size(m)
}
func (m *Wrapper) XXX_DiscardUnknown() {
xxx_messageInfo_Wrapper.DiscardUnknown(m)
}
var xxx_messageInfo_Wrapper proto.InternalMessageInfo
func (m *Wrapper) GetVersion() string {
if m != nil {
@ -188,9 +264,9 @@ func init() {
proto.RegisterType((*Wrapper)(nil), "openapiextension.v1.Wrapper")
}
func init() { proto.RegisterFile("extension.proto", fileDescriptor0) }
func init() { proto.RegisterFile("extension.proto", fileDescriptor_extension_d25f09c742c58c90) }
var fileDescriptor0 = []byte{
var fileDescriptor_extension_d25f09c742c58c90 = []byte{
// 357 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0x4d, 0x4b, 0xc3, 0x40,
0x18, 0x84, 0x49, 0xbf, 0x62, 0x56, 0x6c, 0x65, 0x2d, 0x1a, 0xc5, 0x43, 0x09, 0x08, 0x45, 0x64,

View File

@ -7,6 +7,8 @@ Package httpcache provides a http.RoundTripper implementation that works as a mo
It is only suitable for use as a 'private' cache (i.e. for a web-browser or an API-client and not for a shared proxy).
This project isn't actively maintained; it works for what I, and seemingly others, want to do with it, and I consider it "done". That said, if you find any issues, please open a Pull Request and I will try to review it. Any changes now that change the public API won't be considered.
Cache Backends
--------------
@ -19,6 +21,8 @@ Cache Backends
- [`github.com/die-net/lrucache/twotier`](https://github.com/die-net/lrucache/tree/master/twotier) allows caches to be combined, for example to use lrucache above with a persistent disk-cache.
- [`github.com/birkelund/boltdbcache`](https://github.com/birkelund/boltdbcache) provides a BoltDB implementation (based on the [bbolt](https://github.com/coreos/bbolt) fork).
If you implement any other backend and wish it to be linked here, please send a PR editing this file.
License
-------

View File

@ -1,7 +1,7 @@
// +build !ignore_autogenerated
/*
Copyright 2018 The Knative Authors
Copyright 2019 The Knative Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -16,13 +16,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1alpha1
import (
v1 "k8s.io/api/core/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
)
@ -108,12 +108,8 @@ func (in *BuildSpec) DeepCopyInto(out *BuildSpec) {
*out = *in
if in.Source != nil {
in, out := &in.Source, &out.Source
if *in == nil {
*out = nil
} else {
*out = new(SourceSpec)
(*in).DeepCopyInto(*out)
}
*out = new(SourceSpec)
(*in).DeepCopyInto(*out)
}
if in.Sources != nil {
in, out := &in.Sources, &out.Sources
@ -138,12 +134,8 @@ func (in *BuildSpec) DeepCopyInto(out *BuildSpec) {
}
if in.Template != nil {
in, out := &in.Template, &out.Template
if *in == nil {
*out = nil
} else {
*out = new(TemplateInstantiationSpec)
(*in).DeepCopyInto(*out)
}
*out = new(TemplateInstantiationSpec)
(*in).DeepCopyInto(*out)
}
if in.NodeSelector != nil {
in, out := &in.NodeSelector, &out.NodeSelector
@ -154,21 +146,13 @@ func (in *BuildSpec) DeepCopyInto(out *BuildSpec) {
}
if in.Timeout != nil {
in, out := &in.Timeout, &out.Timeout
if *in == nil {
*out = nil
} else {
*out = new(meta_v1.Duration)
**out = **in
}
*out = new(metav1.Duration)
**out = **in
}
if in.Affinity != nil {
in, out := &in.Affinity, &out.Affinity
if *in == nil {
*out = nil
} else {
*out = new(v1.Affinity)
(*in).DeepCopyInto(*out)
}
*out = new(v1.Affinity)
(*in).DeepCopyInto(*out)
}
return
}
@ -189,39 +173,21 @@ func (in *BuildStatus) DeepCopyInto(out *BuildStatus) {
in.Status.DeepCopyInto(&out.Status)
if in.Cluster != nil {
in, out := &in.Cluster, &out.Cluster
if *in == nil {
*out = nil
} else {
*out = new(ClusterSpec)
**out = **in
}
*out = new(ClusterSpec)
**out = **in
}
if in.Google != nil {
in, out := &in.Google, &out.Google
if *in == nil {
*out = nil
} else {
*out = new(GoogleSpec)
**out = **in
}
*out = new(GoogleSpec)
**out = **in
}
if in.StartTime != nil {
in, out := &in.StartTime, &out.StartTime
if *in == nil {
*out = nil
} else {
*out = new(meta_v1.Time)
(*in).DeepCopyInto(*out)
}
*out = (*in).DeepCopy()
}
if in.CompletionTime != nil {
in, out := &in.CompletionTime, &out.CompletionTime
if *in == nil {
*out = nil
} else {
*out = new(meta_v1.Time)
(*in).DeepCopyInto(*out)
}
*out = (*in).DeepCopy()
}
if in.StepStates != nil {
in, out := &in.StepStates, &out.StepStates
@ -474,12 +440,8 @@ func (in *ParameterSpec) DeepCopyInto(out *ParameterSpec) {
*out = *in
if in.Default != nil {
in, out := &in.Default, &out.Default
if *in == nil {
*out = nil
} else {
*out = new(string)
**out = **in
}
*out = new(string)
**out = **in
}
return
}
@ -499,30 +461,18 @@ func (in *SourceSpec) DeepCopyInto(out *SourceSpec) {
*out = *in
if in.Git != nil {
in, out := &in.Git, &out.Git
if *in == nil {
*out = nil
} else {
*out = new(GitSourceSpec)
**out = **in
}
*out = new(GitSourceSpec)
**out = **in
}
if in.GCS != nil {
in, out := &in.GCS, &out.GCS
if *in == nil {
*out = nil
} else {
*out = new(GCSSourceSpec)
**out = **in
}
*out = new(GCSSourceSpec)
**out = **in
}
if in.Custom != nil {
in, out := &in.Custom, &out.Custom
if *in == nil {
*out = nil
} else {
*out = new(v1.Container)
(*in).DeepCopyInto(*out)
}
*out = new(v1.Container)
(*in).DeepCopyInto(*out)
}
return
}

View File

@ -1,6 +1,4 @@
# The OWNERS file is used by prow to automatically merge approved PRs.
approvers:
- mattmoor
- vaikas-google
- n3wscott
- apis-approvers

View File

@ -42,10 +42,26 @@ func IsInCreate(ctx context.Context) bool {
// the receiver being validated is being updated.
type inUpdateKey struct{}
type updatePayload struct {
base interface{}
subresource string
}
// WithinUpdate is used to note that the webhook is calling within
// the context of a Update operation.
func WithinUpdate(ctx context.Context, base interface{}) context.Context {
return context.WithValue(ctx, inUpdateKey{}, base)
return context.WithValue(ctx, inUpdateKey{}, &updatePayload{
base: base,
})
}
// WithinSubResourceUpdate is used to note that the webhook is calling within
// the context of a Update operation on a subresource.
func WithinSubResourceUpdate(ctx context.Context, base interface{}, sr string) context.Context {
return context.WithValue(ctx, inUpdateKey{}, &updatePayload{
base: base,
subresource: sr,
})
}
// IsInUpdate checks whether the context is an Update.
@ -53,10 +69,24 @@ func IsInUpdate(ctx context.Context) bool {
return ctx.Value(inUpdateKey{}) != nil
}
// IsInStatusUpdate checks whether the context is an Update.
func IsInStatusUpdate(ctx context.Context) bool {
value := ctx.Value(inUpdateKey{})
if value == nil {
return false
}
up := value.(*updatePayload)
return up.subresource == "status"
}
// GetBaseline returns the baseline of the update, or nil when we
// are not within an update context.
func GetBaseline(ctx context.Context) interface{} {
return ctx.Value(inUpdateKey{})
value := ctx.Value(inUpdateKey{})
if value == nil {
return nil
}
return value.(*updatePayload).base
}
// This is attached to contexts passed to webhook interfaces when

View File

@ -1,5 +1,4 @@
# The OWNERS file is used by prow to automatically merge approved PRs.
approvers:
- mattmoor
- vaikas-google
- apis-duck-approvers

View File

@ -94,44 +94,36 @@ func AsStructuredWatcher(wf cache.WatchFunc, obj runtime.Object) cache.WatchFunc
go func() {
defer close(structuredCh)
unstructuredCh := uw.ResultChan()
for {
select {
case ue, ok := <-unstructuredCh:
if !ok {
// Channel is closed.
return
}
for ue := range unstructuredCh {
unstructuredObj, ok := ue.Object.(*unstructured.Unstructured)
if !ok {
// If it isn't an unstructured object, then forward the
// event as-is. This is likely to happen when the event's
// Type is an Error.
structuredCh <- ue
continue
}
structuredObj := obj.DeepCopyObject()
unstructuredObj, ok := ue.Object.(*unstructured.Unstructured)
if !ok {
// If it isn't an unstructured object, then forward the
// event as-is. This is likely to happen when the event's
// Type is an Error.
structuredCh <- ue
continue
}
structuredObj := obj.DeepCopyObject()
err := FromUnstructured(unstructuredObj, structuredObj)
if err != nil {
// Pass back an error indicating that the object we got
// was invalid.
structuredCh <- watch.Event{
Type: watch.Error,
Object: &metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusUnprocessableEntity,
Reason: metav1.StatusReasonInvalid,
Message: err.Error(),
},
}
continue
}
// Send the structured event.
err := FromUnstructured(unstructuredObj, structuredObj)
if err != nil {
// Pass back an error indicating that the object we got
// was invalid.
structuredCh <- watch.Event{
Type: ue.Type,
Object: structuredObj,
Type: watch.Error,
Object: &metav1.Status{
Status: metav1.StatusFailure,
Code: http.StatusUnprocessableEntity,
Reason: metav1.StatusReasonInvalid,
Message: err.Error(),
},
}
continue
}
// Send the structured event.
structuredCh <- watch.Event{
Type: ue.Type,
Object: structuredObj,
}
}
}()

View File

@ -76,11 +76,27 @@ func (t *AddressableType) Populate() {
t.Status = AddressStatus{
&Addressable{
// Populate ALL fields
Addressable: v1beta1.Addressable{
URL: &apis.URL{
Scheme: "http",
Host: "foo.bar.svc.cluster.local",
},
},
Hostname: "this is not empty",
},
}
}
func (a Addressable) GetURL() apis.URL {
if a.URL != nil {
return *a.URL
}
return apis.URL{
Scheme: "http",
Host: a.Hostname,
}
}
// GetListType implements apis.Listable
func (*AddressableType) GetListType() runtime.Object {
return &AddressableTypeList{}

View File

@ -1,5 +1,4 @@
# The OWNERS file is used by prow to automatically merge approved PRs.
approvers:
- mattmoor
- mdemirhan
- configmap-approvers

View File

@ -1,5 +1,4 @@
# The OWNERS file is used by prow to automatically merge approved PRs.
approvers:
- mattmoor
- jonjohnsonjr
- kmeta-approvers

View File

@ -273,7 +273,20 @@ func ConfigureServer(s *http.Server, conf *Server) error {
if testHookOnConn != nil {
testHookOnConn()
}
// The TLSNextProto interface predates contexts, so
// the net/http package passes down its per-connection
// base context via an exported but unadvertised
// method on the Handler. This is for internal
// net/http<=>http2 use only.
var ctx context.Context
type baseContexter interface {
BaseContext() context.Context
}
if bc, ok := h.(baseContexter); ok {
ctx = bc.BaseContext()
}
conf.ServeConn(c, &ServeConnOpts{
Context: ctx,
Handler: h,
BaseConfig: hs,
})
@ -284,6 +297,10 @@ func ConfigureServer(s *http.Server, conf *Server) error {
// ServeConnOpts are options for the Server.ServeConn method.
type ServeConnOpts struct {
// Context is the base context to use.
// If nil, context.Background is used.
Context context.Context
// BaseConfig optionally sets the base configuration
// for values. If nil, defaults are used.
BaseConfig *http.Server
@ -294,6 +311,13 @@ type ServeConnOpts struct {
Handler http.Handler
}
func (o *ServeConnOpts) context() context.Context {
if o.Context != nil {
return o.Context
}
return context.Background()
}
func (o *ServeConnOpts) baseConfig() *http.Server {
if o != nil && o.BaseConfig != nil {
return o.BaseConfig
@ -439,7 +463,7 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
}
func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx context.Context, cancel func()) {
ctx, cancel = context.WithCancel(context.Background())
ctx, cancel = context.WithCancel(opts.context())
ctx = context.WithValue(ctx, http.LocalAddrContextKey, c.LocalAddr())
if hs := opts.baseConfig(); hs != nil {
ctx = context.WithValue(ctx, http.ServerContextKey, hs)

View File

@ -194,9 +194,16 @@ func (cs computeSource) Token() (*oauth2.Token, error) {
if res.ExpiresInSec == 0 || res.AccessToken == "" {
return nil, fmt.Errorf("oauth2/google: incomplete token received from metadata")
}
return &oauth2.Token{
tok := &oauth2.Token{
AccessToken: res.AccessToken,
TokenType: res.TokenType,
Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second),
}, nil
}
// NOTE(cbro): add hidden metadata about where the token is from.
// This is needed for detection by client libraries to know that credentials come from the metadata server.
// This may be removed in a future version of this library.
return tok.WithExtra(map[string]interface{}{
"oauth2.google.tokenSource": "compute-metadata",
"oauth2.google.serviceAccount": acct,
}), nil
}

View File

@ -117,7 +117,7 @@ var (
// ApprovalForce forces the users to view the consent dialog
// and confirm the permissions request at the URL returned
// from AuthCodeURL, even if they've already done so.
ApprovalForce AuthCodeOption = SetAuthURLParam("approval_prompt", "force")
ApprovalForce AuthCodeOption = SetAuthURLParam("prompt", "consent")
)
// An AuthCodeOption is passed to Config.AuthCodeURL.

24
vendor/modules.txt vendored
View File

@ -4,7 +4,7 @@ cloud.google.com/go/compute/metadata
github.com/cpuguy83/go-md2man/md2man
# github.com/davecgh/go-spew v1.1.1
github.com/davecgh/go-spew/spew
# github.com/evanphx/json-patch v4.2.0+incompatible
# github.com/evanphx/json-patch v4.5.0+incompatible
github.com/evanphx/json-patch
# github.com/fsnotify/fsnotify v1.4.7
github.com/fsnotify/fsnotify
@ -29,15 +29,15 @@ github.com/google/go-cmp/cmp/internal/diff
github.com/google/go-cmp/cmp/internal/flags
github.com/google/go-cmp/cmp/internal/function
github.com/google/go-cmp/cmp/internal/value
# github.com/google/go-containerregistry v0.0.0-20190503220729-1c6c7f61e8a5
# github.com/google/go-containerregistry v0.0.0-20190623150931-ca8b66cb1b79
github.com/google/go-containerregistry/pkg/name
# github.com/google/gofuzz v1.0.0
github.com/google/gofuzz
# github.com/googleapis/gnostic v0.2.0
# github.com/googleapis/gnostic v0.3.0
github.com/googleapis/gnostic/OpenAPIv2
github.com/googleapis/gnostic/compiler
github.com/googleapis/gnostic/extensions
# github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc
# github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79
github.com/gregjones/httpcache
github.com/gregjones/httpcache/diskcache
# github.com/hashicorp/golang-lru v0.5.1
@ -60,10 +60,10 @@ github.com/imdario/mergo
github.com/inconshreveable/mousetrap
# github.com/json-iterator/go v1.1.6
github.com/json-iterator/go
# github.com/knative/build v0.6.0
# github.com/knative/build v0.7.0
github.com/knative/build/pkg/apis/build/v1alpha1
github.com/knative/build/pkg/apis/build
# github.com/knative/pkg v0.0.0-20190518173526-34792a92cec2
# github.com/knative/pkg v0.0.0-20190617142447-13b093adc272
github.com/knative/pkg/apis
github.com/knative/pkg/apis/duck/v1beta1
github.com/knative/pkg/kmp
@ -122,14 +122,14 @@ github.com/spf13/pflag
github.com/spf13/viper
# golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/crypto/ssh/terminal
# golang.org/x/net v0.0.0-20190514140710-3ec191127204
# golang.org/x/net v0.0.0-20190628185345-da137c7871d7
golang.org/x/net/http2
golang.org/x/net/http/httpguts
golang.org/x/net/http2/hpack
golang.org/x/net/idna
golang.org/x/net/context/ctxhttp
golang.org/x/net/context
# golang.org/x/oauth2 v0.0.0-20190517181255-950ef44c6e07
# golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
golang.org/x/oauth2
golang.org/x/oauth2/google
golang.org/x/oauth2/internal
@ -208,14 +208,14 @@ k8s.io/api/storage/v1beta1
k8s.io/apimachinery/pkg/apis/meta/v1
k8s.io/apimachinery/pkg/util/duration
k8s.io/apimachinery/pkg/apis/meta/v1beta1
k8s.io/apimachinery/pkg/labels
k8s.io/apimachinery/pkg/runtime
k8s.io/apimachinery/pkg/runtime/schema
k8s.io/apimachinery/pkg/fields
k8s.io/apimachinery/pkg/api/errors
k8s.io/apimachinery/pkg/api/resource
k8s.io/apimachinery/pkg/api/meta
k8s.io/apimachinery/pkg/util/runtime
k8s.io/apimachinery/pkg/runtime/schema
k8s.io/apimachinery/pkg/fields
k8s.io/apimachinery/pkg/labels
k8s.io/apimachinery/pkg/watch
k8s.io/apimachinery/pkg/api/equality
k8s.io/apimachinery/pkg/api/validation
@ -393,7 +393,7 @@ k8s.io/client-go/listers/settings/v1alpha1
k8s.io/client-go/listers/storage/v1
k8s.io/client-go/listers/storage/v1alpha1
k8s.io/client-go/listers/storage/v1beta1
# k8s.io/kube-openapi v0.0.0-20190510232812-a01b7d5d6c22
# k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208
k8s.io/kube-openapi/pkg/util/proto
# sigs.k8s.io/yaml v1.1.0
sigs.k8s.io/yaml