@@ -6,11 +6,13 @@ package status
66import (
77 "context"
88 "fmt"
9+ "strings"
910 "time"
1011
1112 "github.com/spf13/cobra"
1213 "k8s.io/cli-runtime/pkg/genericclioptions"
1314 cmdutil "k8s.io/kubectl/pkg/cmd/util"
15+ "k8s.io/kubectl/pkg/util/slice"
1416 "sigs.k8s.io/cli-utils/cmd/flagutils"
1517 "sigs.k8s.io/cli-utils/cmd/status/printers"
1618 "sigs.k8s.io/cli-utils/cmd/status/printers/printer"
@@ -24,18 +26,39 @@ import (
2426 "sigs.k8s.io/cli-utils/pkg/kstatus/status"
2527 "sigs.k8s.io/cli-utils/pkg/manifestreader"
2628 "sigs.k8s.io/cli-utils/pkg/object"
29+ printcommon "sigs.k8s.io/cli-utils/pkg/print/common"
30+ pkgprinters "sigs.k8s.io/cli-utils/pkg/printers"
2731)
2832
29- func GetRunner (factory cmdutil.Factory , invFactory inventory.ClientFactory , loader manifestreader.ManifestLoader ) * Runner {
33+ const (
34+ Known = "known"
35+ Current = "current"
36+ Deleted = "deleted"
37+ Forever = "forever"
38+ )
39+
40+ const (
41+ Local = "local"
42+ Remote = "remote"
43+ )
44+
45+ var (
46+ PollUntilOptions = []string {Known , Current , Deleted , Forever }
47+ )
48+
49+ func GetRunner (ctx context.Context , factory cmdutil.Factory ,
50+ invFactory inventory.ClientFactory , loader Loader ) * Runner {
3051 r := & Runner {
52+ ctx : ctx ,
3153 factory : factory ,
3254 invFactory : invFactory ,
33- loader : NewInventoryLoader ( loader ) ,
34- pollerFactoryFunc : pollerFactoryFunc ,
55+ loader : loader ,
56+ PollerFactoryFunc : pollerFactoryFunc ,
3557 }
3658 c := & cobra.Command {
37- Use : "status (DIRECTORY | STDIN)" ,
38- RunE : r .runE ,
59+ Use : "status (DIRECTORY | STDIN)" ,
60+ PreRunE : r .preRunE ,
61+ RunE : r .runE ,
3962 }
4063 c .Flags ().DurationVar (& r .period , "poll-period" , 2 * time .Second ,
4164 "Polling period for resource statuses." )
@@ -44,18 +67,24 @@ func GetRunner(factory cmdutil.Factory, invFactory inventory.ClientFactory, load
4467 c .Flags ().StringVar (& r .output , "output" , "events" , "Output format." )
4568 c .Flags ().DurationVar (& r .timeout , "timeout" , 0 ,
4669 "How long to wait before exiting" )
70+ c .Flags ().StringVar (& r .invType , "inv-type" , Local , "Type of the inventory info, must be local or remote" )
71+ c .Flags ().StringVar (& r .inventoryNames , "inv-names" , "" , "Names of targeted inventory: inv1,inv2,..." )
72+ c .Flags ().StringVar (& r .namespaces , "namespaces" , "" , "Names of targeted namespaces: ns1,ns2,..." )
73+ c .Flags ().StringVar (& r .statuses , "statuses" , "" , "Targeted status: st1,st2..." )
4774
4875 r .Command = c
4976 return r
5077}
5178
52- func Command (f cmdutil.Factory , invFactory inventory.ClientFactory , loader manifestreader.ManifestLoader ) * cobra.Command {
53- return GetRunner (f , invFactory , loader ).Command
79+ func Command (ctx context.Context , f cmdutil.Factory ,
80+ invFactory inventory.ClientFactory , loader Loader ) * cobra.Command {
81+ return GetRunner (ctx , f , invFactory , loader ).Command
5482}
5583
5684// Runner captures the parameters for the command and contains
5785// the run function.
5886type Runner struct {
87+ ctx context.Context
5988 Command * cobra.Command
6089 factory cmdutil.Factory
6190 invFactory inventory.ClientFactory
@@ -66,49 +95,165 @@ type Runner struct {
6695 timeout time.Duration
6796 output string
6897
69- pollerFactoryFunc func (cmdutil.Factory ) (poller.Poller , error )
98+ invType string
99+ inventoryNames string
100+ inventoryNameSet map [string ]bool
101+ namespaces string
102+ namespaceSet map [string ]bool
103+ statuses string
104+ statusSet map [string ]bool
105+
106+ PollerFactoryFunc func (cmdutil.Factory ) (poller.Poller , error )
70107}
71108
72- // runE implements the logic of the command and will delegate to the
73- // poller to compute status for each of the resources. One of the printer
74- // implementations takes care of printing the output.
75- func (r * Runner ) runE (cmd * cobra.Command , args []string ) error {
109+ func (r * Runner ) preRunE (* cobra.Command , []string ) error {
110+ if ! slice .ContainsString (PollUntilOptions , r .pollUntil , nil ) {
111+ return fmt .Errorf ("pollUntil must be one of %s" , strings .Join (PollUntilOptions , "," ))
112+ }
113+
114+ if found := pkgprinters .ValidatePrinterType (r .output ); ! found {
115+ return fmt .Errorf ("unknown output type %q" , r .output )
116+ }
117+
118+ if r .invType != Local && r .invType != Remote {
119+ return fmt .Errorf ("inv-type flag should be either local or remote" )
120+ }
121+
122+ if r .invType == Local && r .inventoryNames != "" {
123+ return fmt .Errorf ("inv-names flag should only be used when inv-type is set to remote" )
124+ }
125+
126+ if r .inventoryNames != "" {
127+ r .inventoryNameSet = make (map [string ]bool )
128+ for _ , name := range strings .Split (r .inventoryNames , "," ) {
129+ r .inventoryNameSet [name ] = true
130+ }
131+ }
132+
133+ if r .namespaces != "" {
134+ r .namespaceSet = make (map [string ]bool )
135+ for _ , ns := range strings .Split (r .namespaces , "," ) {
136+ r .namespaceSet [ns ] = true
137+ }
138+ }
139+
140+ if r .statuses != "" {
141+ r .statusSet = make (map [string ]bool )
142+ for _ , st := range strings .Split (r .statuses , "," ) {
143+ parsedST := strings .ToLower (st )
144+ r .statusSet [parsedST ] = true
145+ }
146+ }
147+
148+ return nil
149+ }
150+
151+ // Load inventory info from local storage
152+ // and get info from the cluster based on the local info
153+ // wrap it to be a map mapping from string to objectMetadataSet
154+ func (r * Runner ) loadInvFromDisk (cmd * cobra.Command , args []string ) (* printer.PrintData , error ) {
76155 inv , err := r .loader .GetInvInfo (cmd , args )
77156 if err != nil {
78- return err
157+ return nil , err
79158 }
80159
81160 invClient , err := r .invFactory .NewClient (r .factory )
82161 if err != nil {
83- return err
162+ return nil , err
84163 }
85164
86165 // Based on the inventory template manifest we look up the inventory
87166 // from the live state using the inventory client.
88167 identifiers , err := invClient .GetClusterObjs (inv )
89168 if err != nil {
90- return err
169+ return nil , err
91170 }
92171
93- // Exit here if the inventory is empty.
94- if len (identifiers ) == 0 {
95- _ , _ = fmt .Fprint (cmd .OutOrStdout (), "no resources found in the inventory\n " )
96- return nil
172+ printData := printer.PrintData {
173+ Identifiers : object.ObjMetadataSet {},
174+ InvNameMap : make (map [object.ObjMetadata ]string ),
175+ StatusSet : r .statusSet ,
176+ }
177+
178+ for _ , obj := range identifiers {
179+ // check if the object is under one of the targeted namespaces
180+ if _ , ok := r .namespaceSet [obj .Namespace ]; ok || len (r .namespaceSet ) == 0 {
181+ // add to the map for future reference
182+ printData .InvNameMap [obj ] = inv .Name ()
183+ // append to identifiers
184+ printData .Identifiers = append (printData .Identifiers , obj )
185+ }
186+ }
187+ return & printData , nil
188+ }
189+
190+ // Retrieve a list of inventory object from the cluster
191+ func (r * Runner ) listInvFromCluster () (* printer.PrintData , error ) {
192+ invClient , err := r .invFactory .NewClient (r .factory )
193+ if err != nil {
194+ return nil , err
97195 }
98196
99197 // initialize maps in printData
100198 printData := printer.PrintData {
101- InvNameMap : make (map [object.ObjMetadata ]string ),
102- StatusSet : make (map [string ]bool ),
199+ Identifiers : object.ObjMetadataSet {},
200+ InvNameMap : make (map [object.ObjMetadata ]string ),
201+ StatusSet : r .statusSet ,
103202 }
104- for _ , obj := range identifiers {
105- // add to the map for future reference
106- printData .InvNameMap [obj ] = inv .Name ()
107- // append to identifiers
108- printData .Identifiers = append (printData .Identifiers , obj )
203+
204+ identifiersMap , err := invClient .ListClusterInventoryObjs (r .ctx )
205+ if err != nil {
206+ return nil , err
207+ }
208+
209+ for invName , identifiers := range identifiersMap {
210+ // Check if there are targeted inventory names and include the current inventory name
211+ if _ , ok := r .inventoryNameSet [invName ]; ! ok && len (r .inventoryNameSet ) != 0 {
212+ continue
213+ }
214+ // Filter objects
215+ for _ , obj := range identifiers {
216+ // check if the object is under one of the targeted namespaces
217+ if _ , ok := r .namespaceSet [obj .Namespace ]; ok || len (r .namespaceSet ) == 0 {
218+ // add to the map for future reference
219+ printData .InvNameMap [obj ] = invName
220+ // append to identifiers
221+ printData .Identifiers = append (printData .Identifiers , obj )
222+ }
223+ }
224+ }
225+ return & printData , nil
226+ }
227+
228+ // runE implements the logic of the command and will delegate to the
229+ // poller to compute status for each of the resources. One of the printer
230+ // implementations takes care of printing the output.
231+ func (r * Runner ) runE (cmd * cobra.Command , args []string ) error {
232+ var printData * printer.PrintData
233+ var err error
234+ switch r .invType {
235+ case Local :
236+ if len (args ) != 0 {
237+ printcommon .SprintfWithColor (printcommon .YELLOW ,
238+ "Warning: Path is assigned while list flag is enabled, ignore the path" )
239+ }
240+ printData , err = r .loadInvFromDisk (cmd , args )
241+ case Remote :
242+ printData , err = r .listInvFromCluster ()
243+ default :
244+ return fmt .Errorf ("invType must be either local or remote" )
245+ }
246+ if err != nil {
247+ return err
248+ }
249+
250+ // Exit here if the inventory is empty.
251+ if len (printData .Identifiers ) == 0 {
252+ _ , _ = fmt .Fprint (cmd .OutOrStdout (), "no resources found in the inventory\n " )
253+ return nil
109254 }
110255
111- statusPoller , err := r .pollerFactoryFunc (r .factory )
256+ statusPoller , err := r .PollerFactoryFunc (r .factory )
112257 if err != nil {
113258 return err
114259 }
@@ -119,7 +264,7 @@ func (r *Runner) runE(cmd *cobra.Command, args []string) error {
119264 In : cmd .InOrStdin (),
120265 Out : cmd .OutOrStdout (),
121266 ErrOut : cmd .ErrOrStderr (),
122- }, & printData )
267+ }, printData )
123268 if err != nil {
124269 return fmt .Errorf ("error creating printer: %w" , err )
125270 }
@@ -151,11 +296,11 @@ func (r *Runner) runE(cmd *cobra.Command, args []string) error {
151296 return fmt .Errorf ("unknown value for pollUntil: %q" , r .pollUntil )
152297 }
153298
154- eventChannel := statusPoller .Poll (ctx , identifiers , polling.PollOptions {
299+ eventChannel := statusPoller .Poll (ctx , printData . Identifiers , polling.PollOptions {
155300 PollInterval : r .period ,
156301 })
157302
158- return printer .Print (eventChannel , identifiers , cancelFunc )
303+ return printer .Print (eventChannel , printData . Identifiers , cancelFunc )
159304}
160305
161306// desiredStatusNotifierFunc returns an Observer function for the
0 commit comments