Skip to content

Commit

Permalink
Refactor command structure
Browse files Browse the repository at this point in the history
  • Loading branch information
jessesuen committed Mar 6, 2018
1 parent 101509d commit 90c08bf
Show file tree
Hide file tree
Showing 19 changed files with 427 additions and 475 deletions.
3 changes: 2 additions & 1 deletion cmd/argo/commands/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var (
clientset *kubernetes.Clientset
wfClient v1alpha1.WorkflowInterface
jobStatusIconMap map[wfv1.NodePhase]string
noColor bool
)

func init() {
Expand Down Expand Up @@ -107,7 +108,7 @@ func InitWorkflowClient(ns ...string) v1alpha1.WorkflowInterface {
// color, it provides more consistent string lengths so that tabwriter can calculate
// widths correctly.
func ansiFormat(s string, codes ...int) string {
if globalArgs.noColor || os.Getenv("TERM") == "dumb" || len(codes) == 0 {
if noColor || os.Getenv("TERM") == "dumb" || len(codes) == 0 {
return s
}
codeStrs := make([]string, len(codes))
Expand Down
69 changes: 33 additions & 36 deletions cmd/argo/commands/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,41 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func init() {
RootCmd.AddCommand(deleteCmd)
deleteCmd.Flags().BoolVar(&deleteArgs.all, "all", false, "Delete all workflows")
deleteCmd.Flags().BoolVar(&deleteArgs.completed, "completed", false, "Delete completed workflows")
}

type deleteFlags struct {
all bool // --all
completed bool // --completed
}
// NewDeleteCommand returns a new instance of an `argocd repo` command
func NewDeleteCommand() *cobra.Command {
var (
all bool
completed bool
)

var deleteArgs deleteFlags

var deleteCmd = &cobra.Command{
Use: "delete WORKFLOW",
Short: "delete a workflow and its associated pods",
Run: deleteWorkflowCmd,
}

func deleteWorkflowCmd(cmd *cobra.Command, args []string) {
wfClient = InitWorkflowClient()
if deleteArgs.all {
deleteWorkflows(metav1.ListOptions{})
return
} else if deleteArgs.completed {
options := metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=true", common.LabelKeyCompleted),
}
deleteWorkflows(options)
return
}
if len(args) == 0 {
cmd.HelpFunc()(cmd, args)
os.Exit(1)
}
for _, wfName := range args {
deleteWorkflow(wfName)
var command = &cobra.Command{
Use: "delete WORKFLOW",
Short: "delete a workflow and its associated pods",
Run: func(cmd *cobra.Command, args []string) {
wfClient = InitWorkflowClient()
if all {
deleteWorkflows(metav1.ListOptions{})
return
} else if completed {
options := metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=true", common.LabelKeyCompleted),
}
deleteWorkflows(options)
return
}
if len(args) == 0 {
cmd.HelpFunc()(cmd, args)
os.Exit(1)
}
for _, wfName := range args {
deleteWorkflow(wfName)
}
},
}

command.Flags().BoolVar(&all, "all", false, "Delete all workflows")
command.Flags().BoolVar(&completed, "completed", false, "Delete completed workflows")
return command
}

func deleteWorkflow(wfName string) {
Expand Down
94 changes: 41 additions & 53 deletions cmd/argo/commands/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,40 +19,34 @@ import (

const onExitSuffix = "onExit"

func init() {
RootCmd.AddCommand(getCmd)
getCmd.Flags().StringVarP(&getArgs.output, "output", "o", "", "Output format. One of: json|yaml|wide")
getCmd.Flags().BoolVar(&globalArgs.noColor, "no-color", false, "Disable colorized output")
}

type getFlags struct {
output string // --output
}

var getArgs getFlags

var getCmd = &cobra.Command{
Use: "get WORKFLOW",
Short: "display details about a workflow",
Run: GetWorkflow,
}

// GetWorkflow gets the workflow passed in as args
func GetWorkflow(cmd *cobra.Command, args []string) {
if len(args) == 0 {
cmd.HelpFunc()(cmd, args)
os.Exit(1)
func NewGetCommand() *cobra.Command {
var (
output string
)

var command = &cobra.Command{
Use: "get WORKFLOW",
Short: "display details about a workflow",
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
cmd.HelpFunc()(cmd, args)
os.Exit(1)
}
wfClient := InitWorkflowClient()
wf, err := wfClient.Get(args[0], metav1.GetOptions{})
if err != nil {
log.Fatal(err)
}
printWorkflow(wf, output)
},
}

wfClient := InitWorkflowClient()
wf, err := wfClient.Get(args[0], metav1.GetOptions{})
if err != nil {
log.Fatal(err)
}
printWorkflow(getArgs.output, wf)
command.Flags().StringVarP(&output, "output", "o", "", "Output format. One of: json|yaml|wide")
command.Flags().BoolVar(&noColor, "no-color", false, "Disable colorized output")
return command
}

func printWorkflow(outFmt string, wf *wfv1.Workflow) {
func printWorkflow(wf *wfv1.Workflow, outFmt string) {
switch outFmt {
case "name":
fmt.Println(wf.ObjectMeta.Name)
Expand All @@ -63,13 +57,13 @@ func printWorkflow(outFmt string, wf *wfv1.Workflow) {
outBytes, _ := yaml.Marshal(wf)
fmt.Print(string(outBytes))
case "wide", "":
printWorkflowHelper(wf)
printWorkflowHelper(wf, outFmt)
default:
log.Fatalf("Unknown output format: %s", outFmt)
}
}

func printWorkflowHelper(wf *wfv1.Workflow) {
func printWorkflowHelper(wf *wfv1.Workflow, outFmt string) {
const fmtStr = "%-17s %v\n"
fmt.Printf(fmtStr, "Name:", wf.ObjectMeta.Name)
fmt.Printf(fmtStr, "Namespace:", wf.ObjectMeta.Namespace)
Expand Down Expand Up @@ -118,7 +112,7 @@ func printWorkflowHelper(wf *wfv1.Workflow) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Println()
// apply a dummy FgDefault format to align tabwriter with the rest of the columns
if getArgs.output == "wide" {
if outFmt == "wide" {
fmt.Fprintf(w, "%s\tPODNAME\tDURATION\tARTIFACTS\tMESSAGE\n", ansiFormat("STEP", FgDefault))
} else {
fmt.Fprintf(w, "%s\tPODNAME\tDURATION\tMESSAGE\n", ansiFormat("STEP", FgDefault))
Expand All @@ -132,7 +126,7 @@ func printWorkflowHelper(wf *wfv1.Workflow) {
for _, id := range rootNodeIDs {
if node, ok := wf.Status.Nodes[id]; ok {
if root, ok := roots[node.ID]; ok {
root.renderNodes(w, wf, 0, " ", " ")
root.renderNodes(w, wf, 0, " ", " ", outFmt)
}
}
}
Expand Down Expand Up @@ -166,8 +160,7 @@ func (n *nodeInfo) getStartTime(wf *wfv1.Workflow) metav1.Time {
// Interface to represent Nodes in render form types
type renderNode interface {
// Render this renderNode and its children
renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int,
nodePrefix string, childPrefix string)
renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int, nodePrefix string, childPrefix string, outFmt string)
nodeInfoInterface
}

Expand Down Expand Up @@ -352,7 +345,7 @@ func filterNode(node wfv1.NodeStatus) (bool, bool) {
// whether it was filtered and does this child need special indent
func renderChild(w *tabwriter.Writer, wf *wfv1.Workflow, nInfo renderNode, depth int,
nodePrefix string, childPrefix string, parentFiltered bool,
childIndex int, maxIndex int, childIndent bool) {
childIndex int, maxIndex int, childIndent bool, outFmt string) {
var part, subp string
if parentFiltered && childIndent {
if maxIndex == 0 {
Expand Down Expand Up @@ -390,12 +383,11 @@ func renderChild(w *tabwriter.Writer, wf *wfv1.Workflow, nInfo renderNode, depth
}
childChldPrefix = childPrefix + subp
}
nInfo.renderNodes(w, wf, depth, childNodePrefix, childChldPrefix)
nInfo.renderNodes(w, wf, depth, childNodePrefix, childChldPrefix, outFmt)
}

// Main method to print information of node in get
func printNode(w *tabwriter.Writer, wf *wfv1.Workflow, node wfv1.NodeStatus, depth int,
nodePrefix string, childPrefix string) {
func printNode(w *tabwriter.Writer, wf *wfv1.Workflow, node wfv1.NodeStatus, depth int, nodePrefix string, childPrefix string, outFmt string) {

nodeName := fmt.Sprintf("%s %s", jobStatusIconMap[node.Phase], node.DisplayName)
var args []interface{}
Expand All @@ -405,7 +397,7 @@ func printNode(w *tabwriter.Writer, wf *wfv1.Workflow, node wfv1.NodeStatus, dep
} else {
args = []interface{}{nodePrefix, nodeName, "", "", node.Message}
}
if getArgs.output == "wide" {
if outFmt == "wide" {
msg := args[len(args)-1]
args[len(args)-1] = getArtifactsString(node)
args = append(args, msg)
Expand All @@ -417,40 +409,36 @@ func printNode(w *tabwriter.Writer, wf *wfv1.Workflow, node wfv1.NodeStatus, dep

// renderNodes for each renderNode Type
// boundaryNode
func (nodeInfo *boundaryNode) renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int,
nodePrefix string, childPrefix string) {

func (nodeInfo *boundaryNode) renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int, nodePrefix string, childPrefix string, outFmt string) {
filtered, childIndent := filterNode(nodeInfo.getNodeStatus(wf))
if !filtered {
printNode(w, wf, nodeInfo.getNodeStatus(wf), depth, nodePrefix, childPrefix)
printNode(w, wf, nodeInfo.getNodeStatus(wf), depth, nodePrefix, childPrefix, outFmt)
}

for i, nInfo := range nodeInfo.boundaryContained {
renderChild(w, wf, nInfo, depth, nodePrefix, childPrefix, filtered, i,
len(nodeInfo.boundaryContained)-1, childIndent)
len(nodeInfo.boundaryContained)-1, childIndent, outFmt)
}
}

// nonBoundaryParentNode
func (nodeInfo *nonBoundaryParentNode) renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int,
nodePrefix string, childPrefix string) {
func (nodeInfo *nonBoundaryParentNode) renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int, nodePrefix string, childPrefix string, outFmt string) {
filtered, childIndent := filterNode(nodeInfo.getNodeStatus(wf))
if !filtered {
printNode(w, wf, nodeInfo.getNodeStatus(wf), depth, nodePrefix, childPrefix)
printNode(w, wf, nodeInfo.getNodeStatus(wf), depth, nodePrefix, childPrefix, outFmt)
}

for i, nInfo := range nodeInfo.children {
renderChild(w, wf, nInfo, depth, nodePrefix, childPrefix, filtered, i,
len(nodeInfo.children)-1, childIndent)
len(nodeInfo.children)-1, childIndent, outFmt)
}
}

// executionNode
func (nodeInfo *executionNode) renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int,
nodePrefix string, childPrefix string) {
func (nodeInfo *executionNode) renderNodes(w *tabwriter.Writer, wf *wfv1.Workflow, depth int, nodePrefix string, childPrefix string, outFmt string) {
filtered, _ := filterNode(nodeInfo.getNodeStatus(wf))
if !filtered {
printNode(w, wf, nodeInfo.getNodeStatus(wf), depth, nodePrefix, childPrefix)
printNode(w, wf, nodeInfo.getNodeStatus(wf), depth, nodePrefix, childPrefix, outFmt)
}
}

Expand Down
56 changes: 27 additions & 29 deletions cmd/argo/commands/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,6 @@ var (
DefaultUiImage = imageNamespace + "/argoui:" + imageTag
)

func init() {
RootCmd.AddCommand(installCmd)
installCmd.Flags().BoolVar(&installArgs.Upgrade, "upgrade", false, "upgrade controller/ui deployments and configmap if already installed")
installCmd.Flags().BoolVar(&installArgs.DryRun, "dry-run", false, "print the kubernetes manifests to stdout instead of installing")
installCmd.Flags().StringVar(&installArgs.Namespace, "install-namespace", common.DefaultControllerNamespace, "install into a specific Namespace")
installCmd.Flags().StringVar(&installArgs.InstanceID, "instanceid", "", "optional instance id to use for the controller (for multi-controller environments)")
installCmd.Flags().StringVar(&installArgs.ConfigMap, "configmap", common.DefaultConfigMapName(common.DefaultControllerDeploymentName), "install controller using preconfigured configmap")
installCmd.Flags().StringVar(&installArgs.ControllerName, "controller-name", common.DefaultControllerDeploymentName, "name of controller deployment")
installCmd.Flags().StringVar(&installArgs.ControllerImage, "controller-image", DefaultControllerImage, "use a specified controller image")
installCmd.Flags().StringVar(&installArgs.ServiceAccount, "service-account", "", "use a specified service account for the workflow-controller deployment")
installCmd.Flags().StringVar(&installArgs.ExecutorImage, "executor-image", DefaultExecutorImage, "use a specified executor image")
installCmd.Flags().StringVar(&installArgs.UIName, "ui-name", ArgoUIDeploymentName, "name of ui deployment")
installCmd.Flags().StringVar(&installArgs.UIImage, "ui-image", DefaultUiImage, "use a specified ui image")
installCmd.Flags().StringVar(&installArgs.UIBaseHref, "ui-base-href", "/", "UI base url")
installCmd.Flags().StringVar(&installArgs.UIServiceAccount, "ui-service-account", "", "use a specified service account for the argo-ui deployment")
installCmd.Flags().BoolVar(&installArgs.EnableWebConsole, "enable-web-console", false, "allows exec access into running step container using Argo UI")
}

// InstallFlags has all the required parameters for installing Argo.
type InstallFlags struct {
Upgrade bool // --upgrade
Expand All @@ -76,12 +58,32 @@ type InstallFlags struct {
EnableWebConsole bool // --enable-web-console
}

var installArgs InstallFlags

var installCmd = &cobra.Command{
Use: "install",
Short: "install Argo",
Run: install,
func NewInstallCommand() *cobra.Command {
var (
installArgs InstallFlags
)
var command = &cobra.Command{
Use: "install",
Short: "install Argo",
Run: func(cmd *cobra.Command, args []string) {
Install(installArgs)
},
}
command.Flags().BoolVar(&installArgs.Upgrade, "upgrade", false, "upgrade controller/ui deployments and configmap if already installed")
command.Flags().BoolVar(&installArgs.DryRun, "dry-run", false, "print the kubernetes manifests to stdout instead of installing")
command.Flags().StringVar(&installArgs.Namespace, "install-namespace", common.DefaultControllerNamespace, "install into a specific Namespace")
command.Flags().StringVar(&installArgs.InstanceID, "instanceid", "", "optional instance id to use for the controller (for multi-controller environments)")
command.Flags().StringVar(&installArgs.ConfigMap, "configmap", common.DefaultConfigMapName(common.DefaultControllerDeploymentName), "install controller using preconfigured configmap")
command.Flags().StringVar(&installArgs.ControllerName, "controller-name", common.DefaultControllerDeploymentName, "name of controller deployment")
command.Flags().StringVar(&installArgs.ControllerImage, "controller-image", DefaultControllerImage, "use a specified controller image")
command.Flags().StringVar(&installArgs.ServiceAccount, "service-account", "", "use a specified service account for the workflow-controller deployment")
command.Flags().StringVar(&installArgs.ExecutorImage, "executor-image", DefaultExecutorImage, "use a specified executor image")
command.Flags().StringVar(&installArgs.UIName, "ui-name", ArgoUIDeploymentName, "name of ui deployment")
command.Flags().StringVar(&installArgs.UIImage, "ui-image", DefaultUiImage, "use a specified ui image")
command.Flags().StringVar(&installArgs.UIBaseHref, "ui-base-href", "/", "UI base url")
command.Flags().StringVar(&installArgs.UIServiceAccount, "ui-service-account", "", "use a specified service account for the argo-ui deployment")
command.Flags().BoolVar(&installArgs.EnableWebConsole, "enable-web-console", false, "allows exec access into running step container using Argo UI")
return command
}

func printYAML(obj interface{}) {
Expand All @@ -93,7 +95,7 @@ func printYAML(obj interface{}) {
}

// Install installs the Argo controller and UI in the given Namespace
func Install(cmd *cobra.Command, args InstallFlags) {
func Install(args InstallFlags) {
clientset = initKubeClient()
if !args.DryRun {
fmt.Printf("Installing Argo %s into namespace '%s'\n", argo.GetVersion(), args.Namespace)
Expand All @@ -118,10 +120,6 @@ func Install(cmd *cobra.Command, args InstallFlags) {
installUIService(clientset, args)
}

func install(cmd *cobra.Command, args []string) {
Install(cmd, installArgs)
}

func clusterAdminExists(clientset *kubernetes.Clientset) bool {
// TODO: change this method to check if RBAC is enabled
clusterRoles := clientset.RbacV1().ClusterRoles()
Expand Down
Loading

0 comments on commit 90c08bf

Please sign in to comment.