11package kubernetes
22
33import (
4+ "encoding/json"
5+ "fmt"
6+ "io/ioutil"
7+ "net/http"
8+ "net/url"
9+
410 "github.com/docker/cli/cli/command"
511 "github.com/docker/cli/cli/command/formatter"
612 "github.com/docker/cli/cli/command/stack/options"
13+ "github.com/docker/go-connections/tlsconfig"
14+ "github.com/pkg/errors"
15+ "github.com/sirupsen/logrus"
16+ core_v1 "k8s.io/api/core/v1"
17+ apierrs "k8s.io/apimachinery/pkg/api/errors"
718 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
819)
920
@@ -17,7 +28,7 @@ func GetStacks(dockerCli command.Cli, opts options.List, kopts Options) ([]*form
1728 if dockerCli .ClientInfo ().HasAll () {
1829 opts .AllNamespaces = true
1930 }
20- return getStacks ( kubeCli , opts )
31+ return getStacksWithAllNamespaces ( dockerCli , kubeCli , opts )
2132 }
2233 return getStacksWithNamespaces (kubeCli , opts )
2334}
@@ -47,6 +58,74 @@ func getStacks(kubeCli *KubeCli, opts options.List) ([]*formatter.Stack, error)
4758 return formattedStacks , nil
4859}
4960
61+ func getStacksWithAllNamespaces (dockerCli command.Cli , kubeCli * KubeCli , opts options.List ) ([]* formatter.Stack , error ) {
62+ stacks , err := getStacks (kubeCli , opts )
63+ if err == nil || ! apierrs .IsForbidden (err ) {
64+ return stacks , err
65+ }
66+ nms , err2 := getUserVisibleNamespaces (dockerCli )
67+ if err2 != nil {
68+ logrus .Debugf ("Failed to query user visible namespaces: %s" , err2 )
69+ return nil , err
70+ }
71+ opts .AllNamespaces = false
72+ for _ , namespace := range nms .Items {
73+ kubeCli .kubeNamespace = namespace .Name
74+ ss , err := getStacks (kubeCli , opts )
75+ if err != nil {
76+ return nil , err
77+ }
78+ stacks = append (stacks , ss ... )
79+ }
80+ return stacks , nil
81+ }
82+
83+ func getUserVisibleNamespaces (dockerCli command.Cli ) (* core_v1.NamespaceList , error ) {
84+ host := dockerCli .Client ().DaemonHost ()
85+ endpoint , err := url .Parse (host )
86+ if err != nil {
87+ return nil , err
88+ }
89+ endpoint .Scheme = "https"
90+ endpoint .Path = "/kubernetesNamespaces"
91+ res := core_v1.NamespaceList {}
92+ return & res , makeRequest (dockerCli , * endpoint , func (resp http.Response ) error {
93+ body , err := ioutil .ReadAll (resp .Body )
94+ if err != nil {
95+ return errors .Wrapf (err , "received %d status and unable to read response" , resp .StatusCode )
96+ }
97+ if resp .StatusCode != http .StatusOK {
98+ return fmt .Errorf (string (body ))
99+ }
100+ if err := json .Unmarshal (body , & res ); err != nil {
101+ return errors .Wrapf (err , "unmarshal failed: %s" , string (body ))
102+ }
103+ return nil
104+ })
105+ }
106+
107+ func makeRequest (dockerCli command.Cli , endpoint url.URL , handler func (resp http.Response ) error ) error {
108+ tlsOptions := dockerCli .ClientInfo ().TLSOptions
109+ if tlsOptions == nil {
110+ return fmt .Errorf ("missing TLS options for https" )
111+ }
112+ tlsConfig , err := tlsconfig .Client (* tlsOptions )
113+ if err != nil {
114+ return err
115+ }
116+ httpClient := http.Client {
117+ Transport : & http.Transport {
118+ TLSClientConfig : tlsConfig ,
119+ },
120+ }
121+ resp , err := httpClient .Get (endpoint .String ())
122+ if err != nil {
123+ return err
124+ }
125+ defer resp .Body .Close ()
126+ return handler (* resp )
127+ }
128+
50129func getStacksWithNamespaces (kubeCli * KubeCli , opts options.List ) ([]* formatter.Stack , error ) {
51130 stacks := []* formatter.Stack {}
52131 for _ , namespace := range removeDuplicates (opts .Namespaces ) {
0 commit comments