Skip to content

diagnostic reorg and NetworkCheck fix #18709

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 64 additions & 50 deletions pkg/oc/admin/diagnostics/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf

var kclusterClient kclientset.Interface

config, kclusterClient, serverUrl, err := o.findClusterClients(rawConfig)
config, kclusterClient, rawAdminConfig, err := o.findClusterClients(rawConfig)
if err != nil {
return nil, err
}
if config == nil {
o.Logger().Notice("CED1002", "Could not configure a client with cluster-admin permissions for the current server, so cluster diagnostics will be skipped")
return nil, nil
}
if err != nil {
return nil, err
}
imageClient, err := imageclient.NewForConfig(config)
if err != nil {
return nil, err
Expand Down Expand Up @@ -118,6 +118,7 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf
case clustdiags.NodeDefinitionsName:
d = &clustdiags.NodeDefinitions{KubeClient: kclusterClient}
case clustdiags.MasterNodeName:
serverUrl := rawAdminConfig.Clusters[rawAdminConfig.Contexts[rawAdminConfig.CurrentContext].Cluster].Server
d = &clustdiags.MasterNode{KubeClient: kclusterClient, ServerUrl: serverUrl, MasterConfigFile: o.MasterConfigLocation}
case clustdiags.ClusterRegistryName:
d = &clustdiags.ClusterRegistry{KubeClient: kclusterClient, ImageStreamClient: imageClient.Image(), PreventModification: o.PreventModification}
Expand All @@ -141,8 +142,9 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf
nd.ClientFlags = o.ClientFlags
nd.Level = o.LogOptions.Level
nd.Factory = o.Factory
nd.RawConfig = rawAdminConfig
nd.PreventModification = o.PreventModification
diagnostics = append(diagnostics, nd)
d = nd

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, issue in previous commit got fixed here

default:
return nil, fmt.Errorf("unknown diagnostic: %v", diagnosticName)
}
Expand All @@ -152,84 +154,96 @@ func (o DiagnosticsOptions) buildClusterDiagnostics(rawConfig *clientcmdapi.Conf
}

