Merge pull request #1 from Azure/jose/initial-run-and-connectivity

Add commands to run commands and check cluster connectivity
This commit is contained in:
Jose Blanquicet 2022-02-14 19:17:02 +01:00 коммит произвёл GitHub
Родитель b9037f28f6 344a4f31ef
Коммит dfc3eaae64
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 2995 добавлений и 24 удалений

4
.gitignore поставляемый
Просмотреть файл

@ -4,6 +4,8 @@
*.dll *.dll
*.so *.so
*.dylib *.dylib
/kubectl-az
/kubectl-az-*-*
# Test binary, built with `go test -c` # Test binary, built with `go test -c`
*.test *.test
@ -11,5 +13,3 @@
# Output of the go coverage tool, specifically when used with LiteIDE # Output of the go coverage tool, specifically when used with LiteIDE
*.out *.out
# Dependency directories (remove the comment below to include it)
# vendor/

62
Makefile Normal file
Просмотреть файл

@ -0,0 +1,62 @@
GOHOSTOS ?= $(shell go env GOHOSTOS)
GOHOSTARCH ?= $(shell go env GOHOSTARCH)
TAG := `git describe --tags --always`
VERSION :=
# Adds a '-dirty' suffix to version string if there are uncommitted changes
changes := $(shell git status --porcelain)
ifeq ($(changes),)
VERSION := $(TAG)
else
VERSION := $(TAG)-dirty
endif
LDFLAGS := "-X github.com/Azure/kubectl-az/cmd.version=$(VERSION) -extldflags '-static'"
.DEFAULT_GOAL := kubectl-az
KUBECTL_AZ_TARGETS = \
kubectl-az-linux-amd64 \
kubectl-az-linux-arm64 \
kubectl-az-darwin-amd64 \
kubectl-az-darwin-arm64 \
kubectl-az-windows-amd64
.PHONY: list-kubectl-az-targets
list-kubectl-az-targets:
@echo $(KUBECTL_AZ_TARGETS)
.PHONY: kubectl-az-all
kubectl-az-all: $(KUBECTL_AZ_TARGETS)
.PHONY: kubectl-az
kubectl-az: kubectl-az-$(GOHOSTOS)-$(GOHOSTARCH)
mv kubectl-az-$(GOHOSTOS)-$(GOHOSTARCH) kubectl-az
# make does not allow implicit rules (with '%') to be phony so let's use
# the 'phony_explicit' dependency to make implicit rules inherit the phony
# attribute
.PHONY: phony_explicit
phony_explicit:
.PHONY: kubectl-az-%
kubectl-az-%: phony_explicit
export GO111MODULE=on CGO_ENABLED=0 && \
export GOOS=$(shell echo $* |cut -f1 -d-) GOARCH=$(shell echo $* |cut -f2 -d-) && \
go build -ldflags $(LDFLAGS) \
-o kubectl-az-$${GOOS}-$${GOARCH} \
github.com/Azure/kubectl-az
.PHONY: install
install: kubectl-az
mkdir -p ~/.local/bin/
cp kubectl-az ~/.local/bin/
.PHONY: clean
clean:
rm -f kubectl-az
.PHONY: cleanall
cleanall: clean
rm -f $(KUBECTL_AZ_TARGETS)

108
README.md
Просмотреть файл

@ -1,33 +1,97 @@
# Project # Microsoft Azure CLI kubectl plugin
> This repo has been populated by an initial template to help get you started. Please `kubectl-az` is a set of commands used to troubleshoot Kubernetes clusters in
> make sure to update the content to build a great experience for community-building. Azure.
As the maintainer of this project, please make a few updates: Going through the following documentation will help you to understand each
available command and which one is the most suitable for your case:
- Improving this README.MD file to provide a great experience - [run-command](docs/run-command.md)
- Updating SUPPORT.MD with content about this project's support experience - [check-apiserver-connectivity](docs/check-apiserver-connectivity.md)
- Understanding the security reporting process in SECURITY.MD
- Remove this section from the README Consider `kubectl-az` expects the cluster to use virtual machine scale sets.
And, commands that allow using `--node` flag requires the Kubernetes API server
to up and running because it is used to retrieve the VMSS instance information
of nodes.
However, in case of issues with the Kubernetes API server, we can retrieve the
VMSS instance information from the [Azure portal](https://portal.azure.com/) and
pass it to the commands using the `--id` flag or separately with the
`--subscription`, `--node-resource-group`, `--vmss` and `--instance-id` flags.
## Install
```bash
$ git clone https://github.com/Azure/kubectl-az.git
$ cd kubectl-az
# Build and copy the resulting binary in $HOME/.local/bin/
$ make install
```
Notice it requires Go version 1.17.
## Usage
```bash
$ kubectl az --help
Microsoft Azure CLI kubectl plugin
Usage:
kubectl-az [command]
Available Commands:
check-apiserver-connectivity Check connectivity between the nodes and the Kubernetes API Server
completion Generate the autocompletion script for the specified shell
help Help about any command
run-command Run a command in a node
version Show version
Flags:
-h, --help help for kubectl-az
Use "kubectl-az [command] --help" for more information about a command.
```
It is necessary to sign in to Azure to run any `kubectl-az` command. To do so,
you can use any authentication method provided by the [Azure
CLI](https://github.com/Azure/azure-cli/) using the `az login` command; see
further details
[here](https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli).
However, if you do not have the Azure CLI or have not signed in yet,
`kubectl-az` will open the default browser and load the Azure sign-in page where
you need to authenticate.
## Future
- `kubectl-az` does not store the access token as Azure CLI does. Therefore,
unless you sign in using Azure CLI, `kubectl-az` will request you to
authenticate with the default web browser at every execution.
## Contributing ## Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a This project welcomes contributions and suggestions. Most contributions require
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us you to agree to a Contributor License Agreement (CLA) declaring that you have
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. the right to, and actually do, grant us the rights to use your contribution. For
details, visit https://cla.opensource.microsoft.com.
When you submit a pull request, a CLA bot will automatically determine whether you need to provide When you submit a pull request, a CLA bot will automatically determine whether
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions you need to provide a CLA and decorate the PR appropriately (e.g., status check,
provided by the bot. You will only need to do this once across all repos using our CLA. comment). Simply follow the instructions provided by the bot. You will only need
to do this once across all repos using our CLA.
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). This project has adopted the [Microsoft Open Source Code of
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or Conduct](https://opensource.microsoft.com/codeofconduct/). For more information
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. see the [Code of Conduct
FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional
questions or comments.
## Trademarks ## Trademarks
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft This project may contain trademarks or logos for projects, products, or
trademarks or logos is subject to and must follow services. Authorized use of Microsoft trademarks or logos is subject to and must
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). follow [Microsoft's Trademark & Brand
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
Any use of third-party trademarks or logos are subject to those third-party's policies. Use of Microsoft trademarks or logos in modified versions of this project must
not cause confusion or imply Microsoft sponsorship. Any use of third-party
trademarks or logos are subject to those third-party's policies.

Просмотреть файл

@ -0,0 +1,74 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package cmd
import (
"fmt"
"os"
"regexp"
"strconv"
"strings"
"github.com/Azure/kubectl-az/cmd/utils"
"github.com/spf13/cobra"
)
var connCheckVM utils.VirtualMachineScaleSetVM
var connCheckCmd = &cobra.Command{
Use: "check-apiserver-connectivity",
Short: "Check connectivity between the nodes and the Kubernetes API Server",
RunE: connCheckCmdRun,
SilenceUsage: true,
}
func init() {
utils.AddNodeFlags(connCheckCmd, &connCheckVM)
utils.AddCommonFlags(connCheckCmd, &commonFlags)
rootCmd.AddCommand(connCheckCmd)
}
func connCheckCmdRun(cmd *cobra.Command, args []string) error {
cred, err := utils.GetCredentials()
if err != nil {
return fmt.Errorf("failed to authenticate: %w", err)
}
// Check connectivity by executing "kubectl version" on the node. This
// command will try to contact the API server to get the Kubernetes version
// it is running. Use only the return value of the command, tough.
command := "kubectl --kubeconfig /var/lib/kubelet/kubeconfig version > /dev/null; echo $?"
res, err := utils.RunCommand(cmd.Context(), cred, &connCheckVM, &command, commonFlags.Verbose)
if err != nil {
return fmt.Errorf("failed to run command that checks connectivity: %w", err)
}
// Extract stdout and stderr from response.
// Expected format: "[stdout]<text>[stderr]<text>"
split := regexp.MustCompile(`(\[(stdout|stderr)\])`).Split(res, -1)
if len(split) != 3 {
return fmt.Errorf("couldn't parse response message:\n%s", res)
}
stdOutput := strings.TrimSpace(split[1])
stdError := strings.TrimSpace(split[2])
// The stdout should contain the returned value of "kubectl version":
// 0 (succeeded), otherwise (failure)
ret, err := strconv.Atoi(stdOutput)
if err != nil {
return fmt.Errorf("couldn't parse stdout of response message:\n%s", res)
}
if ret != 0 {
fmt.Printf("\nConnectivity check: failed with returned value %d: %s\n",
ret, stdError)
// Force the binary to return an exit code != 0 (forwarding command's
// return value). Useful if it is used in scripts.
os.Exit(ret)
}
fmt.Println("\nConnectivity check: succeeded")
return nil
}

26
cmd/root.go Normal file
Просмотреть файл

@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package cmd
import (
"os"
"github.com/Azure/kubectl-az/cmd/utils"
"github.com/spf13/cobra"
)
// Common flags for all subcommands
var commonFlags utils.CommonFlags
var rootCmd = &cobra.Command{
Use: "kubectl-az",
Short: "Microsoft Azure CLI kubectl plugin",
}
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}

52
cmd/run-command.go Normal file
Просмотреть файл

@ -0,0 +1,52 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package cmd
import (
"fmt"
"github.com/Azure/kubectl-az/cmd/utils"
"github.com/spf13/cobra"
)
var (
command string
runCommandVM utils.VirtualMachineScaleSetVM
)
var runCommandCmd = &cobra.Command{
Use: "run-command",
Short: "Run a command in a node",
RunE: runCommandCmdRun,
SilenceUsage: true,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("usage: %s <command>", cmd.CommandPath())
}
command = args[0]
return nil
},
}
func init() {
utils.AddNodeFlags(runCommandCmd, &runCommandVM)
utils.AddCommonFlags(runCommandCmd, &commonFlags)
rootCmd.AddCommand(runCommandCmd)
}
func runCommandCmdRun(cmd *cobra.Command, args []string) error {
cred, err := utils.GetCredentials()
if err != nil {
return fmt.Errorf("failed to authenticate: %w", err)
}
res, err := utils.RunCommand(cmd.Context(), cred, &runCommandVM, &command, commonFlags.Verbose)
if err != nil {
return fmt.Errorf("failed to run command: %w", err)
}
fmt.Printf("\n%s", res)
return nil
}

34
cmd/utils/auth.go Normal file
Просмотреть файл

@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package utils
import (
"fmt"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)
// Further details about authentication:
// https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/azidentity
func GetCredentials() (*azidentity.ChainedTokenCredential, error) {
azCLI, err := azidentity.NewAzureCLICredential(nil)
if err != nil {
return nil, fmt.Errorf("error creating default authentication chain: %w", err)
}
// Fallback if users didn't get already authenticated using the Azure CLI
inBrowser, err := azidentity.NewInteractiveBrowserCredential(nil)
if err != nil {
return nil, fmt.Errorf("error creating interactive authentication chain: %w", err)
}
// Methods will be tried in that specific order: (1) Azure CLI (2) Interactive
chain, err := azidentity.NewChainedTokenCredential([]azcore.TokenCredential{azCLI, inBrowser}, nil)
if err != nil {
return nil, fmt.Errorf("error creating credential chain: %w", err)
}
return chain, nil
}

114
cmd/utils/flags.go Normal file
Просмотреть файл

@ -0,0 +1,114 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package utils
import (
"context"
"errors"
"fmt"
"github.com/spf13/cobra"
)
// CommonFlags contains CLI flags common for all subcommands
type CommonFlags struct {
Verbose bool
}
func AddCommonFlags(command *cobra.Command, flags *CommonFlags) {
command.PersistentFlags().BoolVarP(
&flags.Verbose,
"verbose", "v",
false,
"Verbose output.",
)
}
// Every command that allows user to specify the node name has three options:
// (1) Provide the kubernetes node name
// (2) Provide the VMMS instance information (--subscription, --node-resource-group, --vmss and --instance-id)
// (3) Provide Resource ID (/subscriptions/mySubID/resourceGroups/myRG/providers/myProvider/virtualMachineScaleSets/myVMSS/virtualMachines/myInsID)
func AddNodeFlags(command *cobra.Command, vm *VirtualMachineScaleSetVM) {
var (
node string
subscriptionID string
nodeResourceGroup string
vmScaleSet string
instanceID string
resourceID string
)
command.PersistentFlags().StringVarP(
&node,
"node", "",
"",
"Kubernetes node name.",
)
command.PersistentFlags().StringVarP(
&subscriptionID,
"subscription", "",
"",
"Subscription ID.",
)
command.PersistentFlags().StringVarP(
&nodeResourceGroup,
"node-resource-group", "",
"",
"Node resource group name.",
)
command.PersistentFlags().StringVarP(
&vmScaleSet,
"vmss", "",
"",
"Virtual machine scale set name.",
)
command.PersistentFlags().StringVarP(
&instanceID,
"instance-id", "",
"",
"VM scale set instance ID.",
)
command.PersistentFlags().StringVarP(
&resourceID,
"id", "",
"",
`Resource ID containing all information of the VMSS instance using format:
e.g. /subscriptions/mySubID/resourceGroups/myRG/providers/myProvider/virtualMachineScaleSets/myVMSS/virtualMachines/myInsID.
Notice it is not case sensitive.`,
)
command.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
if node != "" {
if resourceID != "" {
return errors.New("specify either --node or --id but not both")
}
var err error
resourceID, err = GetNodeResourceID(context.TODO(), node)
if err != nil {
return fmt.Errorf("failed to retrieve Azure resource ID of node %s from API server: %w",
node, err)
}
}
if subscriptionID != "" && nodeResourceGroup != "" && vmScaleSet != "" && instanceID != "" {
if resourceID != "" {
return errors.New("do not provide VMMS instance information (--subscription, --node-resource-group, --vmss and --instance-id) when --node or --id were provided")
}
vm.SubscriptionID = subscriptionID
vm.NodeResourceGroup = nodeResourceGroup
vm.VMScaleSet = vmScaleSet
vm.InstanceID = instanceID
} else if resourceID != "" {
if err := ParseVMSSResourceID(resourceID, vm); err != nil {
return fmt.Errorf("failed to parse resource id: %w", err)
}
} else {
return errors.New("specify either --node or --id or VMMS instance information (--subscription, --node-resource-group, --vmss and --instance-id)")
}
return nil
}
}

32
cmd/utils/k8s.go Normal file
Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package utils
import (
"context"
"strings"
"github.com/kinvolk/inspektor-gadget/pkg/k8sutil"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
)
var KubernetesConfigFlags = genericclioptions.NewConfigFlags(false)
// GetNodeResourceID retrieve the Azure resource ID of a given node. In other
// words, the resource ID of the VM scale set instance. It returns format:
// /subscriptions/mySubID/resourceGroups/myRG/providers/myProvider/virtualMachineScaleSets/myVMSS/virtualMachines/myInsID
func GetNodeResourceID(ctx context.Context, nodeName string) (string, error) {
client, err := k8sutil.NewClientsetFromConfigFlags(KubernetesConfigFlags)
if err != nil {
return "", err
}
nodeRes, err := client.CoreV1().Nodes().Get(ctx, nodeName, metaV1.GetOptions{})
if err != nil {
return "", err
}
return strings.TrimPrefix(nodeRes.Spec.ProviderID, "azure://"), nil
}

115
cmd/utils/vmss.go Normal file
Просмотреть файл

@ -0,0 +1,115 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package utils
import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute"
"github.com/Azure/go-autorest/autorest/to"
)
type VirtualMachineScaleSetVM struct {
SubscriptionID string
NodeResourceGroup string
VMScaleSet string
InstanceID string
}
// ParseVMSSResourceID extracts elements from a given VMSS resource ID with format:
// /subscriptions/mySubID/resourceGroups/myRG/providers/myProvider/virtualMachineScaleSets/myVMSS/virtualMachines/myInsID
func ParseVMSSResourceID(id string, vm *VirtualMachineScaleSetVM) error {
const expectedItems int = 5
// This allows us to make resource ID (--id) option not case sentitive
id = strings.ToLower(id)
// Required because fmt.Sscanf expects space-separated values
idWithSpaces := strings.TrimSpace(strings.Replace(id, "/", " ", -1))
// We don't need the provider but fmt.Sscanf does not support "%*s" operator
// to read but prevent conversion. Therefore, read it and don't use it.
var provider string
n, err := fmt.Sscanf(idWithSpaces, "subscriptions %s resourcegroups %s providers %s virtualmachinescalesets %s virtualmachines %s",
&vm.SubscriptionID, &vm.NodeResourceGroup, &provider, &vm.VMScaleSet, &vm.InstanceID)
if err != nil {
return fmt.Errorf("error parsing provider ID %s: %w", id, err)
}
if n != expectedItems {
return fmt.Errorf("%d values retrieved while expecting %d when parsing id %s",
n, expectedItems, id)
}
return nil
}
func RunCommand(
ctx context.Context,
cred azcore.TokenCredential,
vm *VirtualMachineScaleSetVM,
command *string,
verbose bool,
) (
string,
error,
) {
const (
commandID = "RunShellScript"
initialDelay = 15 * time.Second
pollingFreq = 2 * time.Second
)
client := armcompute.NewVirtualMachineScaleSetVMsClient(vm.SubscriptionID, cred, nil)
script := []*string{command}
runCommand := armcompute.RunCommandInput{
CommandID: to.StringPtr(commandID),
Script: script,
}
if verbose {
b, _ := json.MarshalIndent(vm, "", " ")
fmt.Printf("Command: %s\nVirtual Machine Scale Set VM:\n%s\n\n", *command, string(b))
}
poller, err := client.BeginRunCommand(ctx, vm.NodeResourceGroup,
vm.VMScaleSet, vm.InstanceID, runCommand, nil)
if err != nil {
return "", fmt.Errorf("couldn't begin running command: %w", err)
}
fmt.Println("Running...")
res, err := poller.PollUntilDone(ctx, pollingFreq)
if err != nil {
return "", fmt.Errorf("error polling command response: %w", err)
}
if verbose {
b, _ := json.MarshalIndent(res, "", " ")
fmt.Printf("\nResponse:\n%s\n", string(b))
}
// TODO: Is it possible to have multiple values after using PollUntilDone()?
if len(res.Value) == 0 || res.Value[0] == nil {
return "", errors.New("no response received after command execution")
}
val := res.Value[0]
// TODO: Isn't there a constant in the SDK to compare this?
if to.String(val.Code) != "ProvisioningState/succeeded" {
b, _ := json.MarshalIndent(res, "", " ")
return "", fmt.Errorf("command execution didn't succeed:\n%s", string(b))
}
// Expected format: "Enable succeeded: \n<text>"
return strings.TrimPrefix(to.String(val.Message), "Enable succeeded: \n"), nil
}

69
cmd/utils/vmss_test.go Normal file
Просмотреть файл

@ -0,0 +1,69 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package utils
import (
"testing"
)
func TestParseVMSSResourceID(t *testing.T) {
type test struct {
description string
id string
expectedResult VirtualMachineScaleSetVM
expectedError bool
}
table := []test{
// KO tests
{
description: "From empty id",
id: "",
expectedResult: VirtualMachineScaleSetVM{},
expectedError: true,
},
{
description: "Unexpected format",
id: "subscriptionsmysubid",
expectedResult: VirtualMachineScaleSetVM{},
expectedError: true,
},
{
description: "Unexpected separator",
id: "subscriptions-mysubid",
expectedResult: VirtualMachineScaleSetVM{},
expectedError: true,
},
{
description: "Incomplete format",
id: "/subscriptions/mysubid",
expectedResult: VirtualMachineScaleSetVM{
SubscriptionID: "mysubid",
},
expectedError: true,
},
// OK test
{
description: "Correct format",
id: "/subscriptions/mysubid/resourcegroups/myrd/providers/myprovider/virtualmachinescalesets/myvmss/virtualmachines/myinsid",
expectedResult: VirtualMachineScaleSetVM{
SubscriptionID: "mysubid",
NodeResourceGroup: "myrd",
VMScaleSet: "myvmss",
InstanceID: "myinsid",
},
expectedError: false,
},
}
for _, entry := range table {
result := VirtualMachineScaleSetVM{}
err := ParseVMSSResourceID(entry.id, &result)
errorOcurred := err != nil
if errorOcurred != entry.expectedError || entry.expectedResult != result {
t.Fatalf("Failed test %q: result %+v (error %t - %s) vs expected %+v (error %t)",
entry.description, result, errorOcurred, err, entry.expectedResult, entry.expectedError)
}
}
}

