Skip to content

Commit

Permalink
Add CLI to kuberay (#135)
Browse files Browse the repository at this point in the history
Co-authored-by: Yifei Feng <[email protected]>
  • Loading branch information
wolfsniper2388 and Yifei Feng authored Jan 27, 2022
1 parent 2ddaba6 commit 3cd3009
Show file tree
Hide file tree
Showing 28 changed files with 2,072 additions and 1 deletion.
7 changes: 6 additions & 1 deletion .github/workflows/test-job.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ jobs:
build:
env:
working-directory: ./ray-operator
cli-working-directory: ./cli
name: Build
runs-on: ubuntu-latest
steps:
Expand All @@ -74,7 +75,7 @@ jobs:
run: go get golang.org/x/tools/cmd/goimports

- name: Run goimports
run: test -z "$(set -o pipefail && $(go env GOPATH)/bin/goimports -l apiserver/ ray-operator/ | tee goimports.out)" || { cat goimports.out && exit 1; }
run: test -z "$(set -o pipefail && $(go env GOPATH)/bin/goimports -l apiserver/ ray-operator/ cli/ | tee goimports.out)" || { cat goimports.out && exit 1; }

- name: Open this to see how to fix goimports if it fails
run: echo Run goimports -w .
Expand Down Expand Up @@ -107,3 +108,7 @@ jobs:
- name: Build Docker Image
run: make docker-image
working-directory: ${{env.working-directory}}

- name: Build CLI
run: go build -o kuberay -a main.go
working-directory: ${{env.cli-working-directory}}
80 changes: 80 additions & 0 deletions cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# KubeRay CLI

[![Build Status](https://github.com/ray-project/kuberay/workflows/Go-build-and-test/badge.svg)](https://github.com/ray-project/kuberay/actions)
[![Go Report Card](https://goreportcard.com/badge/github.com/ray-project/kuberay)](https://goreportcard.com/report/github.com/ray-project/kuberay)

# Overview
KubeRay CLI provides the ability to manage kuberay resources (ray clusters, compute templates etc) through command line interface.

# Implementation
- Kuberay CLI uses [Cobra framework](https://github.com/spf13/cobra) for the CLI application.
- Kuberay CLI depends on kuberay apiserver to manage these resources by sending grpc requests to the kuberay apiserver.

# Installation
TBD

# Prerequisites
- Kuberay apiserver needs to be running and accessible.

# Build
`cd kuberay/cli`
`go build -o kuberay -a main.go`

# Use
## Connect to kuberay apiserver
- Default kuberay apiserver endpoint: `127.0.0.1:8887`.
- If kuberay apiserver is not run locally, this must be set in order to manage ray clusters and ray compute templates.
### Read current kuberay apiserver endpoint
`./kuberay config get endpoint`
### Reset kuberay apiserver endpoint to default (`127.0.0.1:8887`)
`./kuberay config reset endpoint`
### Set kuberay apiserver endpoint
`./kuberay config set endpoint <kuberay apiserver endpoint>`
## Manage Ray Clusters
### Create a Ray Cluster
````
Usage:
kuberay cluster create [flags]
Flags:
--environment string environment of the cluster (valid values: DEV, TESTING, STAGING, PRODUCTION) (default "DEV")
--head-compute-tempalte string compuate template name for ray head
--head-image string ray head image
--head-service-type string ray head service type (ClusterIP, NodePort, LoadBalancer) (default "ClusterIP")
--name string name of the cluster
--namespace string kubernetes namespace where the cluster will be (default "ray-system")
--user string SSO username of ray cluster creator
--version string version of the ray cluster (default "1.9.0")
--worker-compute-template string compute template name of worker in the first worker group
--worker-group-name string first worker group name
--worker-image string image of worker in the first worker group
--worker-replicas uint32 pod replicas of workers in the first worker group (default 1)
````
- Limitation: Currently only one worker compute template is supported during creation.
### Get a Ray Cluster
`./kuberay cluster get <cluster name>`
### List Ray Clusters
`./kuberay cluster list`
### Delete a Ray Cluster
`./kuberay cluster delete <cluster name>`
## Manage Ray Compute Template
### Create a Compute Template
````
Usage:
kuberay template compute create [flags]
Flags:
--cpu uint32 ray pod CPU (default 1)
--gpu uint32 ray head GPU
--gpu-accelerator string GPU Accelerator type
--memory uint32 ray pod memory in GB (default 1)
--name string name of the compute template
````
### Get a Ray Compute Template
`./kuberay template compute get <compute template name>`
### List Ray Compute Templates
`./kuberay template compute list`
### Delete a Ray Compute Template
`./kuberay template compute delete <compute template name>`

154 changes: 154 additions & 0 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package cmd

import (
"fmt"
"os"
"strings"
"time"

"github.com/ray-project/kuberay/cli/pkg/cmd/cluster"
"github.com/ray-project/kuberay/cli/pkg/cmd/config"
"github.com/ray-project/kuberay/cli/pkg/cmd/info"
"github.com/ray-project/kuberay/cli/pkg/cmd/template"
"github.com/ray-project/kuberay/cli/pkg/cmd/version"
"github.com/ray-project/kuberay/cli/pkg/cmdutil"
"github.com/spf13/cobra"

"github.com/fatih/color"
"github.com/kris-nova/logger"
lol "github.com/kris-nova/lolgopher"
"github.com/spf13/viper"
)

var cfgFile string

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "kuberay",
Short: "kuberay offers life cycle management of ray clusters",
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
cobra.CheckErr(rootCmd.Execute())
}

func init() {
loggerLevel := rootCmd.PersistentFlags().IntP("log-level", "l", 3, "set log level, use 0 to silence, 4 for debugging and 5 for debugging with AWS debug logging")
colorValue := rootCmd.PersistentFlags().StringP("color", "C", "true", "toggle colorized logs (valid options: true, false, fabulous)")
cobra.OnInitialize(initConfig, func() {
initLogger(*loggerLevel, *colorValue)
})

// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.

rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.kuberay.yaml)")

// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

rootCmd.PersistentFlags().BoolP("help", "h", false, "help for this command")
rootCmd.AddCommand(info.NewCmdInfo())
rootCmd.AddCommand(version.NewCmdVersion())
rootCmd.AddCommand(cluster.NewCmdCluster())
rootCmd.AddCommand(template.NewCmdTemplate())
rootCmd.AddCommand(config.NewCmdConfig())
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := os.UserHomeDir()
cobra.CheckErr(err)

// Search config in home directory with name ".cli" (without extension).
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".kuberay")

viper.SetDefault("endpoint", fmt.Sprintf("%s:%s", cmdutil.DefaultRpcAddress, cmdutil.DefaultRpcPort))
// Do not write to file system if it already exists
viper.SafeWriteConfig()
}

viper.AutomaticEnv() // read in environment variables that match

viper.ReadInConfig()
}

func initLogger(level int, colorValue string) {
logger.Layout = "2021-01-02 15:04:05"

var bitwiseLevel int
switch level {
case 4:
bitwiseLevel = logger.LogDeprecated | logger.LogAlways | logger.LogSuccess | logger.LogCritical | logger.LogWarning | logger.LogInfo | logger.LogDebug
case 3:
bitwiseLevel = logger.LogDeprecated | logger.LogAlways | logger.LogSuccess | logger.LogCritical | logger.LogWarning | logger.LogInfo
case 2:
bitwiseLevel = logger.LogDeprecated | logger.LogAlways | logger.LogSuccess | logger.LogCritical | logger.LogWarning
case 1:
bitwiseLevel = logger.LogDeprecated | logger.LogAlways | logger.LogSuccess | logger.LogCritical
case 0:
bitwiseLevel = logger.LogDeprecated | logger.LogAlways | logger.LogSuccess
default:
bitwiseLevel = logger.LogDeprecated | logger.LogEverything
}
logger.BitwiseLevel = bitwiseLevel

switch colorValue {
case "fabulous":
logger.Writer = lol.NewLolWriter()
case "true":
logger.Writer = color.Output
}

logger.Line = func(prefix, format string, a ...interface{}) string {
if !strings.Contains(format, "\n") {
format = fmt.Sprintf("%s%s", format, "\n")
}
now := time.Now()
fNow := now.Format(logger.Layout)
var colorize func(format string, a ...interface{}) string
var icon string
switch prefix {
case logger.PreAlways:
icon = "✿"
colorize = color.GreenString
case logger.PreCritical:
icon = "✖"
colorize = color.RedString
case logger.PreInfo:
icon = "ℹ"
colorize = color.CyanString
case logger.PreDebug:
icon = "▶"
colorize = color.GreenString
case logger.PreSuccess:
icon = "✔"
colorize = color.CyanString
case logger.PreWarning:
icon = "!"
colorize = color.GreenString
default:
icon = "ℹ"
colorize = color.CyanString
}

out := fmt.Sprintf(format, a...)
out = fmt.Sprintf("%s [%s] %s", fNow, icon, out)
if colorValue == "true" {
out = colorize(out)
}

return out
}
}
42 changes: 42 additions & 0 deletions cli/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
module github.com/ray-project/kuberay/cli

go 1.17

require (
github.com/fatih/color v1.13.0
github.com/kris-nova/logger v0.2.2
github.com/kris-nova/lolgopher v0.0.0-20210112022122-73f0047e8b65
github.com/olekukonko/tablewriter v0.0.5
github.com/ray-project/kuberay/proto v0.0.0-20220119062608-4054f1bf1765
github.com/spf13/cobra v1.3.0
github.com/spf13/viper v1.10.1
google.golang.org/grpc v1.43.0
)

require (
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
Loading

0 comments on commit 3cd3009

Please sign in to comment.