Skip to content

Commit 4213489

Browse files
committedFeb 23, 2018
NetworkCheck diagnostic: use admin kubeconfig
Formerly, in order to run diagnostics inside a pod, NetworkCheck looked up the user's kubeconfig file and wrote it to a secret for the pod to use as its kubeconfig. However, this only worked if the current context is the cluster-admin. Cluster diagnostics can work even if the cluster-admin context is not currently selected. For NetworkCheck to work the same it is now a cluster diagnostic, and it writes a new pod kubeconfig with only the cluster-admin context.
1 parent 30475fb commit 4213489

File tree

3 files changed

+88
-68
lines changed

3 files changed

+88
-68
lines changed
 

‎pkg/oc/admin/diagnostics/cluster.go

+64-50
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf
5757

5858
var kclusterClient kclientset.Interface
5959

60-
config, kclusterClient, serverUrl, err := o.findClusterClients(rawConfig)
60+
config, kclusterClient, rawAdminConfig, err := o.findClusterClients(rawConfig)
61+
if err != nil {
62+
return nil, err
63+
}
6164
if config == nil {
6265
o.Logger().Notice("CED1002", "Could not configure a client with cluster-admin permissions for the current server, so cluster diagnostics will be skipped")
6366
return nil, nil
6467
}
65-
if err != nil {
66-
return nil, err
67-
}
6868
imageClient, err := imageclient.NewForConfig(config)
6969
if err != nil {
7070
return nil, err
@@ -118,6 +118,7 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf
118118
case clustdiags.NodeDefinitionsName:
119119
d = &clustdiags.NodeDefinitions{KubeClient: kclusterClient}
120120
case clustdiags.MasterNodeName:
121+
serverUrl := rawAdminConfig.Clusters[rawAdminConfig.Contexts[rawAdminConfig.CurrentContext].Cluster].Server
121122
d = &clustdiags.MasterNode{KubeClient: kclusterClient, ServerUrl: serverUrl, MasterConfigFile: o.MasterConfigLocation}
122123
case clustdiags.ClusterRegistryName:
123124
d = &clustdiags.ClusterRegistry{KubeClient: kclusterClient, ImageStreamClient: imageClient.Image(), PreventModification: o.PreventModification}
@@ -141,8 +142,9 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf
141142
nd.ClientFlags = o.ClientFlags
142143
nd.Level = o.LogOptions.Level
143144
nd.Factory = o.Factory
145+
nd.RawConfig = rawAdminConfig
144146
nd.PreventModification = o.PreventModification
145-
diagnostics = append(diagnostics, nd)
147+
d = nd
146148
default:
147149
return nil, fmt.Errorf("unknown diagnostic: %v", diagnosticName)
148150
}
@@ -152,84 +154,96 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf
152154
}
153155

