mirror of https://github.com/fluxcd/cli-utils.git
Adding status command
This commit is contained in:
parent
3021f2f069
commit
26d681d633
|
|
@ -15,11 +15,11 @@ package status
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/util"
|
||||
//"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/clik8s"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/util"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/wirecli/wirestatus"
|
||||
)
|
||||
|
||||
|
|
@ -34,11 +34,18 @@ func GetApplyStatusCommand(a util.Args) *cobra.Command {
|
|||
|
||||
cmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
for i := range args {
|
||||
r, err := wirestatus.DoStatus(clik8s.ResourceConfigPath(args[i]), cmd.OutOrStdout(), a)
|
||||
result, err := wirestatus.DoStatus(clik8s.ResourceConfigPath(args[i]), cmd.OutOrStdout(), a)
|
||||
for i := range result.Resources {
|
||||
u := result.Resources[i].Resource
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "%s/%s %s", u.GetKind(), u.GetName(), result.Resources[i].Status)
|
||||
if result.Resources[i].Error != nil {
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "(err: %s)", result.Resources[i].Error)
|
||||
}
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "\n")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cmd.OutOrStdout(), "Resources: %v\n", len(r.Resources))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
7
go.mod
7
go.mod
|
|
@ -7,22 +7,21 @@ require (
|
|||
github.com/Azure/go-autorest v11.7.0+incompatible // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch v4.1.0+incompatible
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-logr/logr v0.1.0 // indirect
|
||||
github.com/go-logr/zapr v0.1.1 // indirect
|
||||
github.com/go-openapi/spec v0.19.0 // indirect
|
||||
github.com/gogo/protobuf v1.2.1 // indirect
|
||||
github.com/golang/mock v1.2.0 // indirect
|
||||
github.com/google/btree v1.0.0 // indirect
|
||||
github.com/google/go-cmp v0.3.0 // indirect
|
||||
github.com/google/wire v0.2.2-0.20190423202733-d079521b6f51
|
||||
github.com/googleapis/gnostic v0.2.0 // indirect
|
||||
github.com/gophercloud/gophercloud v0.0.0-20190328150603-33e54f40ffcf // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.6.2 // indirect
|
||||
github.com/imdario/mergo v0.3.7 // indirect
|
||||
github.com/json-iterator/go v1.1.6 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/onsi/ginkgo v1.8.0
|
||||
github.com/onsi/gomega v1.5.0
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
|
|
@ -45,7 +44,7 @@ require (
|
|||
k8s.io/apiextensions-apiserver v0.0.0-20190328030136-8ada4fd07db4
|
||||
k8s.io/apimachinery v0.0.0-20190326224424-4ceb6b6c5db5
|
||||
k8s.io/client-go v11.0.0+incompatible
|
||||
k8s.io/klog v0.2.0 // indirect
|
||||
k8s.io/klog v0.3.2 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20190320154901-5e45bb682580 // indirect
|
||||
k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.1.10
|
||||
|
|
|
|||
17
go.sum
17
go.sum
|
|
@ -86,8 +86,6 @@ github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
|||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck=
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/wire v0.2.2-0.20190423202733-d079521b6f51 h1:oah2osnQk2JwZUU9BasNK201Ea2oNDY/3is4GYtnR7k=
|
||||
|
|
@ -101,9 +99,8 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51
|
|||
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/grpc-ecosystem/grpc-gateway v1.6.2 h1:8KyC64BiO8ndiGHY5DlFWWdangUPC9QHPakFRre/Ud0=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
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=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
|
|
@ -141,9 +138,8 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
|
|||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180228065516-1df9eeb2bb81 h1:ImOHKpmdLPXWX5KSYquUWXKaopEPuY7TPPUo18u9aOI=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180228065516-1df9eeb2bb81/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
|
|
@ -175,7 +171,6 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
|
|||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
|
|
@ -225,7 +220,6 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r
|
|||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -252,7 +246,6 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
|
@ -303,7 +296,6 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
|||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/src-d/go-billy.v4 v4.2.1 h1:omN5CrMrMcQ+4I8bJ0wEhOBPanIRWzFC953IiXKdYzo=
|
||||
gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.1.1 h1:XWW/s5W18RaJpmo1l0IYGqXKuJITWRFuA45iOf1dKJs=
|
||||
|
|
@ -314,7 +306,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep
|
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
@ -334,8 +325,8 @@ k8s.io/client-go v7.0.0+incompatible h1:kiH+Y6hn+pc78QS/mtBfMJAMIIaWevHi++JvOGEE
|
|||
k8s.io/client-go v7.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
|
||||
k8s.io/client-go v11.0.0+incompatible h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o=
|
||||
k8s.io/client-go v11.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
|
||||
k8s.io/klog v0.2.0 h1:0ElL0OHzF3N+OhoJTL0uca20SxtYt4X4+bzHeqrB83c=
|
||||
k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.3.2 h1:qvP/U6CcZ6qyi/qSHlJKdlAboCzo3mT0DAm0XAarpz4=
|
||||
k8s.io/klog v0.3.2/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/kube-openapi v0.0.0-20180510204742-b3f03f553288/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
|
||||
k8s.io/kube-openapi v0.0.0-20190320154901-5e45bb682580 h1:fq0ZXW/BAIFZH+dazlups6JTVdwzRo5d9riFA103yuQ=
|
||||
k8s.io/kube-openapi v0.0.0-20190320154901-5e45bb682580/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package unstructured
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
api_unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func jsonPath(fields []string) string {
|
||||
return "." + strings.Join(fields, ".")
|
||||
}
|
||||
|
||||
// NestedInt returns the int value of a nested field.
|
||||
// Returns false if value is not found and an error if not an int
|
||||
func NestedInt(obj map[string]interface{}, fields ...string) (int, bool, error) {
|
||||
var i int
|
||||
var i32 int32
|
||||
var i64 int64
|
||||
var ok bool
|
||||
|
||||
val, found, err := api_unstructured.NestedFieldNoCopy(obj, fields...)
|
||||
if !found || err != nil {
|
||||
return 0, found, err
|
||||
}
|
||||
i, ok = val.(int)
|
||||
if !ok {
|
||||
i32, ok = val.(int32)
|
||||
if ok {
|
||||
i = int(i32)
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
i64, ok = val.(int64)
|
||||
if ok {
|
||||
i = int(i64)
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return 0, true, fmt.Errorf("%v accessor error: %v is of the type %T, expected int", jsonPath(fields), val, val)
|
||||
}
|
||||
return i, true, nil
|
||||
}
|
||||
|
||||
// NestedMapSlice returns the value of a nested field.
|
||||
// Returns false if value is not found and an error if not an slice of maps.
|
||||
func NestedMapSlice(obj map[string]interface{}, fields ...string) ([]map[string]interface{}, bool, error) {
|
||||
val, found, err := api_unstructured.NestedFieldNoCopy(obj, fields...)
|
||||
if !found || err != nil {
|
||||
return nil, found, err
|
||||
}
|
||||
array, ok := val.([]interface{})
|
||||
if !ok {
|
||||
return nil, true, fmt.Errorf("%v accessor error: %v is of the type %T, expected []interface{}", jsonPath(fields), val, val)
|
||||
}
|
||||
|
||||
conditions := []map[string]interface{}{}
|
||||
|
||||
for i := range array {
|
||||
entry, ok := array[i].(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, true, fmt.Errorf("%v accessor error: %v[%d] is of the type %T, expected map[string]interface{}", jsonPath(fields), i, val, val)
|
||||
}
|
||||
conditions = append(conditions, entry)
|
||||
|
||||
}
|
||||
return conditions, true, nil
|
||||
}
|
||||
|
||||
// GetStringField - return field as string defaulting to value if not found
|
||||
func GetStringField(obj map[string]interface{}, field, defaultValue string) string {
|
||||
value := defaultValue
|
||||
fieldV, ok := obj[field]
|
||||
if ok {
|
||||
stringV, ok := fieldV.(string)
|
||||
if ok {
|
||||
value = stringV
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// GetConditions - return conditions array as []map[string]interface{}
|
||||
func GetConditions(obj map[string]interface{}) []map[string]interface{} {
|
||||
conditions, ok, err := NestedMapSlice(obj, "status", "conditions")
|
||||
if err != nil {
|
||||
fmt.Printf("err: %s", err)
|
||||
return []map[string]interface{}{}
|
||||
}
|
||||
if !ok {
|
||||
return []map[string]interface{}{}
|
||||
}
|
||||
return conditions
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package unstructured_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
helperu "sigs.k8s.io/cli-experimental/internal/pkg/client/unstructured"
|
||||
)
|
||||
|
||||
var emptyObj = map[string]interface{}{}
|
||||
var testObj = map[string]interface{}{
|
||||
"f1": map[string]interface{}{
|
||||
"f1f2": map[string]interface{}{
|
||||
"f1f2i32": int32(32),
|
||||
"f1f2i64": int64(64),
|
||||
"f1f2float": 64.02,
|
||||
"f1f2ms": []interface{}{
|
||||
map[string]interface{}{"f1f2ms0f1": 22},
|
||||
map[string]interface{}{"f1f2ms1f1": "index1"},
|
||||
},
|
||||
"f1f2msbad": []interface{}{
|
||||
map[string]interface{}{"f1f2ms0f1": 22},
|
||||
32,
|
||||
},
|
||||
},
|
||||
},
|
||||
"f2": map[string]interface{}{
|
||||
"f2f2": map[string]interface{}{},
|
||||
},
|
||||
|
||||
"ride": "dragon",
|
||||
|
||||
"status": map[string]interface{}{
|
||||
"conditions": []interface{}{
|
||||
map[string]interface{}{"f1f2ms0f1": 22},
|
||||
map[string]interface{}{"f1f2ms1f1": "index1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestNestedInt(t *testing.T) {
|
||||
v, found, err := helperu.NestedInt(testObj, "f1", "f1f2", "f1f2i32")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, found, true)
|
||||
assert.Equal(t, int(32), v)
|
||||
|
||||
v, found, err = helperu.NestedInt(testObj, "f1", "f1f2", "wrongname")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, found, false)
|
||||
assert.Equal(t, int(0), v)
|
||||
|
||||
v, found, err = helperu.NestedInt(testObj, "f1", "f1f2", "f1f2i64")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, found, true)
|
||||
assert.Equal(t, int(64), v)
|
||||
|
||||
v, found, err = helperu.NestedInt(testObj, "f1", "f1f2", "f1f2float")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, found, true)
|
||||
assert.Equal(t, int(0), v)
|
||||
}
|
||||
|
||||
func TestGetStringField(t *testing.T) {
|
||||
v := helperu.GetStringField(testObj, "ride", "horse")
|
||||
assert.Equal(t, v, "dragon")
|
||||
|
||||
v = helperu.GetStringField(testObj, "destination", "north")
|
||||
assert.Equal(t, v, "north")
|
||||
}
|
||||
|
||||
func TestNestedMapSlice(t *testing.T) {
|
||||
v, found, err := helperu.NestedMapSlice(testObj, "f1", "f1f2", "f1f2ms")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, found, true)
|
||||
assert.Equal(t, []map[string]interface{}{
|
||||
map[string]interface{}{"f1f2ms0f1": 22},
|
||||
map[string]interface{}{"f1f2ms1f1": "index1"},
|
||||
}, v)
|
||||
|
||||
v, found, err = helperu.NestedMapSlice(testObj, "f1", "f1f2", "f1f2msbad")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, found, true)
|
||||
assert.Equal(t, []map[string]interface{}(nil), v)
|
||||
|
||||
v, found, err = helperu.NestedMapSlice(testObj, "f1", "f1f2", "wrongname")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, found, false)
|
||||
assert.Equal(t, []map[string]interface{}(nil), v)
|
||||
|
||||
v, found, err = helperu.NestedMapSlice(testObj, "f1", "f1f2", "f1f2i64")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, found, true)
|
||||
assert.Equal(t, []map[string]interface{}(nil), v)
|
||||
}
|
||||
|
||||
func TestGetConditions(t *testing.T) {
|
||||
v := helperu.GetConditions(emptyObj)
|
||||
assert.Equal(t, []map[string]interface{}{}, v)
|
||||
|
||||
v = helperu.GetConditions(testObj)
|
||||
assert.Equal(t, []map[string]interface{}{
|
||||
map[string]interface{}{"f1f2ms0f1": 22},
|
||||
map[string]interface{}{"f1f2ms1f1": "index1"},
|
||||
}, v)
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package status
|
||||
|
||||
/*
|
||||
Status
|
||||
*/
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package status
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
clientu "sigs.k8s.io/cli-experimental/internal/pkg/client/unstructured"
|
||||
)
|
||||
|
||||
func readyConditionReader(u *unstructured.Unstructured) (bool, error) {
|
||||
conditions := clientu.GetConditions(u.UnstructuredContent())
|
||||
for _, c := range conditions {
|
||||
if clientu.GetStringField(c, "type", "") == "Ready" && clientu.GetStringField(c, "status", "") == "False" {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetGenericReadyFn - True if we handle it as a known type
|
||||
func GetGenericReadyFn(u *unstructured.Unstructured) IsReadyFn {
|
||||
return readyConditionReader
|
||||
}
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package status
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
clientu "sigs.k8s.io/cli-experimental/internal/pkg/client/unstructured"
|
||||
)
|
||||
|
||||
// IsReadyFn - status getter
|
||||
type IsReadyFn func(*unstructured.Unstructured) (bool, error)
|
||||
|
||||
var legacyTypes = map[string]map[string]IsReadyFn{
|
||||
"": map[string]IsReadyFn{
|
||||
"Service": alwaysReady,
|
||||
"Pod": podReady,
|
||||
"PersistentVolumeClaim": pvcReady,
|
||||
},
|
||||
"apps": map[string]IsReadyFn{
|
||||
"StatefulSet": stsReady,
|
||||
"DaemonSet": daemonsetReady,
|
||||
"Deployment": deploymentReady,
|
||||
"ReplicaSet": replicasetReady,
|
||||
},
|
||||
"policy": map[string]IsReadyFn{
|
||||
"PodDisruptionBudget": pdbReady,
|
||||
},
|
||||
"batch": map[string]IsReadyFn{
|
||||
"CronJob": cronjobReady,
|
||||
"Job": jobReady,
|
||||
},
|
||||
}
|
||||
|
||||
// GetLegacyReadyFn - True if we handle it as a known type
|
||||
func GetLegacyReadyFn(u *unstructured.Unstructured) IsReadyFn {
|
||||
gvk := u.GroupVersionKind()
|
||||
g := gvk.Group
|
||||
k := gvk.Kind
|
||||
if _, ok := legacyTypes[g]; ok {
|
||||
if fn, ok := legacyTypes[g][k]; ok {
|
||||
return fn
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func alwaysReady(u *unstructured.Unstructured) (bool, error) { return true, nil }
|
||||
|
||||
func compareIntFields(u *unstructured.Unstructured, field1, field2 []string, checkFuncs ...func(int, int) bool) (bool, error) {
|
||||
v1, ok, err := clientu.NestedInt(u.UnstructuredContent(), field1...)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
if !ok {
|
||||
return false, fmt.Errorf("%v not found", field1)
|
||||
}
|
||||
|
||||
v2, ok, err := clientu.NestedInt(u.UnstructuredContent(), field2...)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
if !ok {
|
||||
return false, fmt.Errorf("%v not found", field2)
|
||||
}
|
||||
|
||||
rv := true
|
||||
|
||||
for _, fn := range checkFuncs {
|
||||
rv = rv && fn(v1, v2)
|
||||
}
|
||||
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
func equalInt(v1, v2 int) bool { return v1 == v2 }
|
||||
func geInt(v1, v2 int) bool { return v1 >= v2 }
|
||||
|
||||
// Statefulset
|
||||
func stsReady(u *unstructured.Unstructured) (bool, error) {
|
||||
c1, err := compareIntFields(u, []string{"status", "readyReplicas"}, []string{"spec", "replicas"}, equalInt)
|
||||
if err != nil {
|
||||
return c1, err
|
||||
}
|
||||
c2, err := compareIntFields(u, []string{"status", "currentReplicas"}, []string{"spec", "replicas"}, equalInt)
|
||||
if err != nil {
|
||||
return c2, err
|
||||
}
|
||||
return c1 && c2, nil
|
||||
}
|
||||
|
||||
// Deployment
|
||||
func deploymentReady(u *unstructured.Unstructured) (bool, error) {
|
||||
progress := true
|
||||
available := true
|
||||
conditions := clientu.GetConditions(u.UnstructuredContent())
|
||||
|
||||
if len(conditions) == 0 {
|
||||
return false, fmt.Errorf("no conditions in object")
|
||||
}
|
||||
|
||||
for _, c := range conditions {
|
||||
switch clientu.GetStringField(c, "type", "") {
|
||||
case "Progressing": //appsv1.DeploymentProgressing:
|
||||
// https://github.com/kubernetes/kubernetes/blob/a3ccea9d8743f2ff82e41b6c2af6dc2c41dc7b10/pkg/controller/deployment/progress.go#L52
|
||||
status := clientu.GetStringField(c, "status", "")
|
||||
reason := clientu.GetStringField(c, "reason", "")
|
||||
if status != "True" || reason != "NewReplicaSetAvailable" {
|
||||
progress = false
|
||||
}
|
||||
case "Available": //appsv1.DeploymentAvailable:
|
||||
status := clientu.GetStringField(c, "status", "")
|
||||
if status == "False" {
|
||||
available = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return progress && available, nil
|
||||
}
|
||||
|
||||
// Replicaset
|
||||
func replicasetReady(u *unstructured.Unstructured) (bool, error) {
|
||||
failure := false
|
||||
conditions := clientu.GetConditions(u.UnstructuredContent())
|
||||
|
||||
for _, c := range conditions {
|
||||
switch clientu.GetStringField(c, "type", "") {
|
||||
// https://github.com/kubernetes/kubernetes/blob/a3ccea9d8743f2ff82e41b6c2af6dc2c41dc7b10/pkg/controller/replicaset/replica_set_utils.go
|
||||
case "ReplicaFailure": //appsv1.ReplicaSetReplicaFailure
|
||||
status := clientu.GetStringField(c, "status", "")
|
||||
if status == "True" {
|
||||
failure = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c1, err := compareIntFields(u, []string{"status", "replicas"}, []string{"status", "readyReplicas"}, equalInt)
|
||||
if err != nil {
|
||||
return c1, err
|
||||
}
|
||||
c2, err := compareIntFields(u, []string{"status", "replicas"}, []string{"status", "availableReplicas"}, equalInt)
|
||||
if err != nil {
|
||||
return c2, err
|
||||
}
|
||||
|
||||
return !failure && c1 && c2, nil
|
||||
}
|
||||
|
||||
// Daemonset
|
||||
func daemonsetReady(u *unstructured.Unstructured) (bool, error) {
|
||||
c1, err := compareIntFields(u, []string{"status", "desiredNumberScheduled"}, []string{"status", "numberAvailable"}, equalInt)
|
||||
if err != nil {
|
||||
return c1, err
|
||||
}
|
||||
c2, err := compareIntFields(u, []string{"status", "desiredNumberScheduled"}, []string{"status", "numberReady"}, equalInt)
|
||||
if err != nil {
|
||||
return c2, err
|
||||
}
|
||||
|
||||
return c1 && c2, nil
|
||||
}
|
||||
|
||||
// PVC
|
||||
func pvcReady(u *unstructured.Unstructured) (bool, error) {
|
||||
val, found, err := unstructured.NestedString(u.UnstructuredContent(), "status", "phase")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !found {
|
||||
return false, fmt.Errorf(".status.phase not found")
|
||||
}
|
||||
return val == "Bound", nil // corev1.ClaimBound
|
||||
}
|
||||
|
||||
// Pod
|
||||
func podReady(u *unstructured.Unstructured) (bool, error) {
|
||||
conditions := clientu.GetConditions(u.UnstructuredContent())
|
||||
|
||||
for _, c := range conditions {
|
||||
if clientu.GetStringField(c, "type", "") == "Ready" && (clientu.GetStringField(c, "status", "") == "True" || clientu.GetStringField(c, "reason", "") == "PodCompleted") {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// PodDisruptionBudget
|
||||
func pdbReady(u *unstructured.Unstructured) (bool, error) {
|
||||
return compareIntFields(u, []string{"status", "currentHealthy"}, []string{"status", "desiredHealthy"}, geInt)
|
||||
}
|
||||
|
||||
// Cronjob
|
||||
func cronjobReady(u *unstructured.Unstructured) (bool, error) {
|
||||
obj := u.UnstructuredContent()
|
||||
_, ok := obj["status"]
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Job
|
||||
func jobReady(u *unstructured.Unstructured) (bool, error) {
|
||||
complete := false
|
||||
failed := false
|
||||
|
||||
conditions := clientu.GetConditions(u.UnstructuredContent())
|
||||
|
||||
// https://github.com/kubernetes/kubernetes/blob/master/pkg/controller/job/utils.go#L24
|
||||
for _, c := range conditions {
|
||||
status := clientu.GetStringField(c, "status", "")
|
||||
switch clientu.GetStringField(c, "type", "") {
|
||||
case "Complete":
|
||||
if status == "True" {
|
||||
complete = true
|
||||
}
|
||||
case "Failed":
|
||||
if status == "True" {
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return complete || failed, nil
|
||||
}
|
||||
|
|
@ -14,41 +14,92 @@ limitations under the License.
|
|||
package status
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/errors"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/client"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/clik8s"
|
||||
)
|
||||
|
||||
// Status returns the status for rollouts
|
||||
type Status struct {
|
||||
// DynamicClient is the client used to talk
|
||||
// with the cluster
|
||||
DynamicClient client.Client
|
||||
// Out stores the output
|
||||
Out io.Writer
|
||||
// Resources is a list of resource configurations
|
||||
Resources clik8s.ResourceConfigs
|
||||
Out io.Writer
|
||||
Clientset *kubernetes.Clientset
|
||||
Commit *object.Commit
|
||||
// Commit is a git commit object
|
||||
Commit *object.Commit
|
||||
}
|
||||
|
||||
// ResourceStatus - resource status
|
||||
type ResourceStatus struct {
|
||||
Resource *unstructured.Unstructured
|
||||
Status string
|
||||
Error error
|
||||
}
|
||||
|
||||
// Result contains the Status Result
|
||||
type Result struct {
|
||||
Resources clik8s.ResourceConfigs
|
||||
Ready bool
|
||||
Resources []ResourceStatus
|
||||
}
|
||||
|
||||
// Do executes the apply
|
||||
func (s *Status) Do() (Result, error) {
|
||||
fmt.Fprintf(s.Out, "Doing `cli-experimental apply status`\n")
|
||||
if s.Commit != nil {
|
||||
fmt.Fprintf(s.Out, "Commit %s\n", s.Commit.Hash.String())
|
||||
}
|
||||
pods, err := s.Clientset.CoreV1().Pods("default").List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return Result{}, err
|
||||
}
|
||||
for _, p := range pods.Items {
|
||||
fmt.Fprintf(s.Out, "Pod %s\n", p.Name)
|
||||
// Do executes the status
|
||||
func (a *Status) Do() (Result, error) {
|
||||
ready := true
|
||||
var errs []error
|
||||
var rs = []ResourceStatus{}
|
||||
|
||||
fmt.Fprintf(a.Out, "Doing `cli-experimental apply status`\n")
|
||||
ctx := context.Background()
|
||||
for _, u := range a.Resources {
|
||||
err := a.DynamicClient.Get(ctx,
|
||||
types.NamespacedName{Namespace: u.GetNamespace(), Name: u.GetName()}, u)
|
||||
if err != nil {
|
||||
rs = append(rs, ResourceStatus{Resource: u, Status: "GET_ERROR", Error: err})
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Ready indicator is a simple ANDing of all the individual resource readiness
|
||||
uReady, err := IsReady(u)
|
||||
if err != nil {
|
||||
rs = append(rs, ResourceStatus{Resource: u, Status: "ERROR", Error: err})
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
status := "Ready"
|
||||
if !ready {
|
||||
status = "InProgress"
|
||||
}
|
||||
rs = append(rs, ResourceStatus{Resource: u, Status: status, Error: nil})
|
||||
ready = ready && uReady
|
||||
}
|
||||
|
||||
return Result{Resources: s.Resources}, nil
|
||||
if len(errs) != 0 {
|
||||
return Result{Ready: ready, Resources: rs}, errors.NewAggregate(errs)
|
||||
}
|
||||
return Result{Ready: ready, Resources: rs}, nil
|
||||
}
|
||||
|
||||
// IsReady - return true if object is ready
|
||||
func IsReady(u *unstructured.Unstructured) (bool, error) {
|
||||
fn := GetLegacyReadyFn(u)
|
||||
if fn == nil {
|
||||
fn = GetGenericReadyFn(u)
|
||||
}
|
||||
|
||||
if fn != nil {
|
||||
return fn(u)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,19 +17,663 @@ import (
|
|||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/clik8s"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/status"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/wirecli/wiretest"
|
||||
)
|
||||
|
||||
func TestStatus(t *testing.T) {
|
||||
func noitems() clik8s.ResourceConfigs {
|
||||
return clik8s.ResourceConfigs(nil)
|
||||
}
|
||||
|
||||
func y2u(t *testing.T, spec string) *unstructured.Unstructured {
|
||||
j, err := yaml.YAMLToJSON([]byte(spec))
|
||||
assert.NoError(t, err)
|
||||
u, _, err := unstructured.UnstructuredJSONScheme.Decode(j, nil, nil)
|
||||
assert.NoError(t, err)
|
||||
return u.(*unstructured.Unstructured)
|
||||
}
|
||||
|
||||
func TestEmptyStatus(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
a, done, err := wiretest.InitializeStatus(clik8s.ResourceConfigs(nil), &object.Commit{}, buf)
|
||||
a, done, err := wiretest.InitializeStatus(noitems(), &object.Commit{}, buf)
|
||||
defer done()
|
||||
assert.NoError(t, err)
|
||||
r, err := a.Do()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, status.Result{}, r)
|
||||
assert.Equal(t, status.Result{Ready: true, Resources: []status.ResourceStatus{}}, r)
|
||||
}
|
||||
|
||||
var podNoStatus = `
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: test
|
||||
`
|
||||
var podReady = `
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
conditions:
|
||||
- type: Ready
|
||||
status: "True"
|
||||
`
|
||||
|
||||
var podCompletedOK = `
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
phase: Succeeded
|
||||
conditions:
|
||||
- type: Ready
|
||||
status: "False"
|
||||
reason: PodCompleted
|
||||
|
||||
`
|
||||
|
||||
var podCompletedFail = `
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
phase: Failed
|
||||
conditions:
|
||||
- type: Ready
|
||||
status: "False"
|
||||
reason: PodCompleted
|
||||
|
||||
`
|
||||
|
||||
// Test coverage using IsReady
|
||||
func TestPodStatus(t *testing.T) {
|
||||
r, err := status.IsReady(y2u(t, podNoStatus))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
for _, spec := range []string{podReady, podCompletedOK, podCompletedFail} {
|
||||
r, err = status.IsReady(y2u(t, spec))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
}
|
||||
}
|
||||
|
||||
var pvcNoStatus = `
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: test
|
||||
`
|
||||
var pvcBound = `
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
phase: Bound
|
||||
`
|
||||
|
||||
var pvcUnBound = `
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
phase: UnBound
|
||||
`
|
||||
|
||||
func TestPVCStatus(t *testing.T) {
|
||||
r, err := status.IsReady(y2u(t, pvcNoStatus))
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, pvcBound))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, pvcUnBound))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
}
|
||||
|
||||
var stsNoStatus = `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: test
|
||||
`
|
||||
var stsBadStatus = `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
currentReplicas: 1
|
||||
`
|
||||
|
||||
var stsOK = `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
spec:
|
||||
replicas: 4
|
||||
status:
|
||||
currentReplicas: 4
|
||||
readyReplicas: 4
|
||||
`
|
||||
|
||||
var stsLessReady = `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
spec:
|
||||
replicas: 4
|
||||
status:
|
||||
currentReplicas: 4
|
||||
readyReplicas: 2
|
||||
`
|
||||
var stsLessCurrent = `
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
spec:
|
||||
replicas: 4
|
||||
status:
|
||||
currentReplicas: 2
|
||||
readyReplicas: 4
|
||||
`
|
||||
|
||||
func TestStsStatus(t *testing.T) {
|
||||
r, err := status.IsReady(y2u(t, stsNoStatus))
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, stsBadStatus))
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, stsOK))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, stsLessReady))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, stsLessCurrent))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
}
|
||||
|
||||
var dsNoStatus = `
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: test
|
||||
`
|
||||
var dsBadStatus = `
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
currentReplicas: 1
|
||||
`
|
||||
|
||||
var dsOK = `
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
desiredNumberScheduled: 4
|
||||
numberAvailable: 4
|
||||
numberReady: 4
|
||||
`
|
||||
|
||||
var dsLessReady = `
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
desiredNumberScheduled: 4
|
||||
numberAvailable: 4
|
||||
numberReady: 2
|
||||
`
|
||||
var dsLessAvailable = `
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
desiredNumberScheduled: 4
|
||||
numberAvailable: 2
|
||||
numberReady: 4
|
||||
`
|
||||
|
||||
func TestDaemonsetStatus(t *testing.T) {
|
||||
r, err := status.IsReady(y2u(t, dsNoStatus))
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, dsBadStatus))
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, dsOK))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, dsLessReady))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, dsLessAvailable))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
}
|
||||
|
||||
var depNoStatus = `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test
|
||||
`
|
||||
|
||||
var depOK = `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
conditions:
|
||||
- type: Progressing
|
||||
status: "True"
|
||||
reason: NewReplicaSetAvailable
|
||||
- type: Available
|
||||
status: "True"
|
||||
`
|
||||
|
||||
var depNotProgressing = `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
conditions:
|
||||
- type: Progressing
|
||||
status: "False"
|
||||
reason: Some reason
|
||||
- type: Available
|
||||
status: "True"
|
||||
`
|
||||
|
||||
var depNotAvailable = `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
conditions:
|
||||
- type: Progressing
|
||||
status: "True"
|
||||
reason: NewReplicaSetAvailable
|
||||
- type: Available
|
||||
status: "False"
|
||||
`
|
||||
|
||||
func TestDeploymentStatus(t *testing.T) {
|
||||
r, err := status.IsReady(y2u(t, depNoStatus))
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, depOK))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, depNotProgressing))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, depNotAvailable))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
}
|
||||
|
||||
var rsNoStatus = `
|
||||
apiVersion: apps/v1
|
||||
kind: ReplicaSet
|
||||
metadata:
|
||||
name: test
|
||||
`
|
||||
|
||||
var rsOK1 = `
|
||||
apiVersion: apps/v1
|
||||
kind: ReplicaSet
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
replicas: 2
|
||||
readyReplicas: 2
|
||||
availableReplicas: 2
|
||||
conditions:
|
||||
- type: ReplicaFailure
|
||||
status: "False"
|
||||
`
|
||||
|
||||
var rsOK2 = `
|
||||
apiVersion: apps/v1
|
||||
kind: ReplicaSet
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
replicas: 2
|
||||
readyReplicas: 2
|
||||
availableReplicas: 2
|
||||
`
|
||||
|
||||
var rsLessReady = `
|
||||
apiVersion: apps/v1
|
||||
kind: ReplicaSet
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
replicas: 4
|
||||
readyReplicas: 2
|
||||
availableReplicas: 4
|
||||
`
|
||||
|
||||
var rsLessAvailable = `
|
||||
apiVersion: apps/v1
|
||||
kind: ReplicaSet
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
replicas: 4
|
||||
readyReplicas: 4
|
||||
availableReplicas: 2
|
||||
`
|
||||
|
||||
var rsReplicaFailure = `
|
||||
apiVersion: apps/v1
|
||||
kind: ReplicaSet
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
replicas: 4
|
||||
readyReplicas: 4
|
||||
availableReplicas: 4
|
||||
conditions:
|
||||
- type: ReplicaFailure
|
||||
status: "True"
|
||||
`
|
||||
|
||||
func TestReplicasetStatus(t *testing.T) {
|
||||
r, err := status.IsReady(y2u(t, rsNoStatus))
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, rsOK1))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, rsOK2))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, rsLessAvailable))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, rsLessReady))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, rsReplicaFailure))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
}
|
||||
|
||||
var pdbNoStatus = `
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: test
|
||||
`
|
||||
|
||||
var pdbOK1 = `
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
currentHealthy: 2
|
||||
desiredHealthy: 2
|
||||
`
|
||||
|
||||
var pdbMoreHealthy = `
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
currentHealthy: 4
|
||||
desiredHealthy: 2
|
||||
`
|
||||
|
||||
var pdbLessHealthy = `
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
currentHealthy: 2
|
||||
desiredHealthy: 4
|
||||
`
|
||||
|
||||
func TestPDBStatus(t *testing.T) {
|
||||
r, err := status.IsReady(y2u(t, pdbNoStatus))
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, pdbOK1))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, pdbMoreHealthy))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, pdbLessHealthy))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
}
|
||||
|
||||
var crdNoStatus = `
|
||||
apiVersion: something/v1
|
||||
kind: MyCR
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
`
|
||||
|
||||
var crdReady = `
|
||||
apiVersion: something/v1
|
||||
kind: MyCR
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
conditions:
|
||||
- type: Ready
|
||||
status: "True"
|
||||
`
|
||||
|
||||
var crdNotReady = `
|
||||
apiVersion: something/v1
|
||||
kind: MyCR
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
conditions:
|
||||
- type: Ready
|
||||
status: "False"
|
||||
`
|
||||
|
||||
var crdNoCondition = `
|
||||
apiVersion: something/v1
|
||||
kind: MyCR
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
conditions:
|
||||
- type: SomeCondition
|
||||
status: "False"
|
||||
`
|
||||
|
||||
func TestCRDGenericStatus(t *testing.T) {
|
||||
r, err := status.IsReady(y2u(t, crdNoStatus))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, crdReady))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, crdNotReady))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, crdNoCondition))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
}
|
||||
|
||||
var jobNoStatus = `
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
`
|
||||
|
||||
var jobComplete = `
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
conditions:
|
||||
- type: Complete
|
||||
status: "True"
|
||||
`
|
||||
|
||||
var jobFailed = `
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
conditions:
|
||||
- type: Failed
|
||||
status: "True"
|
||||
`
|
||||
|
||||
var jobInProgress = `
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
conditions:
|
||||
- type: Failed
|
||||
status: "False"
|
||||
- type: Complete
|
||||
status: "False"
|
||||
`
|
||||
|
||||
func TestJobStatus(t *testing.T) {
|
||||
r, err := status.IsReady(y2u(t, jobNoStatus))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, jobComplete))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, jobFailed))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, jobInProgress))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
}
|
||||
|
||||
var cronjobNoStatus = `
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
`
|
||||
|
||||
var cronjobWithStatus = `
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: test
|
||||
namespace: qual
|
||||
status:
|
||||
`
|
||||
|
||||
func TestCronJobStatus(t *testing.T) {
|
||||
r, err := status.IsReady(y2u(t, cronjobNoStatus))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, r)
|
||||
|
||||
r, err = status.IsReady(y2u(t, cronjobWithStatus))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, r)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,26 @@ import (
|
|||
// Injectors from wire.go:
|
||||
|
||||
func InitializeStatus(resourceConfigPath clik8s.ResourceConfigPath, writer io.Writer, args util.Args) (*status.Status, error) {
|
||||
configFlags, err := wirek8s.NewConfigFlags(args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config, err := wirek8s.NewRestConfig(configFlags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dynamicInterface, err := wirek8s.NewDynamicClient(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
restMapper, err := wirek8s.NewRestMapper(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := wirek8s.NewClient(dynamicInterface, restMapper)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pluginConfig := wireconfig.NewPluginConfig()
|
||||
factory := wireconfig.NewResMapFactory(pluginConfig)
|
||||
fileSystem := wireconfig.NewFileSystem()
|
||||
|
|
@ -27,31 +47,39 @@ func InitializeStatus(resourceConfigPath clik8s.ResourceConfigPath, writer io.Wr
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configFlags, err := wirek8s.NewConfigFlags(args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config, err := wirek8s.NewRestConfig(configFlags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clientset, err := wirek8s.NewKubernetesClientSet(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repository := wiregit.NewOptionalRepository(resourceConfigPath)
|
||||
commitIter := wiregit.NewOptionalCommitIter(repository)
|
||||
commit := wiregit.NewOptionalCommit(commitIter)
|
||||
statusStatus := &status.Status{
|
||||
Resources: resourceConfigs,
|
||||
Out: writer,
|
||||
Clientset: clientset,
|
||||
Commit: commit,
|
||||
DynamicClient: client,
|
||||
Out: writer,
|
||||
Resources: resourceConfigs,
|
||||
Commit: commit,
|
||||
}
|
||||
return statusStatus, nil
|
||||
}
|
||||
|
||||
func DoStatus(resourceConfigPath clik8s.ResourceConfigPath, writer io.Writer, args util.Args) (status.Result, error) {
|
||||
configFlags, err := wirek8s.NewConfigFlags(args)
|
||||
if err != nil {
|
||||
return status.Result{}, err
|
||||
}
|
||||
config, err := wirek8s.NewRestConfig(configFlags)
|
||||
if err != nil {
|
||||
return status.Result{}, err
|
||||
}
|
||||
dynamicInterface, err := wirek8s.NewDynamicClient(config)
|
||||
if err != nil {
|
||||
return status.Result{}, err
|
||||
}
|
||||
restMapper, err := wirek8s.NewRestMapper(config)
|
||||
if err != nil {
|
||||
return status.Result{}, err
|
||||
}
|
||||
client, err := wirek8s.NewClient(dynamicInterface, restMapper)
|
||||
if err != nil {
|
||||
return status.Result{}, err
|
||||
}
|
||||
pluginConfig := wireconfig.NewPluginConfig()
|
||||
factory := wireconfig.NewResMapFactory(pluginConfig)
|
||||
fileSystem := wireconfig.NewFileSystem()
|
||||
|
|
@ -61,26 +89,14 @@ func DoStatus(resourceConfigPath clik8s.ResourceConfigPath, writer io.Writer, ar
|
|||
if err != nil {
|
||||
return status.Result{}, err
|
||||
}
|
||||
configFlags, err := wirek8s.NewConfigFlags(args)
|
||||
if err != nil {
|
||||
return status.Result{}, err
|
||||
}
|
||||
config, err := wirek8s.NewRestConfig(configFlags)
|
||||
if err != nil {
|
||||
return status.Result{}, err
|
||||
}
|
||||
clientset, err := wirek8s.NewKubernetesClientSet(config)
|
||||
if err != nil {
|
||||
return status.Result{}, err
|
||||
}
|
||||
repository := wiregit.NewOptionalRepository(resourceConfigPath)
|
||||
commitIter := wiregit.NewOptionalCommitIter(repository)
|
||||
commit := wiregit.NewOptionalCommit(commitIter)
|
||||
statusStatus := &status.Status{
|
||||
Resources: resourceConfigs,
|
||||
Out: writer,
|
||||
Clientset: clientset,
|
||||
Commit: commit,
|
||||
DynamicClient: client,
|
||||
Out: writer,
|
||||
Resources: resourceConfigs,
|
||||
Commit: commit,
|
||||
}
|
||||
result, err := NewStatusCommandResult(statusStatus, writer)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -33,16 +33,26 @@ func InitializeStatus(resourceConfigs clik8s.ResourceConfigs, commit *object.Com
|
|||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
clientset, err := wirek8s.NewKubernetesClientSet(config)
|
||||
dynamicInterface, err := wirek8s.NewDynamicClient(config)
|
||||
if err != nil {
|
||||
cleanup()
|
||||
return nil, nil, err
|
||||
}
|
||||
restMapper, err := wirek8s.NewRestMapper(config)
|
||||
if err != nil {
|
||||
cleanup()
|
||||
return nil, nil, err
|
||||
}
|
||||
client, err := wirek8s.NewClient(dynamicInterface, restMapper)
|
||||
if err != nil {
|
||||
cleanup()
|
||||
return nil, nil, err
|
||||
}
|
||||
statusStatus := &status.Status{
|
||||
Resources: resourceConfigs,
|
||||
Out: writer,
|
||||
Clientset: clientset,
|
||||
Commit: commit,
|
||||
DynamicClient: client,
|
||||
Out: writer,
|
||||
Resources: resourceConfigs,
|
||||
Commit: commit,
|
||||
}
|
||||
return statusStatus, func() {
|
||||
cleanup()
|
||||
|
|
|
|||
15
pkg/cmd.go
15
pkg/cmd.go
|
|
@ -19,15 +19,17 @@ import (
|
|||
"sigs.k8s.io/cli-experimental/internal/pkg/delete"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/prune"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/resourceconfig"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/status"
|
||||
)
|
||||
|
||||
// Cmd is a wrapper for different structs:
|
||||
// apply, prune and delete
|
||||
// These structs share the same client
|
||||
type Cmd struct {
|
||||
Applier *apply.Apply
|
||||
Pruner *prune.Prune
|
||||
Deleter *delete.Delete
|
||||
Applier *apply.Apply
|
||||
Pruner *prune.Prune
|
||||
Deleter *delete.Delete
|
||||
StatusGetter *status.Status
|
||||
}
|
||||
|
||||
// Apply applies resources given the input as a slice of unstructured resources
|
||||
|
|
@ -54,3 +56,10 @@ func (a *Cmd) Delete(resources []*unstructured.Unstructured) error {
|
|||
_, err := a.Deleter.Do()
|
||||
return err
|
||||
}
|
||||
|
||||
// Status returns the status given the input as a slice of unstructured resources
|
||||
func (a *Cmd) Status(resources []*unstructured.Unstructured) error {
|
||||
a.StatusGetter.Resources = resources
|
||||
_, err := a.StatusGetter.Do()
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,8 +61,7 @@ func setupResourcesV1() []*unstructured.Unstructured {
|
|||
r2.SetName("inventory")
|
||||
r2.SetNamespace("default")
|
||||
r2.SetAnnotations(map[string]string{
|
||||
inventory.InventoryAnnotation:
|
||||
"{\"current\":{\"~G_v1_ConfigMap|default|cm1\":null}}",
|
||||
inventory.InventoryAnnotation: "{\"current\":{\"~G_v1_ConfigMap|default|cm1\":null}}",
|
||||
inventory.InventoryHashAnnotation: "1234567",
|
||||
})
|
||||
return []*unstructured.Unstructured{r1, r2}
|
||||
|
|
@ -88,8 +87,7 @@ func setupResourcesV2() []*unstructured.Unstructured {
|
|||
r2.SetName("inventory")
|
||||
r2.SetNamespace("default")
|
||||
r2.SetAnnotations(map[string]string{
|
||||
inventory.InventoryAnnotation:
|
||||
"{\"current\":{\"~G_v1_ConfigMap|default|cm2\":null}}",
|
||||
inventory.InventoryAnnotation: "{\"current\":{\"~G_v1_ConfigMap|default|cm2\":null}}",
|
||||
inventory.InventoryHashAnnotation: "7654321",
|
||||
})
|
||||
return []*unstructured.Unstructured{r1, r2}
|
||||
|
|
@ -157,6 +155,12 @@ func TestCmd(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(cmList.Items), 2)
|
||||
|
||||
err = cmd.Status(resources)
|
||||
assert.NoError(t, err)
|
||||
err = c.List(context.Background(), cmList, "default", nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(cmList.Items), 2)
|
||||
|
||||
err = cmd.Delete(resources)
|
||||
assert.NoError(t, err)
|
||||
err = c.List(context.Background(), cmList, "default", nil)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"sigs.k8s.io/cli-experimental/internal/pkg/apply"
|
||||
delete2 "sigs.k8s.io/cli-experimental/internal/pkg/delete"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/prune"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/status"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/util"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/wirecli/wirek8s"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/wirecli/wiretest"
|
||||
|
|
@ -50,10 +51,15 @@ func InitializeCmd(writer io.Writer, args util.Args) (*Cmd, error) {
|
|||
DynamicClient: client,
|
||||
Out: writer,
|
||||
}
|
||||
statusStatus := &status.Status{
|
||||
DynamicClient: client,
|
||||
Out: writer,
|
||||
}
|
||||
cmd := &Cmd{
|
||||
Applier: applyApply,
|
||||
Pruner: prunePrune,
|
||||
Deleter: deleteDelete,
|
||||
Applier: applyApply,
|
||||
Pruner: prunePrune,
|
||||
Deleter: deleteDelete,
|
||||
StatusGetter: statusStatus,
|
||||
}
|
||||
return cmd, nil
|
||||
}
|
||||
|
|
@ -90,10 +96,15 @@ func InitializeFakeCmd(writer io.Writer, args util.Args) (*Cmd, func(), error) {
|
|||
DynamicClient: client,
|
||||
Out: writer,
|
||||
}
|
||||
statusStatus := &status.Status{
|
||||
DynamicClient: client,
|
||||
Out: writer,
|
||||
}
|
||||
cmd := &Cmd{
|
||||
Applier: applyApply,
|
||||
Pruner: prunePrune,
|
||||
Deleter: deleteDelete,
|
||||
Applier: applyApply,
|
||||
Pruner: prunePrune,
|
||||
Deleter: deleteDelete,
|
||||
StatusGetter: statusStatus,
|
||||
}
|
||||
return cmd, func() {
|
||||
cleanup()
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"sigs.k8s.io/cli-experimental/internal/pkg/apply"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/delete"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/prune"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/status"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/wirecli/wirek8s"
|
||||
"sigs.k8s.io/cli-experimental/internal/pkg/wirecli/wiretest"
|
||||
)
|
||||
|
|
@ -27,6 +28,7 @@ var ProviderSet = wire.NewSet(
|
|||
wire.Struct(new(apply.Apply), "DynamicClient", "Out"),
|
||||
wire.Struct(new(prune.Prune), "DynamicClient", "Out"),
|
||||
wire.Struct(new(delete.Delete), "DynamicClient", "Out"),
|
||||
wire.Struct(new(status.Status), "DynamicClient", "Out"),
|
||||
wire.Struct(new(Cmd), "*"),
|
||||
wirek8s.ProviderSet,
|
||||
)
|
||||
|
|
@ -36,6 +38,7 @@ var ProviderSetForTesting = wire.NewSet(
|
|||
wiretest.NewRestConfig, wirek8s.NewClient, wirek8s.NewRestMapper,
|
||||
wire.Struct(new(apply.Apply), "DynamicClient", "Out"),
|
||||
wire.Struct(new(prune.Prune), "DynamicClient", "Out"),
|
||||
wire.Struct(new(status.Status), "DynamicClient", "Out"),
|
||||
wire.Struct(new(delete.Delete), "DynamicClient", "Out"),
|
||||
wire.Struct(new(Cmd), "*"),
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue