Skip to content

Commit

Permalink
Use 'oc' in tridentctl in OpenShift environments
Browse files Browse the repository at this point in the history
  • Loading branch information
clintonk committed Oct 18, 2017
1 parent 4d2f6fa commit c7e7123
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
- Added support for NetApp Volume Encryption to the ONTAP drivers
(Issue [#3](https://github.com/NetApp/trident/issues/3)).
- Trident installer now works with Kubernetes 1.8.
- tridentctl can detect and use 'oc' in OpenShift environments.

## v17.07.0

Expand Down
27 changes: 23 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ The current attributes and their possible values are below:
| provisioningType | string | thin, thick | Types of provisioning supported by the storage pool. | Whether volumes will be created with thick or thin provisioning. | thick provisioning: ontap-nas, ontap-nas-economy, ontap-san, eseries-iscsi; thin provisioning: ontap-nas, ontap-nas-economy, ontap-san, solidfire-san |
| backendType | string | ontap-nas, ontap-nas-economy, ontap-san, solidfire-san, eseries-iscsi | Backend to which the storage pool belongs. | Specific type of backend on which to provision volumes. | All drivers |
| snapshots | bool | true, false | Whether the backend supports snapshots. | Whether volumes must have snapshot support. | ontap-nas, ontap-san, solidfire-san |
| encryption | bool | true, false | Whether the backend supports volume encryption. | Whether volumes must be encrypted. |
| encryption | bool | true, false | Whether the backend supports volume encryption. | Whether volumes must be encrypted. | ontap-nas, ontap-san, ontap-nas-economy |
| IOPS | int | positive integers | IOPS range the storage pool is capable of providing. | Target IOPS for the volume to be created. | solidfire-san |
Expand Down Expand Up @@ -849,7 +849,7 @@ a command-line utility, `tridentctl`, that provides simple access to Trident.
`tridentctl` can be used to interact with Trident when deployed as a Kubernetes pod
or as a standalone binary. Kubernetes users with sufficient privileges to
manage the namespace that contains the Trident pod may use tridentctl.
Here are a few examples one can use `tridentctl` for to manage Trident backends:
Here are a few `tridentctl` examples for managing Trident backends:
1. Add a new storage backend or update an existing one:
```bash
Expand All @@ -867,6 +867,18 @@ Here are a few examples one can use `tridentctl` for to manage Trident backends:
$ tridentctl get backend <backend-name> -o json
```
4. List all backends managed by Trident, if Trident is running as a standalone
binary. The address and port values are set via arguments to the Trident binary.
```bash
$ export TRIDENT_SERVER=127.0.0.1:8000
$ tridentctl get backend
```
5. Get the logs from Trident:
```bash
$ tridentctl logs
```
Similar commands can be used to list and retrieve the details for volumes and
storage classes managed by Trident. You can get more information by running
`tridentctl --help`. `tridentctl` currently supports adding, updating, listing,
Expand Down Expand Up @@ -1173,9 +1185,16 @@ changes since v1.0).
### Getting Help
Trident is a supported NetApp project. See the [find the support you need](http://mysupport.netapp.com/info/web/ECMLP2619434.html) page on the Support site for options available to you. To open a support case, use the serial number of the backend storage system and select containers and Trident as the category you want help in.
Trident is a supported NetApp project. See the [find the support you need](http://mysupport.netapp.com/info/web/ECMLP2619434.html)
page on the Support site for options available to you. To open a support case,
use the serial number of the backend storage system and select containers and
Trident as the category you want help in. To create a support archive containing
all available Trident logs, use `tridentctl logs -a`.
There is also a vibrant community of container users and engineers on Pub's [#containers](https://netapppub.slack.com/messages/C1E3QH84C) Slack channel. This can be a great place to get answers and discuss with like-minded peers; highly recommended!
There is also a vibrant community of container users and engineers on the
[#containers](https://netapppub.slack.com/messages/C1E3QH84C) Slack channel at
[thePub](http://netapp.io). This can be a great place to get answers and discuss
with like-minded peers; highly recommended!
## Caveats
Expand Down
12 changes: 6 additions & 6 deletions cli/cmd/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,16 +208,16 @@ func getTridentLogs(log string, logMap map[string][]byte) error {
return fmt.Errorf("%s is not a valid Trident log", log)
}

// Build command for 'kubectl logs'
// Build command to get K8S logs
limit := fmt.Sprintf("--limit-bytes=%d", LOG_LIMIT_BYTES)
logsCommand := []string{"logs", TridentPodName, "-n", TridentPodNamespace, "-c", container, limit}

if Debug {
fmt.Printf("Invoking command: kubectl %v\n", strings.Join(logsCommand, " "))
fmt.Printf("Invoking command: %s %v\n", KubernetesCLI, strings.Join(logsCommand, " "))
}

// Get logs
logBytes, err := exec.Command("kubectl", logsCommand...).CombinedOutput()
logBytes, err := exec.Command(KubernetesCLI, logsCommand...).CombinedOutput()
if err != nil {
logMap["error"] = appendError(logMap["error"], logBytes)
} else {
Expand All @@ -239,16 +239,16 @@ func getPodLogs(log string, logMap map[string][]byte) error {
return fmt.Errorf("%s is not a valid Trident log", log)
}

// Build command for 'kubectl logs'
// Build command to get K8S logs
limit := fmt.Sprintf("--limit-bytes=%d", LOG_LIMIT_BYTES)
logsCommand := []string{"logs", pod, "-n", TridentPodNamespace, limit}

if Debug {
fmt.Printf("Invoking command: kubectl %v\n", strings.Join(logsCommand, " "))
fmt.Printf("Invoking command: %s %v\n", KubernetesCLI, strings.Join(logsCommand, " "))
}

// Get logs
logBytes, err := exec.Command("kubectl", logsCommand...).CombinedOutput()
logBytes, err := exec.Command(KubernetesCLI, logsCommand...).CombinedOutput()
if err != nil {
logMap["error"] = appendError(logMap["error"], logBytes)
} else {
Expand Down
64 changes: 50 additions & 14 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"encoding/json"
"errors"
"fmt"
"os"
"os/exec"
Expand All @@ -23,6 +24,9 @@ const (
MODE_TUNNEL = "tunnel"
MODE_LOGS = "logs"

CLI_KUBERNETES = "kubectl"
CLI_OPENSHIFT = "oc"

POD_SERVER = "127.0.0.1:8000"

EXIT_CODE_SUCCESS = 0
Expand All @@ -31,6 +35,7 @@ const (

var (
OperatingMode string
KubernetesCLI string
TridentPodName string
TridentPodNamespace string
ExitCode int
Expand Down Expand Up @@ -69,10 +74,11 @@ func discoverOperatingMode(cmd *cobra.Command) error {
case MODE_DIRECT:
fmt.Printf("Operating mode = %s, Server = %s\n", OperatingMode, Server)
case MODE_TUNNEL:
fmt.Printf("Operating mode = %s, Trident pod = %s, Namespace = %s\n",
OperatingMode, TridentPodName, TridentPodNamespace)
fmt.Printf("Operating mode = %s, Trident pod = %s, Namespace = %s, CLI = %s\n",
OperatingMode, TridentPodName, TridentPodNamespace, KubernetesCLI)
case MODE_LOGS:
fmt.Printf("Operating mode = %s, Namespace = %s\n", OperatingMode, TridentPodNamespace)
fmt.Printf("Operating mode = %s, Namespace = %s, CLI = %s\n",
OperatingMode, TridentPodNamespace, KubernetesCLI)
}
}()

Expand All @@ -93,6 +99,12 @@ func discoverOperatingMode(cmd *cobra.Command) error {
return nil
}

// To work with pods, we need to discover which CLI to invoke
err = discoverKubernetesCLI()
if err != nil {
return err
}

// Server not specified, so try tunneling to a pod
if TridentPodNamespace == "" {
TridentPodNamespace, err = getCurrentNamespace()
Expand All @@ -117,10 +129,29 @@ func discoverOperatingMode(cmd *cobra.Command) error {
return nil
}

func discoverKubernetesCLI() error {

// Try the OpenShift CLI first
_, err := exec.Command(CLI_OPENSHIFT, "version").CombinedOutput()
if GetExitCodeFromError(err) == EXIT_CODE_SUCCESS {
KubernetesCLI = CLI_OPENSHIFT
return nil
}

// Fall back to the K8S CLI
_, err = exec.Command(CLI_KUBERNETES, "version").CombinedOutput()
if GetExitCodeFromError(err) == EXIT_CODE_SUCCESS {
KubernetesCLI = CLI_KUBERNETES
return nil
}

return errors.New("Could not find the Kubernetes CLI.")
}

func getCurrentNamespace() (string, error) {

// Get current namespace from service account info
cmd := exec.Command("kubectl", "get", "serviceaccount", "default", "-o=json")
cmd := exec.Command(KubernetesCLI, "get", "serviceaccount", "default", "-o=json")
stdout, err := cmd.StdoutPipe()
if err != nil {
return "", err
Expand Down Expand Up @@ -148,7 +179,7 @@ func getCurrentNamespace() (string, error) {
func getTridentPod(namespace string) (string, error) {

// Get 'trident' pod info
cmd := exec.Command("kubectl", "get", "pod", "-n", namespace, "-l", "app=trident.netapp.io", "-o=json")
cmd := exec.Command(KubernetesCLI, "get", "pod", "-n", namespace, "-l", "app=trident.netapp.io", "-o=json")
stdout, err := cmd.StdoutPipe()
if err != nil {
return "", err
Expand Down Expand Up @@ -192,7 +223,7 @@ func GetBaseURL() (string, error) {

func TunnelCommand(commandArgs []string) {

// Build tunnel command for 'kubectl exec'
// Build tunnel command to exec command in container
execCommand := []string{"exec", TridentPodName, "-n", TridentPodNamespace, "-c", config.ContainerTrident, "--"}

// Build CLI command
Expand All @@ -209,11 +240,11 @@ func TunnelCommand(commandArgs []string) {
execCommand = append(execCommand, cliCommand...)

if Debug {
fmt.Printf("Invoking tunneled command: kubectl %v\n", strings.Join(execCommand, " "))
fmt.Printf("Invoking tunneled command: %s %v\n", KubernetesCLI, strings.Join(execCommand, " "))
}

// Invoke tridentctl inside the Trident pod
out, err := exec.Command("kubectl", execCommand...).CombinedOutput()
out, err := exec.Command(KubernetesCLI, execCommand...).CombinedOutput()

SetExitCodeFromError(err)
if err != nil {
Expand All @@ -225,7 +256,7 @@ func TunnelCommand(commandArgs []string) {

func TunnelCommandRaw(commandArgs []string) ([]byte, error) {

// Build tunnel command for 'kubectl exec'
// Build tunnel command to exec command in container
execCommand := []string{"exec", TridentPodName, "-n", TridentPodNamespace, "-c", config.ContainerTrident, "--"}

// Build CLI command
Expand All @@ -236,28 +267,33 @@ func TunnelCommandRaw(commandArgs []string) ([]byte, error) {
execCommand = append(execCommand, cliCommand...)

if Debug {
fmt.Printf("Invoking tunneled command: kubectl %v\n", strings.Join(execCommand, " "))
fmt.Printf("Invoking tunneled command: %s %v\n", KubernetesCLI, strings.Join(execCommand, " "))
}

// Invoke tridentctl inside the Trident pod
output, err := exec.Command("kubectl", execCommand...).CombinedOutput()
output, err := exec.Command(KubernetesCLI, execCommand...).CombinedOutput()

SetExitCodeFromError(err)
return output, err
}

func SetExitCodeFromError(err error) {
ExitCode = GetExitCodeFromError(err)
}

func GetExitCodeFromError(err error) int {
if err == nil {
ExitCode = EXIT_CODE_SUCCESS
return EXIT_CODE_SUCCESS
} else {

// Default to 1 in case we can't determine a process exit code
ExitCode = EXIT_CODE_FAILURE
code := EXIT_CODE_FAILURE

if exitError, ok := err.(*exec.ExitError); ok {
ws := exitError.Sys().(syscall.WaitStatus)
ExitCode = ws.ExitStatus()
code = ws.ExitStatus()
}

return code
}
}

0 comments on commit c7e7123

Please sign in to comment.