154156
// attempts to find which context in the config might be a cluster-admin for the server in the current context.
155-
// returns config for the context chosen, kclusterClient for same, serverUrl of same, and any fatal error
156-
func (o DiagnosticsOptions) findClusterClients(rawConfig *clientcmdapi.Config) (*rest.Config, kclientset.Interface, string, error) {
157+
// returns openshift client config for the context chosen, kclusterClient and raw config of same, and any fatal error
158+
func (o DiagnosticsOptions) findClusterClients(rawConfig *clientcmdapi.Config) (*rest.Config, kclientset.Interface, *clientcmdapi.Config, error) {
157159
if o.ClientClusterContext != "" { // user has specified cluster context to use
158160
context, exists := rawConfig.Contexts[o.ClientClusterContext]
159161
if !exists {
160162
configErr := fmt.Errorf("Specified '%s' as cluster-admin context, but it was not found in your client configuration.", o.ClientClusterContext)
161163
o.Logger().Error("CED1003", configErr.Error())
162-
return nil, nil, "", configErr
164+
return nil, nil, nil, configErr
163165
}
164-
config, kube, serverUrl, err := o.makeClusterClients(rawConfig, o.ClientClusterContext, context)
165-
if err != nil || config == nil {
166-
return nil, nil, "", err
167-
}
168-
return config, kube, serverUrl, nil
166+
return o.makeClusterClients(rawConfig, o.ClientClusterContext, context)
169167
}
170168
currentContext, exists := rawConfig.Contexts[rawConfig.CurrentContext]
171169
if !exists { // config specified cluster admin context that doesn't exist; complain and quit
172170
configErr := fmt.Errorf("Current context '%s' not found in client configuration; will not attempt cluster diagnostics.", rawConfig.CurrentContext)
173171
o.Logger().Error("CED1004", configErr.Error())
174-
return nil, nil, "", configErr
172+
return nil, nil, nil, configErr
175173
}
174+
176175
// check if current context is already cluster admin
177-
config, kube, serverUrl, err := o.makeClusterClients(rawConfig, rawConfig.CurrentContext, currentContext)
176+
config, kube, rawAdminConfig, err := o.makeClusterClients(rawConfig, rawConfig.CurrentContext, currentContext)
178177
if err == nil && config != nil {
179-
return config, kube, serverUrl, nil
178+
return config, kube, rawAdminConfig, nil
180179
}
180+
181181
// otherwise, for convenience, search for a context with the same server but with the system:admin user
182182
for name, context := range rawConfig.Contexts {
183183
if context.Cluster == currentContext.Cluster && name != rawConfig.CurrentContext && strings.HasPrefix(context.AuthInfo, "system:admin/") {
184-
config, kube, serverUrl, err := o.makeClusterClients(rawConfig, name, context)
184+
config, kube, rawAdminConfig, err := o.makeClusterClients(rawConfig, name, context)
185185
if err != nil || config == nil {
186186
break // don't try more than one such context, they'll probably fail the same
187187
}
188-
return config, kube, serverUrl, nil
188+
return config, kube, rawAdminConfig, nil
189189
}
190190
}
191-
return nil, nil, "", nil
191+
return nil, nil, nil, nil
192192
}
193193

194194
// makes the client from the specified context and determines whether it is a cluster-admin.
195-
func (o DiagnosticsOptions) makeClusterClients(rawConfig *clientcmdapi.Config, contextName string, context *clientcmdapi.Context) (*rest.Config, kclientset.Interface, string, error) {
195+
func (o DiagnosticsOptions) makeClusterClients(rawConfig *clientcmdapi.Config, contextName string, context *clientcmdapi.Context) (*rest.Config, kclientset.Interface, *clientcmdapi.Config, error) {
196196
overrides := &clientcmd.ConfigOverrides{Context: *context}
197197
clientConfig := clientcmd.NewDefaultClientConfig(*rawConfig, overrides)
198-
serverUrl := rawConfig.Clusters[context.Cluster].Server
199198
factory := osclientcmd.NewFactory(clientConfig)
199+
200+
// create a config for making openshift clients
200201
config, err := factory.ClientConfig()
201202
if err != nil {
202-
o.Logger().Debug("CED1006", fmt.Sprintf("Error creating client for context '%s':\n%v", contextName, err))
203-
return nil, nil, "", nil
203+
o.Logger().Debug("CED1006", fmt.Sprintf("Error creating client config for context '%s':\n%v", contextName, err))
204+
return nil, nil, nil, nil
205+
}
206+
207+
// create a kube client
208+
kubeClient, err := factory.ClientSet()
209+
if err != nil {
210+
o.Logger().Debug("CED1006", fmt.Sprintf("Error creating kube client for context '%s':\n%v", contextName, err))
211+
return nil, nil, nil, nil
204212
}
213+
205214
o.Logger().Debug("CED1005", fmt.Sprintf("Checking if context is cluster-admin: '%s'", contextName))
206-
if kubeClient, err := factory.ClientSet(); err != nil {
207-
o.Logger().Debug("CED1006", fmt.Sprintf("Error creating client for context '%s':\n%v", contextName, err))
208-
return nil, nil, "", nil
209-
} else {
210-
subjectAccessReview := &authorization.SelfSubjectAccessReview{
211-
Spec: authorization.SelfSubjectAccessReviewSpec{
212-
ResourceAttributes: &authorization.ResourceAttributes{
213-
// if you can do everything, you're the cluster admin.
214-
Verb: "*",
215-
Group: "*",
216-
Resource: "*",
217-
},
215+
subjectAccessReview := &authorization.SelfSubjectAccessReview{
216+
Spec: authorization.SelfSubjectAccessReviewSpec{
217+
ResourceAttributes: &authorization.ResourceAttributes{
218+
// if you can do everything, you're the cluster admin.
219+
Verb: "*",
220+
Group: "*",
221+
Resource: "*",
218222
},
219-
}
220-
if resp, err := kubeClient.Authorization().SelfSubjectAccessReviews().Create(subjectAccessReview); err != nil {
221-
if regexp.MustCompile(`User "[\w:]+" cannot create \w+ at the cluster scope`).MatchString(err.Error()) {
222-
o.Logger().Debug("CED1007", fmt.Sprintf("Context '%s' does not have cluster-admin access:\n%v", contextName, err))
223-
return nil, nil, "", nil
224-
} else {
225-
o.Logger().Error("CED1008", fmt.Sprintf("Unknown error testing cluster-admin access for context '%s':\n%v", contextName, err))
226-
return nil, nil, "", err
227-
}
228-
} else if resp.Status.Allowed {
229-
o.Logger().Info("CED1009", fmt.Sprintf("Using context for cluster-admin access: '%s'", contextName))
230-
return config, kubeClient, serverUrl, nil
231-
}
223+
},
224+
}
225+
resp, err := kubeClient.Authorization().SelfSubjectAccessReviews().Create(subjectAccessReview)
226+
if err != nil && regexp.MustCompile(`User "[\w:]+" cannot create \w+ at the cluster scope`).MatchString(err.Error()) {
227+
o.Logger().Debug("CED1007", fmt.Sprintf("Context '%s' does not have cluster-admin access:\n%v", contextName, err))
228+
return nil, nil, nil, nil
229+
}
230+
if err != nil {
231+
o.Logger().Error("CED1008", fmt.Sprintf("Unknown error testing cluster-admin access for context '%s':\n%v", contextName, err))
232+
return nil, nil, nil, err
233+
}
234+
if !resp.Status.Allowed {
235+
o.Logger().Debug("CED1010", fmt.Sprintf("Context does not have cluster-admin access: '%s'", contextName))
236+
return nil, nil, nil, nil
237+
}
238+
239+
o.Logger().Info("CED1009", fmt.Sprintf("Using context for cluster-admin access: '%s'", contextName))
240+
adminConfig := rawConfig.DeepCopy()
241+
adminConfig.CurrentContext = contextName
242+
if err := clientcmdapi.MinifyConfig(adminConfig); err != nil {
243+
return nil, nil, nil, err
244+
}
245+
if err := clientcmdapi.FlattenConfig(adminConfig); err != nil {
246+
return nil, nil, nil, err
232247
}
233-
o.Logger().Debug("CED1010", fmt.Sprintf("Context does not have cluster-admin access: '%s'", contextName))
234-
return nil, nil, "", nil
248+
return config, kubeClient, adminConfig, nil
235249
}

‎pkg/oc/admin/diagnostics/diagnostics/cluster/network/run_pod.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
kvalidation "k8s.io/apimachinery/pkg/util/validation"
1717
"k8s.io/apimachinery/pkg/util/wait"
1818
"k8s.io/apiserver/pkg/storage/names"
19+
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
1920
kapi "k8s.io/kubernetes/pkg/apis/core"
2021
kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
2122

@@ -44,6 +45,7 @@ type NetworkDiagnostic struct {
4445
ClientFlags *flag.FlagSet
4546
Level int
4647
Factory *osclientcmd.Factory
48+
RawConfig *clientcmdapi.Config
4749
PreventModification bool
4850
LogDir string
4951
PodImage string
@@ -112,8 +114,6 @@ func (d *NetworkDiagnostic) CanRun() (bool, error) {
112114
return false, errors.New("must have kube client")
113115
} else if d.NetNamespacesClient == nil || d.ClusterNetworkClient == nil {
114116
return false, errors.New("must have openshift client")
115-
} else if _, err := d.getKubeConfig(); err != nil {
116-
return false, err
117117
}
118118
return true, nil
119119
}

‎pkg/oc/admin/diagnostics/diagnostics/cluster/network/setup.go

+22-16
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,28 @@ package network
22

33
// Set up test environment needed for network diagnostics
44
import (
5+
"bytes"
56
"fmt"
6-
"io/ioutil"
77
"strings"
88
"time"
99

1010
kerrs "k8s.io/apimachinery/pkg/api/errors"
11+
"k8s.io/apimachinery/pkg/api/meta"
1112
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/runtime"
1214
kerrors "k8s.io/apimachinery/pkg/util/errors"
1315
"k8s.io/apimachinery/pkg/util/sets"
1416
"k8s.io/apimachinery/pkg/util/wait"
1517
"k8s.io/apiserver/pkg/storage/names"
1618
kclientcmd "k8s.io/client-go/tools/clientcmd"
19+
"k8s.io/client-go/tools/clientcmd/api/latest"
1720
kapi "k8s.io/kubernetes/pkg/apis/core"
21+
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
22+
"k8s.io/kubernetes/pkg/printers"
1823

19-
"github.com/openshift/origin/pkg/client/config"
2024
"github.com/openshift/origin/pkg/network"
2125
networkapi "github.com/openshift/origin/pkg/network/apis/network"
2226
"github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util"
23-
diagutil "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/util"
2427
)
2528

2629
func (d *NetworkDiagnostic) TestSetup() error {
@@ -273,20 +276,23 @@ func (d *NetworkDiagnostic) makeNamespaceGlobal(nsName string) error {
273276
})
274277
}
275278

279+
// turn a raw config object into its string representation (kubeconfig)
276280
func (d *NetworkDiagnostic) getKubeConfig() ([]byte, error) {
277-
// KubeConfig path search order:
278-
// 1. User given config path
279-
// 2. Default admin config paths
280-
// 3. Default openshift client config search paths
281-
paths := []string{}
282-
paths = append(paths, d.ClientFlags.Lookup(config.OpenShiftConfigFlagName).Value.String())
283-
paths = append(paths, diagutil.AdminKubeConfigPaths...)
284-
paths = append(paths, config.NewOpenShiftClientConfigLoadingRules().Precedence...)
281+
var b bytes.Buffer
285282

286-
for _, path := range paths {
287-
if configData, err := ioutil.ReadFile(path); err == nil {
288-
return configData, nil
289-
}
283+
// there does not seem to be a simple DefaultPrinter to invoke; create one
284+
options := &printers.PrintOptions{
285+
OutputFormatType: "yaml",
286+
AllowMissingKeys: true,
287+
}
288+
printer, err := cmdutil.PrinterForOptions(meta.NewDefaultRESTMapper(nil, nil), latest.Scheme, nil, []runtime.Decoder{latest.Codec}, options)
289+
if err != nil {
290+
return nil, fmt.Errorf("from PrinterForOptions: %#v", err)
291+
}
292+
printer = printers.NewVersionedPrinter(printer, latest.Scheme, latest.ExternalVersion)
293+
294+
if err := printer.PrintObj(d.RawConfig, &b); err != nil {
295+
return nil, fmt.Errorf("from PrintObj: %#v", err)
290296
}
291-
return nil, fmt.Errorf("Unable to find kube config")
297+
return b.Bytes(), nil
292298
}

0 commit comments

Comments
 (0)
Please sign in to comment.