25
cmd/version.go Normal file
Просмотреть файл

@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
// This variable is used by the "version" command and is set during build
var version = "undefined"
func init() {
rootCmd.AddCommand(versionCmd)
}
var versionCmd = &cobra.Command{
Use: "version",
Short: "Show version",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(version)
},
}

Просмотреть файл

@ -0,0 +1,71 @@
# Check Connectivity
We can use `check-connectivity` to verify that nodes can communicate with the
Kubernetes API server:
```bash
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
aks-agentpool-27170680-vmss000000 Ready agent 11d v1.22.4
aks-agentpool-27170680-vmss000001 Ready agent 11d v1.22.4
aks-agentpool-27170680-vmss000002 Ready agent 11d v1.22.4
$ kubectl az check-apiserver-connectivity --node aks-agentpool-27170680-vmss000000
Running...
Connectivity check: succeeded
```
Or we could also pass directly the VMSS instance information:
```bash
$ kubectl az check-apiserver-connectivity --id "/subscriptions/$SUBSCRIPTION/resourceGroups/$NODERESOURCEGROUP/providers/Microsoft.Compute/virtualMachineScaleSets/$VMSS/virtualmachines/$INSTANCEID"
```
```bash
$ kubectl az check-apiserver-connectivity --subscription $SUBSCRIPTION --node-resource-group $NODERESOURCEGROUP --vmss $VMSS --instance-id $INSTANCEID
```
The `check-connectivity` command verifies the connectivity between the nodes and
the API server by executing the command `kubectl version` from the node itself.
This command will try to contact the API server to get the Kubernetes version it
is running, which is enough to verify the connectivity. We have to consider that
`kubectl` uses the URL of the API server available in the `kubeconfig` file and
not directly the IP address. It means that this connectivity check requires the
DNS to be working correctly to succeed.
We can use the flag `-v`/`--verbose` to have further details about the command
that is being executed in the nodes to check connectivity:
```bash
$ kubectl az check-apiserver-connectivity --node aks-agentpool-27170680-vmss000001 -v
Command: kubectl --kubeconfig /var/lib/kubelet/kubeconfig version > /dev/null; echo $?
Virtual Machine Scale Set VM:
{
"SubscriptionID": "MySub",
"NodeResourceGroup": "MyNodeRG",
"VMScaleSet": "MyVMSS",
"InstanceID": "X"
}
Running...
Response:
{
"value": [
{
"code": "ProvisioningState/succeeded",
"displayStatus": "Provisioning succeeded",
"level": "Info",
"message": "Enable succeeded: \n[stdout]\n0\n\n[stderr]\n"
}
]
}
Connectivity check: succeeded
```
Given that the `check-connectivity` command checks the connectivity by running a
command on the nodes, all the
[restrictions](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/run-command#restrictions)
of running scripts in an Azure Linux VM also apply here.

54
docs/run-command.md Normal file
Просмотреть файл

@ -0,0 +1,54 @@
# Run Command
We can use `run-command` to execute a command on one of the cluster nodes:
```bash
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
aks-agentpool-27170680-vmss000000 Ready agent 11d v1.22.4
aks-agentpool-27170680-vmss000001 Ready agent 11d v1.22.4
aks-agentpool-27170680-vmss000002 Ready agent 11d v1.22.4
$ kubectl az run-command "ip route" --node aks-agentpool-27170680-vmss000000
Running...
[stdout]
default via 10.240.0.1 dev eth0 proto dhcp src 10.240.0.4 metric 100
10.240.0.0/16 dev eth0 proto kernel scope link src 10.240.0.4
10.244.2.2 dev calic38a36632c7 scope link
10.244.2.6 dev cali0b155bb80e7 scope link
10.244.2.7 dev cali997a02e57a6 scope link
10.244.2.8 dev calia2f1486fcb5 scope link
10.244.2.9 dev cali221544885dd scope link
10.244.2.10 dev cali8913de1b395 scope link
10.244.2.14 dev cali8eecb1f59c6 scope link
168.63.129.16 via 10.240.0.1 dev eth0 proto dhcp src 10.240.0.4 metric 100
169.254.169.254 via 10.240.0.1 dev eth0 proto dhcp src 10.240.0.4 metric 100
[stderr]
```
Another example when requested command prints information to the standard error:
```
$ kubectl az run-command "cat non-existent-file" --node aks-agentpool-27170680-vmss000000
Running...
[stdout]
[stderr]
cat: non-existent-file: No such file or directory
```
Or we could also pass directly the VMSS instance information:
```bash
$ kubectl az run-command "ip route" --id "/subscriptions/$SUBSCRIPTION/resourceGroups/$NODERESOURCEGROUP/providers/Microsoft.Compute/virtualMachineScaleSets/$VMSS/virtualmachines/$INSTANCEID"
```
```bash
$ kubectl az run-command "ip route" --subscription $SUBSCRIPTION --node-resource-group $NODERESOURCEGROUP --vmss $VMSS --instance-id $INSTANCEID
```
Take into account that all the
[restrictions](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/run-command#restrictions)
of running scripts in an Azure Linux VM also apply here.

80
go.mod Normal file
Просмотреть файл

@ -0,0 +1,80 @@
module github.com/Azure/kubectl-az
go 1.17
require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.13.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v0.3.0
github.com/Azure/go-autorest/autorest/to v0.4.0
github.com/kinvolk/inspektor-gadget v0.4.2
github.com/spf13/cobra v1.3.0
k8s.io/apimachinery v0.23.3
k8s.io/cli-runtime v0.23.3
)
require (
github.com/Azure/azure-sdk-for-go v61.1.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-logr/logr v1.2.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt v3.2.1+incompatible // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.2.0 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/api v0.23.3 // indirect
k8s.io/client-go v0.23.3 // indirect
k8s.io/klog/v2 v2.30.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
sigs.k8s.io/kustomize/api v0.10.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.13.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
)

2089
go.sum Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

10
main.go Normal file
Просмотреть файл

@ -0,0 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package main
import "github.com/Azure/kubectl-az/cmd"
func main() {
cmd.Execute()
}