// attempts to find which context in the config might be a cluster-admin for the server in the current context.
// returns config for the context chosen, kclusterClient for same, serverUrl of same, and any fatal error
func (o DiagnosticsOptions) findClusterClients(rawConfig *clientcmdapi.Config) (*rest.Config, kclientset.Interface, string, error) {
// returns openshift client config for the context chosen, kclusterClient and raw config of same, and any fatal error
func (o DiagnosticsOptions) findClusterClients(rawConfig *clientcmdapi.Config) (*rest.Config, kclientset.Interface, *clientcmdapi.Config, error) {
if o.ClientClusterContext != "" { // user has specified cluster context to use
context, exists := rawConfig.Contexts[o.ClientClusterContext]
if !exists {
configErr := fmt.Errorf("Specified '%s' as cluster-admin context, but it was not found in your client configuration.", o.ClientClusterContext)
o.Logger().Error("CED1003", configErr.Error())
return nil, nil, "", configErr
return nil, nil, nil, configErr
}
config, kube, serverUrl, err := o.makeClusterClients(rawConfig, o.ClientClusterContext, context)
if err != nil || config == nil {
return nil, nil, "", err
}
return config, kube, serverUrl, nil
return o.makeClusterClients(rawConfig, o.ClientClusterContext, context)
}
currentContext, exists := rawConfig.Contexts[rawConfig.CurrentContext]
if !exists { // config specified cluster admin context that doesn't exist; complain and quit
configErr := fmt.Errorf("Current context '%s' not found in client configuration; will not attempt cluster diagnostics.", rawConfig.CurrentContext)
o.Logger().Error("CED1004", configErr.Error())
return nil, nil, "", configErr
return nil, nil, nil, configErr
}

// check if current context is already cluster admin
config, kube, serverUrl, err := o.makeClusterClients(rawConfig, rawConfig.CurrentContext, currentContext)
config, kube, rawAdminConfig, err := o.makeClusterClients(rawConfig, rawConfig.CurrentContext, currentContext)
if err == nil && config != nil {
return config, kube, serverUrl, nil
return config, kube, rawAdminConfig, nil
}

// otherwise, for convenience, search for a context with the same server but with the system:admin user
for name, context := range rawConfig.Contexts {
if context.Cluster == currentContext.Cluster && name != rawConfig.CurrentContext && strings.HasPrefix(context.AuthInfo, "system:admin/") {
config, kube, serverUrl, err := o.makeClusterClients(rawConfig, name, context)
config, kube, rawAdminConfig, err := o.makeClusterClients(rawConfig, name, context)
if err != nil || config == nil {
break // don't try more than one such context, they'll probably fail the same
}
return config, kube, serverUrl, nil
return config, kube, rawAdminConfig, nil
}
}
return nil, nil, "", nil
return nil, nil, nil, nil
}

// makes the client from the specified context and determines whether it is a cluster-admin.
func (o DiagnosticsOptions) makeClusterClients(rawConfig *clientcmdapi.Config, contextName string, context *clientcmdapi.Context) (*rest.Config, kclientset.Interface, string, error) {
func (o DiagnosticsOptions) makeClusterClients(rawConfig *clientcmdapi.Config, contextName string, context *clientcmdapi.Context) (*rest.Config, kclientset.Interface, *clientcmdapi.Config, error) {
overrides := &clientcmd.ConfigOverrides{Context: *context}
clientConfig := clientcmd.NewDefaultClientConfig(*rawConfig, overrides)
serverUrl := rawConfig.Clusters[context.Cluster].Server
factory := osclientcmd.NewFactory(clientConfig)

// create a config for making openshift clients
config, err := factory.ClientConfig()
if err != nil {
o.Logger().Debug("CED1006", fmt.Sprintf("Error creating client for context '%s':\n%v", contextName, err))
return nil, nil, "", nil
o.Logger().Debug("CED1006", fmt.Sprintf("Error creating client config for context '%s':\n%v", contextName, err))
return nil, nil, nil, nil
}

// create a kube client
kubeClient, err := factory.ClientSet()
if err != nil {
o.Logger().Debug("CED1006", fmt.Sprintf("Error creating kube client for context '%s':\n%v", contextName, err))
return nil, nil, nil, nil
}

o.Logger().Debug("CED1005", fmt.Sprintf("Checking if context is cluster-admin: '%s'", contextName))
if kubeClient, err := factory.ClientSet(); err != nil {
o.Logger().Debug("CED1006", fmt.Sprintf("Error creating client for context '%s':\n%v", contextName, err))
return nil, nil, "", nil
} else {
subjectAccessReview := &authorization.SelfSubjectAccessReview{
Spec: authorization.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorization.ResourceAttributes{
// if you can do everything, you're the cluster admin.
Verb: "*",
Group: "*",
Resource: "*",
},
subjectAccessReview := &authorization.SelfSubjectAccessReview{
Spec: authorization.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorization.ResourceAttributes{
// if you can do everything, you're the cluster admin.
Verb: "*",
Group: "*",
Resource: "*",
},
}
if resp, err := kubeClient.Authorization().SelfSubjectAccessReviews().Create(subjectAccessReview); err != nil {
if regexp.MustCompile(`User "[\w:]+" cannot create \w+ at the cluster scope`).MatchString(err.Error()) {
o.Logger().Debug("CED1007", fmt.Sprintf("Context '%s' does not have cluster-admin access:\n%v", contextName, err))
return nil, nil, "", nil
} else {
o.Logger().Error("CED1008", fmt.Sprintf("Unknown error testing cluster-admin access for context '%s':\n%v", contextName, err))
return nil, nil, "", err
}
} else if resp.Status.Allowed {
o.Logger().Info("CED1009", fmt.Sprintf("Using context for cluster-admin access: '%s'", contextName))
return config, kubeClient, serverUrl, nil
}
},
}
resp, err := kubeClient.Authorization().SelfSubjectAccessReviews().Create(subjectAccessReview)
if err != nil && regexp.MustCompile(`User "[\w:]+" cannot create \w+ at the cluster scope`).MatchString(err.Error()) {
o.Logger().Debug("CED1007", fmt.Sprintf("Context '%s' does not have cluster-admin access:\n%v", contextName, err))
return nil, nil, nil, nil
}
if err != nil {
o.Logger().Error("CED1008", fmt.Sprintf("Unknown error testing cluster-admin access for context '%s':\n%v", contextName, err))
return nil, nil, nil, err
}
if !resp.Status.Allowed {
o.Logger().Debug("CED1010", fmt.Sprintf("Context does not have cluster-admin access: '%s'", contextName))
return nil, nil, nil, nil
}

o.Logger().Info("CED1009", fmt.Sprintf("Using context for cluster-admin access: '%s'", contextName))
adminConfig := rawConfig.DeepCopy()
adminConfig.CurrentContext = contextName
if err := clientcmdapi.MinifyConfig(adminConfig); err != nil {
return nil, nil, nil, err
}
if err := clientcmdapi.FlattenConfig(adminConfig); err != nil {
return nil, nil, nil, err
}
o.Logger().Debug("CED1010", fmt.Sprintf("Context does not have cluster-admin access: '%s'", contextName))
return nil, nil, "", nil
return config, kubeClient, adminConfig, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
kvalidation "k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/storage/names"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
kapi "k8s.io/kubernetes/pkg/apis/core"
kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"

Expand Down Expand Up @@ -44,6 +45,7 @@ type NetworkDiagnostic struct {
ClientFlags *flag.FlagSet
Level int
Factory *osclientcmd.Factory
RawConfig *clientcmdapi.Config
PreventModification bool
LogDir string
PodImage string
Expand Down Expand Up @@ -112,8 +114,6 @@ func (d *NetworkDiagnostic) CanRun() (bool, error) {
return false, errors.New("must have kube client")
} else if d.NetNamespacesClient == nil || d.ClusterNetworkClient == nil {
return false, errors.New("must have openshift client")
} else if _, err := d.getKubeConfig(); err != nil {
return false, err
}
return true, nil
}
Expand Down
38 changes: 22 additions & 16 deletions pkg/oc/admin/diagnostics/diagnostics/cluster/network/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,28 @@ package network

// Set up test environment needed for network diagnostics
import (
"bytes"
"fmt"
"io/ioutil"
"strings"
"time"

kerrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
kerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/storage/names"
kclientcmd "k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/clientcmd/api/latest"
kapi "k8s.io/kubernetes/pkg/apis/core"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/printers"

"github.com/openshift/origin/pkg/client/config"
"github.com/openshift/origin/pkg/network"
networkapi "github.com/openshift/origin/pkg/network/apis/network"
"github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/cluster/network/in_pod/util"
diagutil "github.com/openshift/origin/pkg/oc/admin/diagnostics/diagnostics/util"
)

func (d *NetworkDiagnostic) TestSetup() error {
Expand Down Expand Up @@ -273,20 +276,23 @@ func (d *NetworkDiagnostic) makeNamespaceGlobal(nsName string) error {
})
}

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

for _, path := range paths {
if configData, err := ioutil.ReadFile(path); err == nil {
return configData, nil
}
// there does not seem to be a simple DefaultPrinter to invoke; create one
options := &printers.PrintOptions{
OutputFormatType: "yaml",
AllowMissingKeys: true,
}
printer, err := cmdutil.PrinterForOptions(meta.NewDefaultRESTMapper(nil, nil), latest.Scheme, nil, []runtime.Decoder{latest.Codec}, options)
if err != nil {
return nil, fmt.Errorf("from PrinterForOptions: %#v", err)
}
printer = printers.NewVersionedPrinter(printer, latest.Scheme, latest.ExternalVersion)

if err := printer.PrintObj(d.RawConfig, &b); err != nil {
return nil, fmt.Errorf("from PrintObj: %#v", err)
}
return nil, fmt.Errorf("Unable to find kube config")
return b.Bytes(), nil
}