mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
Move commands to where they should be (#1002)
* Move main to cmd/odo. * Refactor doc generation into one single command. * Rename for consistency. * Move commands to pkg/odo/cli. * Export Add*Flag functions to prepare for move. * Move validateName to pkg/odo/cli/util/validation.go. * Move functions used by only one command to the command file. * Renamed to storage_test since tests are storage-related. * Move usage template to cmdutils. * Use RootCmd() instead of var access. * Move printComponentInfo back to cmdutils and expose. * Move application to application package. * Move component to component package. Move componentShortFlag also. Not sure why it was on delete and not on component. * Move commands to appropriate packages. * Rename root to cli. * Rename main to odo. * Fix wrong reference to main file. * Fix(?) generate-coverage.sh. * Move root command name to cli.go. * Move Add*Flag functions to genericclioptions/context_flags. Move adding completion handler to package-specific functions (duplication >_<) * Move CmdUsageTemplate and PrintComponentInfo to odo/util package. * Move VERSION and getLatestReleaseInfo to cli/version package. Remove now empty cmdutils. * Start using NewCmd* instead of init. Break import cycle. :) * Rename client to cmdutils. * Move to use NewCmd* pattern for all commands. * Fix cross-compilation target.
This commit is contained in:
committed by
Suraj Narwade
parent
b21872d31d
commit
6d05c4ba9d
@@ -1,320 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/application"
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
applicationShortFlag bool
|
||||
applicationForceDeleteFlag bool
|
||||
)
|
||||
|
||||
// applicationCmd represents the app command
|
||||
var applicationCmd = &cobra.Command{
|
||||
Use: "app",
|
||||
Short: "Perform application operations",
|
||||
Long: `Performs application operations related to your OpenShift project.`,
|
||||
Example: fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s",
|
||||
applicationCreateCmd.Example,
|
||||
applicationGetCmd.Example,
|
||||
applicationDeleteCmd.Example,
|
||||
applicationDescribeCmd.Example,
|
||||
applicationListCmd.Example,
|
||||
applicationSetCmd.Example),
|
||||
Aliases: []string{"application"},
|
||||
// 'odo app' is the same as 'odo app get'
|
||||
// 'odo app <application_name>' is the same as 'odo app set <application_name>'
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) > 0 && args[0] != "get" && args[0] != "set" {
|
||||
applicationSetCmd.Run(cmd, args)
|
||||
} else {
|
||||
applicationGetCmd.Run(cmd, args)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var applicationCreateCmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Create an application",
|
||||
Long: `Create an application.
|
||||
If no app name is passed, a default app name will be auto-generated.
|
||||
`,
|
||||
Example: ` # Create an application
|
||||
odo app create myapp
|
||||
odo app create
|
||||
`,
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
projectName := context.Project
|
||||
|
||||
var appName string
|
||||
if len(args) == 1 {
|
||||
// The only arg passed is the app name
|
||||
appName = args[0]
|
||||
} else {
|
||||
// Desired app name is not passed so, generate a new app name
|
||||
// Fetch existing list of apps
|
||||
apps, err := application.List(client)
|
||||
util.CheckError(err, "")
|
||||
|
||||
// Generate a random name that's not already in use for the existing apps
|
||||
appName, err = application.GetDefaultAppName(apps)
|
||||
util.CheckError(err, "")
|
||||
}
|
||||
// validate application name
|
||||
err := validateName(appName)
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf("Creating application: %v in project: %v\n", appName, projectName)
|
||||
err = application.Create(client, appName)
|
||||
util.CheckError(err, "")
|
||||
err = application.SetCurrent(client, appName)
|
||||
|
||||
// TODO: updating the app name should be done via SetCurrent and passing the Context
|
||||
// not strictly needed here but Context should stay in sync
|
||||
context.Application = appName
|
||||
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf("Switched to application: %v in project: %v\n", appName, projectName)
|
||||
},
|
||||
}
|
||||
|
||||
var applicationGetCmd = &cobra.Command{
|
||||
Use: "get",
|
||||
Short: "Get the active application",
|
||||
Long: "Get the active application",
|
||||
Example: ` # Get the currently active application
|
||||
odo app get
|
||||
`,
|
||||
Args: cobra.ExactArgs(0),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
projectName := context.Project
|
||||
app := context.Application
|
||||
if applicationShortFlag {
|
||||
fmt.Print(app)
|
||||
return
|
||||
}
|
||||
if app == "" {
|
||||
fmt.Printf("There's no active application.\nYou can create one by running 'odo application create <name>'.\n")
|
||||
return
|
||||
}
|
||||
fmt.Printf("The current application is: %v in project: %v\n", app, projectName)
|
||||
},
|
||||
}
|
||||
|
||||
var applicationDeleteCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Short: "Delete the given application",
|
||||
Long: "Delete the given application",
|
||||
Example: ` # Delete the application
|
||||
odo app delete myapp
|
||||
`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
projectName := context.Project
|
||||
appName := context.Application
|
||||
if len(args) == 1 {
|
||||
// If app name passed, consider it for deletion
|
||||
appName = args[0]
|
||||
}
|
||||
|
||||
var confirmDeletion string
|
||||
|
||||
// Print App Information which will be deleted
|
||||
err := printDeleteAppInfo(client, appName)
|
||||
util.CheckError(err, "")
|
||||
exists, err := application.Exists(client, appName)
|
||||
util.CheckError(err, "")
|
||||
if !exists {
|
||||
fmt.Printf("Application %v in project %v does not exist\n", appName, projectName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if applicationForceDeleteFlag {
|
||||
confirmDeletion = "y"
|
||||
} else {
|
||||
fmt.Printf("Are you sure you want to delete the application: %v from project: %v? [y/N] ", appName, projectName)
|
||||
fmt.Scanln(&confirmDeletion)
|
||||
}
|
||||
|
||||
if strings.ToLower(confirmDeletion) == "y" {
|
||||
err := application.Delete(client, appName)
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf("Deleted application: %s from project: %v\n", appName, projectName)
|
||||
} else {
|
||||
fmt.Printf("Aborting deletion of application: %v\n", appName)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var applicationListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List all applications in the current project",
|
||||
Long: "List all applications in the current project.",
|
||||
Example: ` # List all applications in the current project
|
||||
odo app list
|
||||
|
||||
# List all applications in the specified project
|
||||
odo app list --project myproject
|
||||
`,
|
||||
Args: cobra.ExactArgs(0),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
projectName := context.Project
|
||||
|
||||
apps, err := application.ListInProject(client)
|
||||
util.CheckError(err, "unable to get list of applications")
|
||||
if len(apps) > 0 {
|
||||
fmt.Printf("The project '%v' has the following applications:\n", projectName)
|
||||
tabWriter := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent)
|
||||
fmt.Fprintln(tabWriter, "ACTIVE", "\t", "NAME")
|
||||
for _, app := range apps {
|
||||
activeMark := " "
|
||||
if app.Active {
|
||||
activeMark = "*"
|
||||
}
|
||||
fmt.Fprintln(tabWriter, activeMark, "\t", app.Name)
|
||||
}
|
||||
tabWriter.Flush()
|
||||
} else {
|
||||
fmt.Printf("There are no applications deployed in the project '%v'.\n", projectName)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var applicationSetCmd = &cobra.Command{
|
||||
Use: "set",
|
||||
Short: "Set application as active",
|
||||
Long: "Set application as active",
|
||||
Example: ` # Set an application as active
|
||||
odo app set myapp
|
||||
`,
|
||||
Args: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("Please provide application name")
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("Only one argument (application name) is allowed")
|
||||
}
|
||||
return nil
|
||||
}, Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
projectName := context.Project
|
||||
|
||||
// error if application does not exist
|
||||
appName := args[0]
|
||||
exists, err := application.Exists(client, appName)
|
||||
util.CheckError(err, "unable to check if application exists")
|
||||
if !exists {
|
||||
fmt.Printf("Application %v does not exist\n", appName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = application.SetCurrent(client, appName)
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf("Switched to application: %v in project: %v\n", args[0], projectName)
|
||||
|
||||
// TODO: updating the app name should be done via SetCurrent and passing the Context
|
||||
// not strictly needed here but Context should stay in sync
|
||||
context.Application = appName
|
||||
},
|
||||
}
|
||||
|
||||
var applicationDescribeCmd = &cobra.Command{
|
||||
Use: "describe [application_name]",
|
||||
Short: "Describe the given application",
|
||||
Long: "Describe the given application",
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Example: ` # Describe webapp application,
|
||||
odo app describe webapp
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
projectName := context.Project
|
||||
|
||||
appName := context.Application
|
||||
if len(args) == 0 {
|
||||
if appName == "" {
|
||||
fmt.Printf("There's no active application in project: %v\n", projectName)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
appName = args[0]
|
||||
//Check whether application exist or not
|
||||
exists, err := application.Exists(client, appName)
|
||||
util.CheckError(err, "")
|
||||
if !exists {
|
||||
fmt.Printf("Application with the name %s does not exist in %s \n", appName, projectName)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// List of Component
|
||||
componentList, err := component.List(client, appName)
|
||||
util.CheckError(err, "")
|
||||
if len(componentList) == 0 {
|
||||
fmt.Printf("Application %s has no components deployed.\n", appName)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Application %s has:\n", appName)
|
||||
|
||||
for _, currentComponent := range componentList {
|
||||
componentType, path, componentURL, appStore, err := component.GetComponentDesc(client, currentComponent.Name, appName)
|
||||
util.CheckError(err, "")
|
||||
printComponentInfo(currentComponent.Name, componentType, path, componentURL, appStore)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
applicationDeleteCmd.Flags().BoolVarP(&applicationForceDeleteFlag, "force", "f", false, "Delete application without prompting")
|
||||
|
||||
applicationGetCmd.Flags().BoolVarP(&applicationShortFlag, "short", "q", false, "If true, display only the application name")
|
||||
// add flags from 'get' to application command
|
||||
applicationCmd.Flags().AddFlagSet(applicationGetCmd.Flags())
|
||||
|
||||
applicationCmd.AddCommand(applicationListCmd)
|
||||
applicationCmd.AddCommand(applicationDeleteCmd)
|
||||
applicationCmd.AddCommand(applicationGetCmd)
|
||||
applicationCmd.AddCommand(applicationCreateCmd)
|
||||
applicationCmd.AddCommand(applicationSetCmd)
|
||||
applicationCmd.AddCommand(applicationDescribeCmd)
|
||||
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(applicationListCmd)
|
||||
addProjectFlag(applicationCreateCmd)
|
||||
addProjectFlag(applicationDeleteCmd)
|
||||
addProjectFlag(applicationDescribeCmd)
|
||||
addProjectFlag(applicationSetCmd)
|
||||
addProjectFlag(applicationGetCmd)
|
||||
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
applicationCmd.Annotations = map[string]string{"command": "other"}
|
||||
applicationCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
rootCmd.AddCommand(applicationCmd)
|
||||
|
||||
completion.RegisterCommandHandler(applicationDescribeCmd, completion.AppCompletionHandler)
|
||||
completion.RegisterCommandHandler(applicationDeleteCmd, completion.AppCompletionHandler)
|
||||
completion.RegisterCommandHandler(applicationSetCmd, completion.AppCompletionHandler)
|
||||
|
||||
}
|
||||
303
cmd/catalog.go
303
cmd/catalog.go
@@ -1,303 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/catalog"
|
||||
svc "github.com/redhat-developer/odo/pkg/service"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var catalogCmd = &cobra.Command{
|
||||
Use: "catalog [options]",
|
||||
Short: "Catalog related operations",
|
||||
Long: "Catalog related operations",
|
||||
Example: fmt.Sprintf("%s\n%s\n%s",
|
||||
catalogListCmd.Example,
|
||||
catalogSearchCmd.Example,
|
||||
catalogDescribeCmd.Example),
|
||||
}
|
||||
|
||||
var catalogListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List all available component & service types.",
|
||||
Long: "List all available component and service types from OpenShift",
|
||||
Example: ` # Get the supported components
|
||||
odo catalog list components
|
||||
|
||||
# Get the supported services from service catalog
|
||||
odo catalog list services
|
||||
`,
|
||||
}
|
||||
|
||||
var catalogListComponentCmd = &cobra.Command{
|
||||
Use: "components",
|
||||
Short: "List all components available.",
|
||||
Long: "List all available component types from OpenShift's Image Builder.",
|
||||
Example: ` # Get the supported components
|
||||
odo catalog list components
|
||||
|
||||
# Search for a supported component
|
||||
odo catalog search component nodejs
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client := genericclioptions.Client(cmd)
|
||||
catalogList, err := catalog.List(client)
|
||||
util.CheckError(err, "unable to list components")
|
||||
switch len(catalogList) {
|
||||
case 0:
|
||||
fmt.Printf("No deployable components found\n")
|
||||
default:
|
||||
currentProject := client.GetCurrentProjectName()
|
||||
w := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent)
|
||||
fmt.Fprintln(w, "NAME", "\t", "PROJECT", "\t", "TAGS")
|
||||
for _, component := range catalogList {
|
||||
componentName := component.Name
|
||||
if component.Namespace == currentProject {
|
||||
/*
|
||||
If current namespace is same as the current component namespace,
|
||||
Loop through every other component,
|
||||
If there exists a component with same name but in different namespaces,
|
||||
mark the one from current namespace with (*)
|
||||
*/
|
||||
for _, comp := range catalogList {
|
||||
if comp.Name == component.Name && component.Namespace != comp.Namespace {
|
||||
componentName = fmt.Sprintf("%s (*)", component.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(w, componentName, "\t", component.Namespace, "\t", strings.Join(component.Tags, ","))
|
||||
}
|
||||
w.Flush()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var catalogListServiceCmd = &cobra.Command{
|
||||
Use: "services",
|
||||
Short: "Lists all available services",
|
||||
Long: "Lists all available services",
|
||||
Example: ` # List all services
|
||||
odo catalog list services
|
||||
|
||||
# Search for a supported service
|
||||
odo catalog search service mysql
|
||||
`,
|
||||
Args: cobra.ExactArgs(0),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client := genericclioptions.Client(cmd)
|
||||
catalogList, err := svc.ListCatalog(client)
|
||||
util.CheckError(err, "unable to list services because Service Catalog is not enabled in your cluster")
|
||||
switch len(catalogList) {
|
||||
case 0:
|
||||
fmt.Printf("No deployable services found\n")
|
||||
default:
|
||||
w := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent)
|
||||
fmt.Fprintln(w, "NAME", "\t", "PLANS")
|
||||
for _, service := range catalogList {
|
||||
fmt.Fprintln(w, service.Name, "\t", strings.Join(service.PlanList, ","))
|
||||
}
|
||||
w.Flush()
|
||||
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var catalogSearchCmd = &cobra.Command{
|
||||
Use: "search",
|
||||
Short: "Search available component & service types.",
|
||||
Long: `Search available component & service types..
|
||||
|
||||
This searches for a partial match for the given search term in all the available
|
||||
components & services.
|
||||
`,
|
||||
Example: ` # Search for a component
|
||||
odo catalog search component python
|
||||
|
||||
# Search for a service
|
||||
odo catalog search service mysql
|
||||
`,
|
||||
}
|
||||
|
||||
var catalogSearchComponentCmd = &cobra.Command{
|
||||
Use: "component",
|
||||
Short: "Search component type in catalog",
|
||||
Long: `Search component type in catalog.
|
||||
|
||||
This searches for a partial match for the given search term in all the available
|
||||
components.
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Example: ` # Search for a component
|
||||
odo catalog search component python
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client := genericclioptions.Client(cmd)
|
||||
searchTerm := args[0]
|
||||
components, err := catalog.Search(client, searchTerm)
|
||||
util.CheckError(err, "unable to search for components")
|
||||
|
||||
switch len(components) {
|
||||
case 0:
|
||||
fmt.Printf("No component matched the query: %v\n", searchTerm)
|
||||
default:
|
||||
fmt.Println("The following components were found:")
|
||||
for _, component := range components {
|
||||
fmt.Printf("- %v\n", component)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var catalogSearchServiceCmd = &cobra.Command{
|
||||
Use: "service",
|
||||
Short: "Search service type in catalog",
|
||||
Long: `Search service type in catalog.
|
||||
|
||||
This searches for a partial match for the given search term in all the available
|
||||
services from service catalog.
|
||||
`,
|
||||
Example: ` # Search for a service
|
||||
odo catalog search service mysql
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client := genericclioptions.Client(cmd)
|
||||
searchTerm := args[0]
|
||||
components, err := svc.Search(client, searchTerm)
|
||||
util.CheckError(err, "unable to search for services")
|
||||
|
||||
switch len(components) {
|
||||
case 0:
|
||||
fmt.Printf("No service matched the query: %v\n", searchTerm)
|
||||
default:
|
||||
w := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent)
|
||||
fmt.Fprintln(w, "NAME", "\t", "PLANS")
|
||||
for _, component := range components {
|
||||
fmt.Fprintln(w, component.Name, "\t", strings.Join(component.PlanList, ","))
|
||||
}
|
||||
w.Flush()
|
||||
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var catalogDescribeCmd = &cobra.Command{
|
||||
Use: "describe",
|
||||
Short: "Describe catalog item",
|
||||
Long: "Describe the given catalog item from OpenShift",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Example: ` # Describe the given service
|
||||
odo catalog describe service mysql-persistent
|
||||
`,
|
||||
}
|
||||
|
||||
var catalogDescribeServiceCmd = &cobra.Command{
|
||||
Use: "service",
|
||||
Short: "Describe a service",
|
||||
Long: `Describe a service type.
|
||||
|
||||
This describes the service and the associated plans.
|
||||
`,
|
||||
Example: ` # Describe a service
|
||||
odo catalog describe service mysql-persistent
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client := genericclioptions.Client(cmd)
|
||||
serviceName := args[0]
|
||||
service, plans, err := svc.GetServiceClassAndPlans(client, serviceName)
|
||||
util.CheckError(err, "")
|
||||
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetBorder(false)
|
||||
table.SetAlignment(tablewriter.ALIGN_LEFT)
|
||||
|
||||
serviceData := [][]string{
|
||||
{"Name", service.Name},
|
||||
{"Bindable", fmt.Sprint(service.Bindable)},
|
||||
{"Operated by the broker", service.ServiceBrokerName},
|
||||
{"Short Description", service.ShortDescription},
|
||||
{"Long Description", service.LongDescription},
|
||||
{"Versions Available", strings.Join(service.VersionsAvailable, ",")},
|
||||
{"Tags", strings.Join(service.Tags, ",")},
|
||||
}
|
||||
|
||||
table.AppendBulk(serviceData)
|
||||
|
||||
table.Append([]string{""})
|
||||
|
||||
if len(plans) > 0 {
|
||||
table.Append([]string{"PLANS"})
|
||||
|
||||
for _, plan := range plans {
|
||||
|
||||
// create the display values for required and optional parameters
|
||||
requiredWithMandatoryUserInputParameterNames := []string{}
|
||||
requiredWithOptionalUserInputParameterNames := []string{}
|
||||
optionalParameterDisplay := []string{}
|
||||
for _, parameter := range plan.Parameters {
|
||||
if parameter.Required {
|
||||
// until we have a better solution for displaying the plan data (like a separate table perhaps)
|
||||
// this is simplest thing to do
|
||||
if parameter.HasDefaultValue {
|
||||
defaultValueStr := fmt.Sprintf("%v", parameter.DefaultValue)
|
||||
requiredWithOptionalUserInputParameterNames = append(
|
||||
requiredWithOptionalUserInputParameterNames,
|
||||
fmt.Sprintf("%s (default: '%s')", parameter.Name, defaultValueStr))
|
||||
} else {
|
||||
requiredWithMandatoryUserInputParameterNames = append(requiredWithMandatoryUserInputParameterNames, parameter.Name)
|
||||
}
|
||||
|
||||
} else {
|
||||
optionalParameterDisplay = append(optionalParameterDisplay, parameter.Name)
|
||||
}
|
||||
}
|
||||
|
||||
table.Append([]string{"***********************", "*****************************************************"})
|
||||
planLineSeparator := []string{"-----------------", "-----------------"}
|
||||
|
||||
planData := [][]string{
|
||||
{"Name", plan.Name},
|
||||
planLineSeparator,
|
||||
{"Display Name", plan.DisplayName},
|
||||
planLineSeparator,
|
||||
{"Short Description", plan.Description},
|
||||
planLineSeparator,
|
||||
{"Required Params without a default value", strings.Join(requiredWithMandatoryUserInputParameterNames, ", ")},
|
||||
planLineSeparator,
|
||||
{"Required Params with a default value", strings.Join(requiredWithOptionalUserInputParameterNames, ", ")},
|
||||
planLineSeparator,
|
||||
{"Optional Params", strings.Join(optionalParameterDisplay, ", ")},
|
||||
{"", ""},
|
||||
}
|
||||
table.AppendBulk(planData)
|
||||
}
|
||||
table.Render()
|
||||
} else {
|
||||
fmt.Printf("No plans found for service %s\n", serviceName)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
catalogCmd.AddCommand(catalogSearchCmd)
|
||||
catalogCmd.AddCommand(catalogListCmd)
|
||||
catalogCmd.AddCommand(catalogDescribeCmd)
|
||||
catalogListCmd.AddCommand(catalogListComponentCmd)
|
||||
catalogListCmd.AddCommand(catalogListServiceCmd)
|
||||
catalogSearchCmd.AddCommand(catalogSearchComponentCmd)
|
||||
catalogSearchCmd.AddCommand(catalogSearchServiceCmd)
|
||||
catalogDescribeCmd.AddCommand(catalogDescribeServiceCmd)
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
catalogCmd.Annotations = map[string]string{"command": "other"}
|
||||
catalogCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
rootCmd.AddCommand(catalogCmd)
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
package cmd
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cli"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"os"
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -86,11 +89,74 @@ func referencePrinter(command *cobra.Command, level int) string {
|
||||
"```sh\n"+command.Example+"\n```",
|
||||
command.Long,
|
||||
tableOutput.String(),
|
||||
"```sh\n"+GenerateCLIStructure()+"\n```",
|
||||
"```sh\n"+fmt.Sprint(commandPrinter(command, 0))+"\n```",
|
||||
commandOutput)
|
||||
}
|
||||
|
||||
// Generates and returns a markdown-formatted CLI reference page for Odo
|
||||
func GenerateCLIReference() string {
|
||||
return referencePrinter(rootCmd, 0)
|
||||
func getFlags(flags *pflag.FlagSet) []string {
|
||||
var f []string
|
||||
flags.VisitAll(func(flag *pflag.Flag) {
|
||||
f = append(f, fmt.Sprintf("--%v", flag.Name))
|
||||
})
|
||||
return f
|
||||
}
|
||||
|
||||
func flattenFlags(flags []string) string {
|
||||
var flagString string
|
||||
for _, flag := range flags {
|
||||
flagString = flagString + flag + " "
|
||||
}
|
||||
return flagString
|
||||
}
|
||||
|
||||
func commandPrinter(command *cobra.Command, level int) string {
|
||||
var finalCommand string
|
||||
// add indentation
|
||||
for i := 0; i < level; i++ {
|
||||
finalCommand = finalCommand + " "
|
||||
}
|
||||
finalCommand = finalCommand +
|
||||
command.Name() +
|
||||
" " +
|
||||
flattenFlags(getFlags(command.NonInheritedFlags())) +
|
||||
": " +
|
||||
command.Short +
|
||||
"\n"
|
||||
for _, subcommand := range command.Commands() {
|
||||
finalCommand = finalCommand + commandPrinter(subcommand, level+1)
|
||||
}
|
||||
return finalCommand
|
||||
}
|
||||
|
||||
// Generates and returns a markdown-formatted CLI reference page for Odo
|
||||
func main() {
|
||||
var clidoc = &cobra.Command{
|
||||
Use: "cli-doc",
|
||||
Short: "Generate CLI reference for Odo",
|
||||
|
||||
Example: ` # Generate a markdown-formatted CLI reference page for Odo
|
||||
cli-doc reference > docs/cli-reference.md
|
||||
|
||||
# Generate the CLI structure
|
||||
cli-doc structure`,
|
||||
Args: cobra.OnlyValidArgs,
|
||||
ValidArgs: []string{"help", "reference", "structure"},
|
||||
|
||||
Run: func(command *cobra.Command, args []string) {
|
||||
switch args[0] {
|
||||
case "reference":
|
||||
fmt.Print(referencePrinter(cli.RootCmd(), 0))
|
||||
case "structure":
|
||||
fmt.Print(commandPrinter(cli.RootCmd(), 0))
|
||||
default:
|
||||
fmt.Print(command.Usage())
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
err := clidoc.Execute()
|
||||
if err != nil {
|
||||
fmt.Println(errors.Cause(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func getFlags(flags *pflag.FlagSet) []string {
|
||||
var f []string
|
||||
flags.VisitAll(func(flag *pflag.Flag) {
|
||||
f = append(f, fmt.Sprintf("--%v", flag.Name))
|
||||
})
|
||||
return f
|
||||
}
|
||||
|
||||
func flattenFlags(flags []string) string {
|
||||
var flagString string
|
||||
for _, flag := range flags {
|
||||
flagString = flagString + flag + " "
|
||||
}
|
||||
return flagString
|
||||
}
|
||||
|
||||
func commandPrinter(command *cobra.Command, level int) string {
|
||||
var finalCommand string
|
||||
// add indentation
|
||||
for i := 0; i < level; i++ {
|
||||
finalCommand = finalCommand + " "
|
||||
}
|
||||
finalCommand = finalCommand +
|
||||
command.Name() +
|
||||
" " +
|
||||
flattenFlags(getFlags(command.NonInheritedFlags())) +
|
||||
": " +
|
||||
command.Short +
|
||||
"\n"
|
||||
for _, subcommand := range command.Commands() {
|
||||
finalCommand = finalCommand + commandPrinter(subcommand, level+1)
|
||||
}
|
||||
return finalCommand
|
||||
}
|
||||
|
||||
func GenerateCLIStructure() string {
|
||||
return commandPrinter(rootCmd, 0)
|
||||
}
|
||||
164
cmd/cmdutils.go
164
cmd/cmdutils.go
@@ -1,164 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/pkg/occlient"
|
||||
"github.com/redhat-developer/odo/pkg/storage"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
)
|
||||
|
||||
// printDeleteAppInfo will print things which will be deleted
|
||||
func printDeleteAppInfo(client *occlient.Client, appName string) error {
|
||||
componentList, err := component.List(client, appName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get Component list")
|
||||
}
|
||||
|
||||
for _, currentComponent := range componentList {
|
||||
_, _, componentURL, appStore, err := component.GetComponentDesc(client, currentComponent.Name, appName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to get component description")
|
||||
}
|
||||
fmt.Println("Component", currentComponent.Name, "will be deleted.")
|
||||
|
||||
if len(componentURL) != 0 {
|
||||
fmt.Println(" Externally exposed URL will be removed")
|
||||
}
|
||||
|
||||
for _, store := range appStore {
|
||||
fmt.Println(" Storage", store.Name, "of size", store.Size, "will be removed")
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// printComponentInfo prints Component Information like path, URL & storage
|
||||
func printComponentInfo(currentComponentName string, componentType string, path string, componentURL string, appStore []storage.StorageInfo) {
|
||||
// Source
|
||||
if path != "" {
|
||||
fmt.Println("Component", currentComponentName, "of type", componentType, "with source in", path)
|
||||
}
|
||||
// URL
|
||||
if componentURL != "" {
|
||||
fmt.Println("Externally exposed via", componentURL)
|
||||
}
|
||||
// Storage
|
||||
for _, store := range appStore {
|
||||
fmt.Println("Storage", store.Name, "of size", store.Size)
|
||||
}
|
||||
}
|
||||
|
||||
// validateName will do validation of application & component names
|
||||
// Criteria for valid name in kubernetes: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/
|
||||
func validateName(name string) error {
|
||||
|
||||
errorList := validation.IsDNS1123Label(name)
|
||||
|
||||
if len(errorList) != 0 {
|
||||
return errors.New(fmt.Sprintf("%s is not a valid name: %s", name, strings.Join(errorList, " ")))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// validateStoragePath will validate storagePath, if there is any existing storage with similar path, it will give an error
|
||||
func validateStoragePath(client *occlient.Client, storagePath, componentName, applicationName string) error {
|
||||
storeList, err := storage.List(client, componentName, applicationName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, store := range storeList {
|
||||
if store.Path == storagePath {
|
||||
return errors.Errorf("there already is a storage mounted at %s", storagePath)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// printMountedStorageInComponent prints all the mounted storage in a given component of the application
|
||||
func printMountedStorageInComponent(client *occlient.Client, componentName string, applicationName string) {
|
||||
|
||||
// defining the column structure of the table
|
||||
tabWriterMounted := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent)
|
||||
|
||||
// create headers of mounted storage table
|
||||
fmt.Fprintln(tabWriterMounted, "NAME", "\t", "SIZE", "\t", "PATH")
|
||||
|
||||
storageListMounted, err := storage.ListMounted(client, componentName, applicationName)
|
||||
util.CheckError(err, "could not get mounted storage list")
|
||||
|
||||
// iterating over all mounted storage and put in the mount storage table
|
||||
if len(storageListMounted) > 0 {
|
||||
for _, mStorage := range storageListMounted {
|
||||
fmt.Fprintln(tabWriterMounted, mStorage.Name, "\t", mStorage.Size, "\t", mStorage.Path)
|
||||
}
|
||||
|
||||
// print all mounted storage of the given component
|
||||
fmt.Printf("The component '%v' has the following storage attached:\n", componentName)
|
||||
tabWriterMounted.Flush()
|
||||
} else {
|
||||
fmt.Printf("The component '%v' has no storage attached\n", componentName)
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
|
||||
// printMountedStorageInAllComponent prints all the mounted storage in all the components of the application and project
|
||||
func printMountedStorageInAllComponent(client *occlient.Client, applicationName string) {
|
||||
componentList, err := component.List(client, applicationName)
|
||||
util.CheckError(err, "could not get component list")
|
||||
|
||||
// iterating over all the components in the given aplication and project
|
||||
for _, component := range componentList {
|
||||
printMountedStorageInComponent(client, component.Name, applicationName)
|
||||
}
|
||||
}
|
||||
|
||||
// printUnmountedStorage prints all the unmounted storage in the application
|
||||
func printUnmountedStorage(client *occlient.Client, applicationName string) {
|
||||
|
||||
// defining the column structure of the unmounted storage table
|
||||
tabWriterUnmounted := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent)
|
||||
|
||||
// create header of unmounted storage in all the components of the given application and project
|
||||
fmt.Fprintln(tabWriterUnmounted, "NAME", "\t", "SIZE")
|
||||
|
||||
storageListUnmounted, err := storage.ListUnmounted(client, applicationName)
|
||||
util.CheckError(err, "could not get unmounted storage list")
|
||||
|
||||
// iterating over all unmounted storage and put in the unmount storage table
|
||||
if len(storageListUnmounted) > 0 {
|
||||
for _, uStorage := range storageListUnmounted {
|
||||
fmt.Fprintln(tabWriterUnmounted, uStorage.Name, "\t", uStorage.Size)
|
||||
}
|
||||
|
||||
// print unmounted storage of all the application
|
||||
fmt.Printf("Storage that are not mounted to any component:\n")
|
||||
tabWriterUnmounted.Flush()
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
|
||||
func addProjectFlag(cmd *cobra.Command) {
|
||||
cmd.Flags().String(util.ProjectFlagName, "", "Project, defaults to active project")
|
||||
completion.RegisterCommandFlagHandler(cmd, "project", completion.ProjectNameCompletionHandler)
|
||||
}
|
||||
|
||||
func addComponentFlag(cmd *cobra.Command) {
|
||||
cmd.Flags().String(util.ComponentFlagName, "", "Component, defaults to active component.")
|
||||
}
|
||||
|
||||
func addApplicationFlag(cmd *cobra.Command) {
|
||||
cmd.Flags().String(util.ApplicationFlagName, "", "Application, defaults to active application")
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
appsv1 "github.com/openshift/api/apps/v1"
|
||||
"github.com/redhat-developer/odo/pkg/occlient"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ktesting "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
func Test_validateName(t *testing.T) {
|
||||
tests := []struct {
|
||||
testCase string
|
||||
name string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
testCase: "Test case - 1",
|
||||
name: "app",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
testCase: "Test case - 2",
|
||||
name: "app123",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
testCase: "Test case - 3",
|
||||
name: "app-123",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
testCase: "Test case - 4",
|
||||
name: "app.123",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
testCase: "Test case - 5",
|
||||
name: "app_123",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
testCase: "Test case - 6",
|
||||
name: "App",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
testCase: "Test case - 7",
|
||||
name: "b7pdkva7ynxf8qoyuh02tbgu2ufcy4jq7udyom7it0g8gouc39x3gy0p1wrsbt6",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
testCase: "Test case - 8",
|
||||
name: "b7pdkva7ynxf8qoyuh02tbgu2ufcy4jq7udyom7it0g8gouc39x3gy0p1wrsbt6p",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Log("Running test", tt.testCase)
|
||||
t.Run(tt.testCase, func(t *testing.T) {
|
||||
if err := validateName(tt.name); (err != nil) != tt.wantErr {
|
||||
t.Errorf("Expected error = %v, But got = %v", tt.wantErr, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_validateStoragePath(t *testing.T) {
|
||||
|
||||
type args struct {
|
||||
storagePath, componentName, applicationName string
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Test Case 1",
|
||||
args: args{
|
||||
storagePath: "/opt/app-root/src/storage/",
|
||||
componentName: "nodejs",
|
||||
applicationName: "app",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
||||
{
|
||||
name: "Test Case 2",
|
||||
args: args{
|
||||
storagePath: "/opt/app-root/src/storage/test",
|
||||
componentName: "nodejs",
|
||||
applicationName: "app",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
pvcList := v1.PersistentVolumeClaimList{
|
||||
Items: []v1.PersistentVolumeClaim{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mystorage-app-pvc",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/component-name": "nodejs",
|
||||
"app.kubernetes.io/name": "app",
|
||||
"app.kubernetes.io/storage-name": "mystorage",
|
||||
},
|
||||
Namespace: "myproject",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
pvc := v1.PersistentVolumeClaim{
|
||||
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mystorage-app-pvc",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/component-name": "nodejs",
|
||||
"app.kubernetes.io/name": "app",
|
||||
"app.kubernetes.io/storage-name": "mystorage",
|
||||
},
|
||||
Namespace: "myproject",
|
||||
},
|
||||
}
|
||||
|
||||
listOfDC := appsv1.DeploymentConfigList{
|
||||
Items: []appsv1.DeploymentConfig{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "nodejs-app",
|
||||
Namespace: "myproject",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/component-name": "nodejs",
|
||||
"app.kubernetes.io/component-type": "nodejs",
|
||||
"app.kubernetes.io/name": "app",
|
||||
},
|
||||
},
|
||||
Spec: appsv1.DeploymentConfigSpec{
|
||||
Template: &v1.PodTemplateSpec{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
MountPath: "/opt/app-root/src/storage/",
|
||||
Name: "mystorage-app-pvc-idrcg-volume",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "mystorage-app-pvc-idrcg-volume",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
|
||||
ClaimName: "mystorage-app-pvc",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
labelSelector := "app.kubernetes.io/component-name=nodejs,app.kubernetes.io/name=app"
|
||||
storageSelector := "app.kubernetes.io/storage-name"
|
||||
client, fakeClientSet := occlient.FakeNew()
|
||||
fakeClientSet.AppsClientset.PrependReactor("list", "deploymentconfigs", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
if !reflect.DeepEqual(action.(ktesting.ListAction).GetListRestrictions().Labels.String(), labelSelector) {
|
||||
return true, nil, fmt.Errorf("labels not matching with expected values, expected:%s, got:%s", labelSelector, action.(ktesting.ListAction).GetListRestrictions())
|
||||
}
|
||||
return true, &listOfDC, nil
|
||||
})
|
||||
|
||||
fakeClientSet.Kubernetes.PrependReactor("get", "persistentvolumeclaims", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
pvcName := action.(ktesting.GetAction).GetName()
|
||||
if pvcName != pvcList.Items[0].Name {
|
||||
return true, nil, fmt.Errorf("'get' called with different pvcName")
|
||||
}
|
||||
return true, &pvc, nil
|
||||
})
|
||||
|
||||
fakeClientSet.Kubernetes.PrependReactor("list", "persistentvolumeclaims", func(action ktesting.Action) (bool, runtime.Object, error) {
|
||||
if !reflect.DeepEqual(action.(ktesting.ListAction).GetListRestrictions().Labels.String(), storageSelector) {
|
||||
return true, nil, fmt.Errorf("labels not matching with expected values, expected:%s, got:%s", storageSelector, action.(ktesting.ListAction).GetListRestrictions())
|
||||
}
|
||||
return true, &pvcList, nil
|
||||
})
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
err := validateStoragePath(client, tt.args.storagePath, tt.args.componentName, tt.args.applicationName)
|
||||
if err != nil && tt.wantErr == false {
|
||||
t.Errorf("test failed, expected error: nil, but got: %#v", err)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// componentCmd represents the component command
|
||||
var componentCmd = &cobra.Command{
|
||||
Use: "component",
|
||||
Short: "Components of application.",
|
||||
Example: fmt.Sprintf("%s\n%s",
|
||||
componentGetCmd.Example,
|
||||
componentSetCmd.Example),
|
||||
// 'odo component' is the same as 'odo component get'
|
||||
// 'odo component <component_name>' is the same as 'odo component set <component_name>'
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) > 0 && args[0] != "get" && args[0] != "set" {
|
||||
componentSetCmd.Run(cmd, args)
|
||||
} else {
|
||||
componentGetCmd.Run(cmd, args)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var componentGetCmd = &cobra.Command{
|
||||
Use: "get",
|
||||
Short: "Get currently active component",
|
||||
Long: "Get currently active component.",
|
||||
Example: ` # Get the currently active component
|
||||
odo component get
|
||||
`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
glog.V(4).Infof("component get called")
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
component := context.ComponentAllowingEmpty(true)
|
||||
|
||||
if componentShortFlag {
|
||||
fmt.Print(component)
|
||||
} else {
|
||||
if component == "" {
|
||||
fmt.Printf("No component is set as current\n")
|
||||
return
|
||||
}
|
||||
fmt.Printf("The current component is: %v\n", component)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var componentSetCmd = &cobra.Command{
|
||||
Use: "set",
|
||||
Short: "Set active component.",
|
||||
Long: "Set component as active.",
|
||||
Example: ` # Set component named 'frontend' as active
|
||||
odo set component frontend
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
projectName := context.Project
|
||||
applicationName := context.Application
|
||||
componentName := context.Component(args[0])
|
||||
|
||||
err := component.SetCurrent(componentName, applicationName, projectName)
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf("Switched to component: %v\n", componentName)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
componentGetCmd.Flags().BoolVarP(&componentShortFlag, "short", "q", false, "If true, display only the component name")
|
||||
|
||||
// add flags from 'get' to component command
|
||||
componentCmd.Flags().AddFlagSet(componentGetCmd.Flags())
|
||||
|
||||
componentCmd.AddCommand(componentGetCmd)
|
||||
componentCmd.AddCommand(componentSetCmd)
|
||||
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(componentGetCmd)
|
||||
addProjectFlag(componentSetCmd)
|
||||
//Adding `--application` flag
|
||||
addApplicationFlag(componentGetCmd)
|
||||
addApplicationFlag(componentSetCmd)
|
||||
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
componentCmd.Annotations = map[string]string{"command": "component"}
|
||||
componentCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
rootCmd.AddCommand(componentCmd)
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/redhat-developer/odo/pkg/config"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// configurationCmd represents the app command
|
||||
var configurationCmd = &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "Modifies configuration settings",
|
||||
Long: `Modifies Odo specific configuration settings within the config file.
|
||||
|
||||
Available Parameters:
|
||||
UpdateNotification - Controls if an update notification is shown or not (true or false)
|
||||
NamePrefix - Default prefix is the current directory name. Use this value to set a default name prefix
|
||||
Timeout - Timeout (in seconds) for OpenShift server connection check`,
|
||||
Example: fmt.Sprintf("%s\n%s\n",
|
||||
configurationViewCmd.Example,
|
||||
configurationSetCmd.Example),
|
||||
Aliases: []string{"configuration"},
|
||||
// 'odo utils config' is the same as 'odo utils config --help'
|
||||
Args: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) >= 1 && args[0] != "view" && args[0] != "set" {
|
||||
return fmt.Errorf(`Unknown command, use "set" or "view"`)
|
||||
}
|
||||
return nil
|
||||
}, Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) > 0 && args[0] == "set" {
|
||||
configurationSetCmd.Run(cmd, args)
|
||||
} else if len(args) > 0 && args[0] == "view" {
|
||||
configurationViewCmd.Run(cmd, args)
|
||||
} else {
|
||||
cmd.Help()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var configurationSetCmd = &cobra.Command{
|
||||
Use: "set",
|
||||
Short: "Set a value in odo config file",
|
||||
Long: `Set an individual value in the Odo configuration file
|
||||
|
||||
Available Parameters:
|
||||
UpdateNotification - Controls if an update notification is shown or not (true or false)
|
||||
NamePrefix - Default prefix is the current directory name. Use this value to set a default name prefix.
|
||||
Timeout - Timeout (in seconds) for OpenShift server connection check`,
|
||||
Example: `
|
||||
# Set a configuration value
|
||||
odo utils config set UpdateNotification false
|
||||
odo utils config set NamePrefix "app"
|
||||
odo utils config set timeout 20
|
||||
`,
|
||||
Args: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 2 {
|
||||
return fmt.Errorf("Please provide a parameter name and value")
|
||||
} else if len(args) > 2 {
|
||||
return fmt.Errorf("Only one value per parameter is allowed")
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
}, RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := config.New()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to set configuration")
|
||||
}
|
||||
return cfg.SetConfiguration(strings.ToLower(args[0]), args[1])
|
||||
},
|
||||
}
|
||||
|
||||
var configurationViewCmd = &cobra.Command{
|
||||
Use: "view",
|
||||
Short: "View current configuration values",
|
||||
Long: "View current configuration values",
|
||||
Example: ` # For viewing the current configuration
|
||||
odo utils config view
|
||||
`,
|
||||
Args: cobra.ExactArgs(0),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cfg, err := config.New()
|
||||
if err != nil {
|
||||
fmt.Println(err, ": unable to view configuration")
|
||||
}
|
||||
w := tabwriter.NewWriter(os.Stdout, 5, 2, 2, ' ', tabwriter.TabIndent)
|
||||
fmt.Fprintln(w, "PARAMETER", "\t", "CURRENT_VALUE")
|
||||
fmt.Fprintln(w, "UpdateNotification", "\t", cfg.GetUpdateNotification())
|
||||
fmt.Fprintln(w, "NamePrefix", "\t", cfg.GetNamePrefix())
|
||||
fmt.Fprintln(w, "Timeout", "\t", cfg.GetTimeout())
|
||||
w.Flush()
|
||||
},
|
||||
}
|
||||
240
cmd/create.go
240
cmd/create.go
@@ -1,240 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
odoutil "github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/golang/glog"
|
||||
"github.com/redhat-developer/odo/pkg/application"
|
||||
"github.com/redhat-developer/odo/pkg/catalog"
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
componentBinary string
|
||||
componentGit string
|
||||
componentLocal string
|
||||
componentPorts []string
|
||||
componentEnvVars []string
|
||||
)
|
||||
|
||||
var componentCreateCmd = &cobra.Command{
|
||||
Use: "create <component_type> [component_name] [flags]",
|
||||
Short: "Create a new component",
|
||||
Long: `Create a new component to deploy on OpenShift.
|
||||
|
||||
If a component name is not provided, it'll be auto-generated.
|
||||
|
||||
By default, builder images will be used from the current namespace. You can explicitly supply a namespace by using: odo create namespace/name:version
|
||||
If version is not specified by default, latest wil be chosen as the version.
|
||||
|
||||
A full list of component types that can be deployed is available using: 'odo catalog list'`,
|
||||
Example: ` # Create new Node.js component with the source in current directory.
|
||||
odo create nodejs
|
||||
|
||||
# A specific image version may also be specified
|
||||
odo create nodejs:latest
|
||||
|
||||
# Create new Node.js component named 'frontend' with the source in './frontend' directory
|
||||
odo create nodejs frontend --local ./frontend
|
||||
|
||||
# Create new Node.js component with source from remote git repository.
|
||||
odo create nodejs --git https://github.com/openshift/nodejs-ex.git
|
||||
|
||||
# Create a new Node.js component of version 6 from the 'openshift' namespace
|
||||
odo create openshift/nodejs:6 --local /nodejs-ex
|
||||
|
||||
# Create new Wildfly component with binary named sample.war in './downloads' directory
|
||||
odo create wildfly wildly --binary ./downloads/sample.war
|
||||
|
||||
# Create new Node.js component with the source in current directory and ports 8080-tcp,8100-tcp and 9100-udp exposed
|
||||
odo create nodejs --port 8080,8100/tcp,9100/udp
|
||||
|
||||
# Create new Node.js component with the source in current directory and env variables key=value and key1=value1 exposed
|
||||
odo create nodejs --env key=value,key1=value1
|
||||
|
||||
# For more examples, visit: https://github.com/redhat-developer/odo/blob/master/docs/examples.md
|
||||
odo create python --git https://github.com/openshift/django-ex.git
|
||||
`,
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
stdout := color.Output
|
||||
glog.V(4).Infof("Component create called with args: %#v, flags: binary=%s, git=%s, local=%s", strings.Join(args, " "), componentBinary, componentGit, componentLocal)
|
||||
|
||||
context := genericclioptions.NewContextCreatingAppIfNeeded(cmd)
|
||||
client := context.Client
|
||||
projectName := context.Project
|
||||
applicationName := context.Application
|
||||
|
||||
checkFlag := 0
|
||||
componentPath := ""
|
||||
var componentPathType component.CreateType
|
||||
|
||||
if len(componentBinary) != 0 {
|
||||
componentPath = componentBinary
|
||||
componentPathType = component.BINARY
|
||||
checkFlag++
|
||||
}
|
||||
if len(componentGit) != 0 {
|
||||
componentPath = componentGit
|
||||
componentPathType = component.GIT
|
||||
checkFlag++
|
||||
}
|
||||
if len(componentLocal) != 0 {
|
||||
componentPath = componentLocal
|
||||
componentPathType = component.SOURCE
|
||||
checkFlag++
|
||||
}
|
||||
|
||||
if checkFlag > 1 {
|
||||
fmt.Println("The source can be either --binary or --local or --git")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
componentImageName, componentType, _, componentVersion := util.ParseCreateCmdArgs(args)
|
||||
|
||||
// Fetch list of existing components in-order to attempt generation of unique component name
|
||||
componentList, err := component.List(client, applicationName)
|
||||
odoutil.CheckError(err, "")
|
||||
|
||||
// Generate unique name for component
|
||||
componentName, err := component.GetDefaultComponentName(
|
||||
componentPath,
|
||||
componentPathType,
|
||||
componentType,
|
||||
componentList,
|
||||
)
|
||||
odoutil.CheckError(err, "")
|
||||
|
||||
// Check to see if the catalog type actually exists
|
||||
exists, err := catalog.Exists(client, componentType)
|
||||
odoutil.CheckError(err, "")
|
||||
if !exists {
|
||||
fmt.Printf("Invalid component type: %v\nRun 'odo catalog list components' to see a list of supported component types\n", componentType)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Check to see if that particular version exists
|
||||
versionExists, err := catalog.VersionExists(client, componentType, componentVersion)
|
||||
odoutil.CheckError(err, "")
|
||||
if !versionExists {
|
||||
fmt.Printf("Invalid component version: %v\nRun 'odo catalog list components' to see a list of supported component type versions\n", componentVersion)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Retrieve the componentName, if the componentName isn't specified, we will use the default image name
|
||||
if len(args) == 2 {
|
||||
componentName = args[1]
|
||||
}
|
||||
|
||||
// Validate component name
|
||||
err = validateName(componentName)
|
||||
odoutil.CheckError(err, "")
|
||||
exists, err = component.Exists(client, componentName, applicationName)
|
||||
odoutil.CheckError(err, "")
|
||||
if exists {
|
||||
fmt.Printf("component with the name %s already exists in the current application\n", componentName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Deploy the component with Git
|
||||
if len(componentGit) != 0 {
|
||||
|
||||
// Use Git
|
||||
err := component.CreateFromGit(client, componentName, componentImageName, componentGit, applicationName, componentPorts, componentEnvVars)
|
||||
odoutil.CheckError(err, "")
|
||||
fmt.Printf("Triggering build from %s.\n\n", componentGit)
|
||||
|
||||
// Git is the only one using BuildConfig since we need to retrieve the git
|
||||
err = component.Build(client, componentName, applicationName, true, true, stdout)
|
||||
odoutil.CheckError(err, "")
|
||||
|
||||
} else if len(componentLocal) != 0 {
|
||||
|
||||
// Use the absolute path for the component
|
||||
dir, err := filepath.Abs(componentLocal)
|
||||
odoutil.CheckError(err, "")
|
||||
fileInfo, err := os.Stat(dir)
|
||||
odoutil.CheckError(err, "")
|
||||
if !fileInfo.IsDir() {
|
||||
fmt.Println("Please provide a path to the directory")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Create
|
||||
err = component.CreateFromPath(client, componentName, componentImageName, dir, applicationName, "local", componentPorts, componentEnvVars)
|
||||
odoutil.CheckError(err, "")
|
||||
|
||||
} else if len(componentBinary) != 0 {
|
||||
// Deploy the component with a binary
|
||||
|
||||
// Retrieve the path of the binary
|
||||
path, err := filepath.Abs(componentBinary)
|
||||
odoutil.CheckError(err, "")
|
||||
|
||||
// Create
|
||||
err = component.CreateFromPath(client, componentName, componentImageName, path, applicationName, "binary", componentPorts, componentEnvVars)
|
||||
odoutil.CheckError(err, "")
|
||||
|
||||
} else {
|
||||
// If the user does not provide anything (local, git or binary), use the current absolute path and deploy it
|
||||
dir, err := filepath.Abs("./")
|
||||
odoutil.CheckError(err, "")
|
||||
|
||||
// Create
|
||||
err = component.CreateFromPath(client, componentName, componentImageName, dir, applicationName, "local", componentPorts, componentEnvVars)
|
||||
odoutil.CheckError(err, "")
|
||||
}
|
||||
|
||||
ports, err := component.GetComponentPorts(client, componentName, applicationName)
|
||||
odoutil.CheckError(err, "")
|
||||
fmt.Printf("Component '%s' was created", componentName)
|
||||
|
||||
if len(ports) > 1 {
|
||||
fmt.Printf(" and ports %s were opened\n", strings.Join(ports, ","))
|
||||
} else if len(ports) == 1 {
|
||||
fmt.Printf(" and port %s was opened\n", ports[0])
|
||||
}
|
||||
|
||||
if len(componentGit) == 0 {
|
||||
fmt.Printf("To push source code to the component run 'odo push'\n")
|
||||
}
|
||||
// after component is successfully created, set is as active
|
||||
err = application.SetCurrent(client, applicationName)
|
||||
odoutil.CheckError(err, "")
|
||||
err = component.SetCurrent(componentName, applicationName, projectName)
|
||||
odoutil.CheckError(err, "")
|
||||
fmt.Printf("\nComponent '%s' is now set as active component.\n", componentName)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
componentCreateCmd.Flags().StringVarP(&componentBinary, "binary", "b", "", "Use a binary as the source file for the component")
|
||||
componentCreateCmd.Flags().StringVarP(&componentGit, "git", "g", "", "Use a git repository as the source file for the component")
|
||||
componentCreateCmd.Flags().StringVarP(&componentLocal, "local", "l", "", "Use local directory as a source file for the component")
|
||||
componentCreateCmd.Flags().StringSliceVarP(&componentPorts, "port", "p", []string{}, "Ports to be used when the component is created (ex. 8080,8100/tcp,9100/udp")
|
||||
componentCreateCmd.Flags().StringSliceVar(&componentEnvVars, "env", []string{}, "Environmental variables for the component. For example --env VariableName=Value")
|
||||
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
componentCreateCmd.Annotations = map[string]string{"command": "component"}
|
||||
componentCreateCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(componentCreateCmd)
|
||||
//Adding `--application` flag
|
||||
addApplicationFlag(componentCreateCmd)
|
||||
|
||||
completion.RegisterCommandFlagHandler(componentCreateCmd, "local", completion.FileCompletionHandler)
|
||||
completion.RegisterCommandFlagHandler(componentCreateCmd, "binary", completion.FileCompletionHandler)
|
||||
|
||||
rootCmd.AddCommand(componentCreateCmd)
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
componentShortFlag bool
|
||||
componentForceDeleteFlag bool
|
||||
)
|
||||
|
||||
var componentDeleteCmd = &cobra.Command{
|
||||
Use: "delete <component_name>",
|
||||
Short: "Delete an existing component",
|
||||
Long: "Delete an existing component.",
|
||||
Example: ` # Delete component named 'frontend'.
|
||||
odo delete frontend
|
||||
`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
glog.V(4).Infof("component delete called")
|
||||
glog.V(4).Infof("args: %#v", strings.Join(args, " "))
|
||||
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
projectName := context.Project
|
||||
applicationName := context.Application
|
||||
|
||||
// If no arguments have been passed, get the current component
|
||||
// else, use the first argument and check to see if it exists
|
||||
var componentName string
|
||||
if len(args) == 0 {
|
||||
componentName = context.Component()
|
||||
} else {
|
||||
componentName = context.Component(args[0])
|
||||
}
|
||||
|
||||
var confirmDeletion string
|
||||
if componentForceDeleteFlag {
|
||||
confirmDeletion = "y"
|
||||
} else {
|
||||
fmt.Printf("Are you sure you want to delete %v from %v? [y/N] ", componentName, applicationName)
|
||||
fmt.Scanln(&confirmDeletion)
|
||||
}
|
||||
|
||||
if strings.ToLower(confirmDeletion) == "y" {
|
||||
err := component.Delete(client, componentName, applicationName)
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf("Component %s from application %s has been deleted\n", componentName, applicationName)
|
||||
|
||||
currentComponent, err := component.GetCurrent(applicationName, projectName)
|
||||
util.CheckError(err, "Unable to get current component")
|
||||
|
||||
if currentComponent == "" {
|
||||
fmt.Println("No default component has been set")
|
||||
} else {
|
||||
fmt.Printf("Default component set to: %s\n", currentComponent)
|
||||
}
|
||||
|
||||
} else {
|
||||
fmt.Printf("Aborting deletion of component: %v\n", componentName)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
componentDeleteCmd.Flags().BoolVarP(&componentForceDeleteFlag, "force", "f", false, "Delete component without prompting")
|
||||
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
componentDeleteCmd.Annotations = map[string]string{"command": "component"}
|
||||
componentDeleteCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(componentDeleteCmd)
|
||||
//Adding `--application` flag
|
||||
addApplicationFlag(componentDeleteCmd)
|
||||
|
||||
rootCmd.AddCommand(componentDeleteCmd)
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var describeCmd = &cobra.Command{
|
||||
Use: "describe [component_name]",
|
||||
Short: "Describe the given component",
|
||||
Long: `Describe the given component.`,
|
||||
Example: ` # Describe nodejs component,
|
||||
odo describe nodejs
|
||||
`,
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
|
||||
// If no arguments have been passed, get the current component
|
||||
// else, use the first argument and check to see if it exists
|
||||
var componentName string
|
||||
if len(args) == 0 {
|
||||
componentName = context.Component()
|
||||
} else {
|
||||
componentName = context.Component(args[0])
|
||||
}
|
||||
componentType, path, componentURL, appStore, err := component.GetComponentDesc(client, componentName, applicationName)
|
||||
util.CheckError(err, "")
|
||||
printComponentInfo(componentName, componentType, path, componentURL, appStore)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
describeCmd.Annotations = map[string]string{"command": "component"}
|
||||
describeCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(describeCmd)
|
||||
//Adding `--application` flag
|
||||
addApplicationFlag(describeCmd)
|
||||
|
||||
rootCmd.AddCommand(describeCmd)
|
||||
}
|
||||
155
cmd/link.go
155
cmd/link.go
@@ -1,155 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/secret"
|
||||
"os"
|
||||
|
||||
svc "github.com/redhat-developer/odo/pkg/service"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
port string
|
||||
wait bool
|
||||
)
|
||||
|
||||
var linkCmd = &cobra.Command{
|
||||
Use: "link <service> --component [component] OR link <component> --component [component]",
|
||||
Short: "Link component to a service or component",
|
||||
Long: `Link component to a service or component
|
||||
|
||||
If the source component is not provided, the current active component is assumed.
|
||||
|
||||
In both use cases, link adds the appropriate secret to the environment of the source component.
|
||||
The source component can then consume the entries of the secret as environment variables.
|
||||
|
||||
For example:
|
||||
|
||||
We have created a frontend application called 'frontend':
|
||||
odo create nodejs frontend
|
||||
|
||||
We've also created a backend application called 'backend' with port 8080 exposed:
|
||||
odo create nodejs backend --port 8080
|
||||
|
||||
You can now link the two applications:
|
||||
odo link backend --component frontend
|
||||
|
||||
Now the frontend has 2 ENV variables it can use:
|
||||
COMPONENT_BACKEND_HOST=backend-app
|
||||
COMPONENT_BACKEND_PORT=8080
|
||||
|
||||
If you wish to use a database, we can use the Service Catalog and link it to our backend:
|
||||
odo service create dh-postgresql-apb --plan dev -p postgresql_user=luke -p postgresql_password=secret
|
||||
odo link dh-postgresql-apb
|
||||
|
||||
Now backend has 2 ENV variables it can use:
|
||||
DB_USER=luke
|
||||
DB_PASSWORD=secret
|
||||
`,
|
||||
Example: ` # Link the current component to the 'my-postgresql' service
|
||||
odo link my-postgresql
|
||||
|
||||
# Link component 'nodejs' to the 'my-postgresql' service
|
||||
odo link my-postgresql --component nodejs
|
||||
|
||||
# Link current component to the 'backend' component (backend must have a single exposed port)
|
||||
odo link backend
|
||||
|
||||
# Link component 'nodejs' to the 'backend' component
|
||||
odo link backend --component nodejs
|
||||
|
||||
# Link current component to port 8080 of the 'backend' component (backend must have port 8080 exposed)
|
||||
odo link backend --port 8080
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
projectName := context.Project
|
||||
applicationName := context.Application
|
||||
sourceComponentName := context.Component()
|
||||
|
||||
suppliedName := args[0]
|
||||
|
||||
svcSxists, err := svc.SvcExists(client, suppliedName, applicationName)
|
||||
util.CheckError(err, "Unable to determine if service %s exists", suppliedName)
|
||||
|
||||
cmpExists, err := component.Exists(client, suppliedName, applicationName)
|
||||
util.CheckError(err, "Unable to determine if component %s exists", suppliedName)
|
||||
|
||||
if svcSxists {
|
||||
if cmpExists {
|
||||
glog.V(4).Infof("Both a service and component with name %s - assuming a link to the service is required", suppliedName)
|
||||
}
|
||||
|
||||
serviceName := suppliedName
|
||||
|
||||
// if there is a ServiceBinding, then that means there is already a secret (or there will be soon)
|
||||
// which we can link to
|
||||
_, err = client.GetServiceBinding(serviceName, projectName)
|
||||
if err != nil {
|
||||
fmt.Printf(`The service was not created via Odo.
|
||||
Please delete the service and recreate it using 'odo service create %s'`, serviceName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if wait {
|
||||
// we wait until the secret has been created on the OpenShift
|
||||
// this is done because the secret is only created after the Pod that runs the
|
||||
// service is in running state.
|
||||
// This can take a long time to occur if the image of the service has yet to be downloaded
|
||||
fmt.Printf("Waiting for secret of service %s to come up\n", serviceName)
|
||||
_, err = client.WaitAndGetSecret(serviceName, projectName)
|
||||
util.CheckError(err, "")
|
||||
} else {
|
||||
// we also need to check whether there is a secret with the same name as the service
|
||||
// the secret should have been created along with the secret
|
||||
_, err = client.GetSecret(serviceName, projectName)
|
||||
if err != nil {
|
||||
fmt.Printf(`The service %s created by 'odo service create' is being provisioned.
|
||||
You may have to wait a few seconds until OpenShift fully provisions it.`, serviceName)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
err = client.LinkSecret(serviceName, sourceComponentName, applicationName, projectName)
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf("Service %s has been successfully linked to the component %s.\n", serviceName, sourceComponentName)
|
||||
} else if cmpExists {
|
||||
targetComponent := args[0]
|
||||
|
||||
secretName, err := secret.DetermineSecretName(client, targetComponent, applicationName, port)
|
||||
util.CheckError(err, "")
|
||||
|
||||
err = client.LinkSecret(secretName, sourceComponentName, applicationName, projectName)
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf("Component %s has been successfully linked to component %s.\n", targetComponent, sourceComponentName)
|
||||
} else {
|
||||
fmt.Printf(`Neither a service nor a component named %s could be located
|
||||
Please create one of the two before attempting to use odo link`, suppliedName)
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
linkCmd.PersistentFlags().StringVar(&port, "port", "", "Port of the backend to which to link")
|
||||
linkCmd.PersistentFlags().BoolVarP(&wait, "wait", "w", false, "If enabled, the link command will wait for the service to be provisioned")
|
||||
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
linkCmd.Annotations = map[string]string{"command": "component"}
|
||||
linkCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(linkCmd)
|
||||
//Adding `--application` flag
|
||||
addApplicationFlag(linkCmd)
|
||||
//Adding `--component` flag
|
||||
addComponentFlag(linkCmd)
|
||||
|
||||
rootCmd.AddCommand(linkCmd)
|
||||
}
|
||||
60
cmd/list.go
60
cmd/list.go
@@ -1,60 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var componentListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List all components in the current application",
|
||||
Long: "List all components in the current application.",
|
||||
Example: ` # List all components in the application
|
||||
odo list
|
||||
`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
|
||||
components, err := component.List(client, applicationName)
|
||||
util.CheckError(err, "")
|
||||
if len(components) == 0 {
|
||||
fmt.Println("There are no components deployed.")
|
||||
return
|
||||
}
|
||||
|
||||
activeMark := " "
|
||||
w := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent)
|
||||
fmt.Fprintln(w, "ACTIVE", "\t", "NAME", "\t", "TYPE")
|
||||
currentComponent := context.ComponentAllowingEmpty(true)
|
||||
for _, comp := range components {
|
||||
if comp.Name == currentComponent {
|
||||
activeMark = "*"
|
||||
}
|
||||
fmt.Fprintln(w, activeMark, "\t", comp.Name, "\t", comp.Type)
|
||||
activeMark = " "
|
||||
}
|
||||
w.Flush()
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
componentListCmd.Annotations = map[string]string{"command": "component"}
|
||||
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(componentListCmd)
|
||||
//Adding `--application` flag
|
||||
addApplicationFlag(componentListCmd)
|
||||
|
||||
rootCmd.AddCommand(componentListCmd)
|
||||
}
|
||||
58
cmd/log.go
58
cmd/log.go
@@ -1,58 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"os"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
logFollow bool
|
||||
)
|
||||
|
||||
var logCmd = &cobra.Command{
|
||||
Use: "log [component_name]",
|
||||
Short: "Retrieve the log for the given component.",
|
||||
Long: `Retrieve the log for the given component.`,
|
||||
Example: ` # Get the logs for the nodejs component
|
||||
odo log nodejs
|
||||
`,
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
// Retrieve stdout / io.Writer
|
||||
stdout := os.Stdout
|
||||
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
|
||||
var argComponent string
|
||||
if len(args) == 1 {
|
||||
argComponent = args[0]
|
||||
}
|
||||
componentName := context.Component(argComponent)
|
||||
|
||||
// Retrieve the log
|
||||
err := component.GetLogs(client, componentName, applicationName, logFollow, stdout)
|
||||
util.CheckError(err, "Unable to retrieve logs, does your component exist?")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
logCmd.Flags().BoolVarP(&logFollow, "follow", "f", false, "Follow logs")
|
||||
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
logCmd.Annotations = map[string]string{"command": "component"}
|
||||
logCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(logCmd)
|
||||
//Adding `--application` flag
|
||||
addApplicationFlag(logCmd)
|
||||
|
||||
rootCmd.AddCommand(logCmd)
|
||||
}
|
||||
58
cmd/login.go
58
cmd/login.go
@@ -1,58 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/redhat-developer/odo/pkg/auth"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
userName string
|
||||
password string
|
||||
token string
|
||||
caAuth string
|
||||
skipTLS bool
|
||||
)
|
||||
|
||||
// versionCmd represents the version command
|
||||
var loginCmd = &cobra.Command{
|
||||
Use: "login",
|
||||
Short: "Login to cluster",
|
||||
Long: "Login to cluster",
|
||||
Example: `
|
||||
# Log in interactively
|
||||
odo login
|
||||
|
||||
# Log in to the given server with the given certificate authority file
|
||||
odo login localhost:8443 --certificate-authority=/path/to/cert.crt
|
||||
|
||||
# Log in to the given server with the given credentials (basic auth)
|
||||
odo login localhost:8443 --username=myuser --password=mypass
|
||||
|
||||
# Log in to the given server with the given credentials (token)
|
||||
odo login localhost:8443 --token=xxxxxxxxxxxxxxxxxxxxxxx
|
||||
`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var server string
|
||||
if len(args) == 1 {
|
||||
server = args[0]
|
||||
}
|
||||
err := auth.Login(server, userName, password, token, caAuth, skipTLS)
|
||||
if err != nil {
|
||||
util.CheckError(err, "")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
loginCmd.Annotations = map[string]string{"command": "utility"}
|
||||
loginCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
loginCmd.Flags().StringVarP(&userName, "username", "u", userName, "username, will prompt if not provided")
|
||||
loginCmd.Flags().StringVarP(&password, "password", "p", password, "password, will prompt if not provided")
|
||||
loginCmd.Flags().StringVarP(&token, "token", "t", token, "token, will prompt if not provided")
|
||||
loginCmd.Flags().BoolVar(&skipTLS, "insecure-skip-tls-verify", false, "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure")
|
||||
loginCmd.Flags().StringVar(&caAuth, "certificate-authority", userName, "Path to a cert file for the certificate authority")
|
||||
rootCmd.AddCommand(loginCmd)
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
)
|
||||
|
||||
var logoutCmd = &cobra.Command{
|
||||
Use: "logout",
|
||||
Short: "Log out of the current OpenShift session",
|
||||
Long: "Log out of the current OpenShift session",
|
||||
Example: ` # Logout
|
||||
odo logout
|
||||
`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
err := client.RunLogout(os.Stdout)
|
||||
util.CheckError(err, "")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
logoutCmd.Annotations = map[string]string{"command": "utility"}
|
||||
logoutCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
rootCmd.AddCommand(logoutCmd)
|
||||
}
|
||||
85
cmd/odo/odo.go
Normal file
85
cmd/odo/odo.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/posener/complete"
|
||||
"github.com/redhat-developer/odo/pkg/odo/cli"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// create the complete command
|
||||
root := cli.RootCmd()
|
||||
rootCmp := createCompletion(root)
|
||||
cmp := complete.New("odo", rootCmp)
|
||||
|
||||
// AddFlags adds the completion flags to the program flags, specifying custom names
|
||||
cmp.CLI.InstallName = "complete"
|
||||
cmp.CLI.UninstallName = "uncomplete"
|
||||
cmp.AddFlags(nil)
|
||||
|
||||
// add the completion flags to the root command, though they won't appear in completions
|
||||
root.Flags().AddGoFlagSet(flag.CommandLine)
|
||||
// override usage so that flag.Parse uses root command's usage instead of default one when invoked with -h
|
||||
flag.Usage = usage
|
||||
|
||||
// parse the flags - both the program's flags and the completion flags
|
||||
flag.Parse()
|
||||
|
||||
// run the completion, in case that the completion was invoked
|
||||
// and ran as a completion script or handled a flag that passed
|
||||
// as argument, the Run method will return true,
|
||||
// in that case, our program have nothing to do and should return.
|
||||
if cmp.Complete() {
|
||||
return
|
||||
}
|
||||
|
||||
// Call commands
|
||||
cli.Execute()
|
||||
}
|
||||
|
||||
func usage() {
|
||||
_ = cli.RootCmd().Usage()
|
||||
}
|
||||
|
||||
func createCompletion(root *cobra.Command) complete.Command {
|
||||
rootCmp := complete.Command{}
|
||||
rootCmp.Flags = make(complete.Flags)
|
||||
addFlags := func(flag *pflag.Flag) {
|
||||
if flag.Hidden {
|
||||
return
|
||||
}
|
||||
var handler complete.Predictor
|
||||
handler, ok := completion.GetCommandFlagHandler(root, flag.Name)
|
||||
if !ok {
|
||||
handler = complete.PredictAnything
|
||||
}
|
||||
|
||||
if len(flag.Shorthand) > 0 {
|
||||
rootCmp.Flags["-"+flag.Shorthand] = handler
|
||||
}
|
||||
|
||||
rootCmp.Flags["--"+flag.Name] = handler
|
||||
}
|
||||
root.LocalFlags().VisitAll(addFlags)
|
||||
root.InheritedFlags().VisitAll(addFlags)
|
||||
if root.HasAvailableSubCommands() {
|
||||
rootCmp.Sub = make(complete.Commands)
|
||||
for _, c := range root.Commands() {
|
||||
if !c.Hidden {
|
||||
rootCmp.Sub[c.Name()] = createCompletion(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var handler complete.Predictor
|
||||
handler, ok := completion.GetCommandHandler(root)
|
||||
if !ok {
|
||||
handler = complete.PredictNothing
|
||||
}
|
||||
rootCmp.Args = handler
|
||||
|
||||
return rootCmp
|
||||
}
|
||||
221
cmd/project.go
221
cmd/project.go
@@ -1,221 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/project"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
projectShortFlag bool
|
||||
projectForceDeleteFlag bool
|
||||
)
|
||||
|
||||
var projectCmd = &cobra.Command{
|
||||
Use: "project [options]",
|
||||
Short: "Perform project operations",
|
||||
Long: "Perform project operations",
|
||||
Example: fmt.Sprintf("%s\n%s\n%s\n%s\n%s",
|
||||
projectSetCmd.Example,
|
||||
projectCreateCmd.Example,
|
||||
projectListCmd.Example,
|
||||
projectDeleteCmd.Example,
|
||||
projectGetCmd.Example),
|
||||
// 'odo project' is the same as 'odo project get'
|
||||
// 'odo project <project_name>' is the same as 'odo project set <project_name>'
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) > 0 && args[0] != "get" && args[0] != "set" {
|
||||
projectSetCmd.Run(cmd, args)
|
||||
} else {
|
||||
projectGetCmd.Run(cmd, args)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var projectSetCmd = &cobra.Command{
|
||||
Use: "set",
|
||||
Short: "Set the current active project",
|
||||
Long: "Set the current active project",
|
||||
Example: ` # Set the current active project
|
||||
odo project set myproject
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
projectName := args[0]
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
current := context.Project
|
||||
|
||||
exists, err := project.Exists(client, projectName)
|
||||
util.CheckError(err, "")
|
||||
if !exists {
|
||||
fmt.Printf("The project %s does not exist\n", projectName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = project.SetCurrent(client, projectName)
|
||||
util.CheckError(err, "")
|
||||
if projectShortFlag {
|
||||
fmt.Print(projectName)
|
||||
} else {
|
||||
if current == projectName {
|
||||
fmt.Printf("Already on project : %v\n", projectName)
|
||||
} else {
|
||||
fmt.Printf("Switched to project : %v\n", projectName)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var projectGetCmd = &cobra.Command{
|
||||
Use: "get",
|
||||
Short: "Get the active project",
|
||||
Long: "Get the active project",
|
||||
Example: ` # Get the active project
|
||||
odo project get
|
||||
`,
|
||||
Args: cobra.ExactArgs(0),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
project := context.Project
|
||||
|
||||
if projectShortFlag {
|
||||
fmt.Print(project)
|
||||
} else {
|
||||
fmt.Printf("The current project is: %v\n", project)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var projectCreateCmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Create a new project",
|
||||
Long: "Create a new project",
|
||||
Example: ` # Create a new project
|
||||
odo project create myproject
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
projectName := args[0]
|
||||
client := genericclioptions.Client(cmd)
|
||||
err := project.Create(client, projectName)
|
||||
util.CheckError(err, "")
|
||||
err = project.SetCurrent(client, projectName)
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf("New project created and now using project : %v\n", projectName)
|
||||
},
|
||||
}
|
||||
|
||||
var projectDeleteCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Short: "Delete a project",
|
||||
Long: "Delete a project and all resources deployed in the project being deleted",
|
||||
Example: ` # Delete a project
|
||||
odo project delete myproject
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
projectName := args[0]
|
||||
client := genericclioptions.Client(cmd)
|
||||
|
||||
// Validate existence of the project to be deleted
|
||||
isValidProject, err := project.Exists(client, projectName)
|
||||
util.CheckError(err, "Failed to delete project %s", projectName)
|
||||
if !isValidProject {
|
||||
fmt.Printf("The project %s does not exist. Please check the list of projects using `odo project list`\n", projectName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var confirmDeletion string
|
||||
if projectForceDeleteFlag {
|
||||
confirmDeletion = "y"
|
||||
} else {
|
||||
fmt.Printf("Are you sure you want to delete project %v? [y/N] ", projectName)
|
||||
fmt.Scanln(&confirmDeletion)
|
||||
}
|
||||
|
||||
if strings.ToLower(confirmDeletion) != "y" {
|
||||
fmt.Printf("Aborting deletion of project: %v\n", projectName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("Deleting project %s...\n(this operation may take some time)\n", projectName)
|
||||
err = project.Delete(client, projectName)
|
||||
if err != nil {
|
||||
util.CheckError(err, "")
|
||||
}
|
||||
fmt.Printf("Deleted project : %v\n", projectName)
|
||||
|
||||
// Get Current Project
|
||||
currProject := project.GetCurrent(client)
|
||||
|
||||
// Check if List returns empty, if so, the currProject is showing old currentProject
|
||||
// In openshift, when the project is deleted, it does not reset the current project in kube config file which is used by odo for current project
|
||||
projects, err := project.List(client)
|
||||
util.CheckError(err, "")
|
||||
if len(projects) != 0 {
|
||||
fmt.Printf("%s has been set as the active project\n", currProject)
|
||||
} else {
|
||||
// oc errors out as "error: you do not have rights to view project "$deleted_project"."
|
||||
fmt.Printf("You are not a member of any projects. You can request a project to be created using the `odo project create <project_name>` command\n")
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
var projectListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List all the projects",
|
||||
Long: "List all the projects",
|
||||
Example: ` # List all the projects
|
||||
odo project list
|
||||
`,
|
||||
Args: cobra.ExactArgs(0),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
client := genericclioptions.Client(cmd)
|
||||
projects, err := project.List(client)
|
||||
util.CheckError(err, "")
|
||||
if len(projects) == 0 {
|
||||
fmt.Println("You are not a member of any projects. You can request a project to be created using the `odo project create <project_name>` command")
|
||||
return
|
||||
}
|
||||
fmt.Printf("ACTIVE NAME\n")
|
||||
for _, project := range projects {
|
||||
activeMark := " "
|
||||
if project.Active {
|
||||
activeMark = "*"
|
||||
}
|
||||
fmt.Printf(" %s %s\n", activeMark, project.Name)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
projectGetCmd.Flags().BoolVarP(&projectShortFlag, "short", "q", false, "If true, display only the project name")
|
||||
projectSetCmd.Flags().BoolVarP(&projectShortFlag, "short", "q", false, "If true, display only the project name")
|
||||
projectDeleteCmd.Flags().BoolVarP(&projectForceDeleteFlag, "force", "f", false, "Delete project without prompting")
|
||||
projectDeleteCmd.Flags().BoolVarP(&projectShortFlag, "short", "q", false, "Delete project without prompting")
|
||||
|
||||
projectCmd.Flags().AddFlagSet(projectGetCmd.Flags())
|
||||
projectCmd.AddCommand(projectGetCmd)
|
||||
projectCmd.AddCommand(projectSetCmd)
|
||||
projectCmd.AddCommand(projectCreateCmd)
|
||||
projectCmd.AddCommand(projectDeleteCmd)
|
||||
projectCmd.AddCommand(projectListCmd)
|
||||
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
projectCmd.Annotations = map[string]string{"command": "other"}
|
||||
projectCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
completion.RegisterCommandHandler(projectSetCmd, completion.ProjectNameCompletionHandler)
|
||||
completion.RegisterCommandHandler(projectDeleteCmd, completion.ProjectNameCompletionHandler)
|
||||
|
||||
rootCmd.AddCommand(projectCmd)
|
||||
}
|
||||
116
cmd/push.go
116
cmd/push.go
@@ -1,116 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
odoutil "github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
|
||||
"path/filepath"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var pushCmd = &cobra.Command{
|
||||
Use: "push [component name]",
|
||||
Short: "Push source code to a component",
|
||||
Long: `Push source code to a component.`,
|
||||
Example: ` # Push source code to the current component
|
||||
odo push
|
||||
|
||||
# Push data to the current component from the original source.
|
||||
odo push
|
||||
|
||||
# Push source code in ~/mycode to component called my-component
|
||||
odo push my-component --local ~/mycode
|
||||
`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
stdout := color.Output
|
||||
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
|
||||
var argComponent string
|
||||
if len(args) == 1 {
|
||||
argComponent = args[0]
|
||||
}
|
||||
componentName := context.Component(argComponent)
|
||||
|
||||
fmt.Printf("Pushing changes to component: %v\n", componentName)
|
||||
|
||||
sourceType, sourcePath, err := component.GetComponentSource(client, componentName, applicationName)
|
||||
odoutil.CheckError(err, "unable to get component source")
|
||||
switch sourceType {
|
||||
case "local", "binary":
|
||||
// use value of '--dir' as source if it was used
|
||||
if len(componentLocal) != 0 {
|
||||
if sourceType == "binary" {
|
||||
fmt.Printf("Unable to push local directory:%s to component %s that uses binary %s.\n", componentLocal, componentName, sourcePath)
|
||||
os.Exit(1)
|
||||
}
|
||||
sourcePath = util.GenFileUrl(componentLocal, runtime.GOOS)
|
||||
}
|
||||
|
||||
u, err := url.Parse(sourcePath)
|
||||
odoutil.CheckError(err, fmt.Sprintf("unable to parse source %s from component %s", sourcePath, componentName))
|
||||
|
||||
if u.Scheme != "" && u.Scheme != "file" {
|
||||
fmt.Printf("Component %s has invalid source path %s", componentName, u.Scheme)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
localLocation := util.ReadFilePath(u, runtime.GOOS)
|
||||
|
||||
_, err = os.Stat(localLocation)
|
||||
if err != nil {
|
||||
odoutil.CheckError(err, "")
|
||||
}
|
||||
|
||||
if sourceType == "local" {
|
||||
glog.V(4).Infof("Copying directory %s to pod", localLocation)
|
||||
err = component.PushLocal(client, componentName, applicationName, localLocation, os.Stdout, []string{})
|
||||
} else {
|
||||
dir := filepath.Dir(localLocation)
|
||||
glog.V(4).Infof("Copying file %s to pod", localLocation)
|
||||
err = component.PushLocal(client, componentName, applicationName, dir, os.Stdout, []string{localLocation})
|
||||
}
|
||||
odoutil.CheckError(err, fmt.Sprintf("failed to push component: %v", componentName))
|
||||
|
||||
case "git":
|
||||
// currently we don't support changing build type
|
||||
// it doesn't make sense to use --dir with git build
|
||||
if len(componentLocal) != 0 {
|
||||
fmt.Printf("Unable to push local directory:%s to component %s that uses Git repository:%s.\n", componentLocal, componentName, sourcePath)
|
||||
os.Exit(1)
|
||||
}
|
||||
err := component.Build(client, componentName, applicationName, true, true, stdout)
|
||||
odoutil.CheckError(err, fmt.Sprintf("failed to push component: %v", componentName))
|
||||
}
|
||||
|
||||
fmt.Printf("changes successfully pushed to component: %v\n", componentName)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
pushCmd.Flags().StringVarP(&componentLocal, "local", "l", "", "Use given local directory as a source for component. (It must be a local component)")
|
||||
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
pushCmd.Annotations = map[string]string{"command": "component"}
|
||||
pushCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(pushCmd)
|
||||
//Adding `--application` flag
|
||||
addApplicationFlag(pushCmd)
|
||||
|
||||
rootCmd.AddCommand(pushCmd)
|
||||
}
|
||||
156
cmd/root.go
156
cmd/root.go
@@ -1,156 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"github.com/redhat-developer/odo/pkg/config"
|
||||
"github.com/redhat-developer/odo/pkg/notify"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// Templates
|
||||
var rootUsageTemplate = `Usage:{{if .Runnable}}
|
||||
{{if .HasAvailableFlags}}{{appendIfNotPresent .UseLine "[flags]"}}{{else}}{{.UseLine}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
|
||||
{{ .CommandPath}} [command]{{end}}{{if gt .Aliases 0}}
|
||||
|
||||
Aliases:
|
||||
{{.NameAndAliases}}{{end}}{{if .HasExample}}
|
||||
|
||||
Examples:
|
||||
{{ .Example }}{{end}}{{ if .HasAvailableSubCommands}}
|
||||
|
||||
Component Commands:{{range .Commands}}{{if eq .Annotations.command "component"}}
|
||||
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableLocalFlags}}
|
||||
|
||||
Other Commands:{{range .Commands}}{{if eq .Annotations.command "other"}}
|
||||
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableLocalFlags}}
|
||||
|
||||
Utility Commands:{{range .Commands}}{{if or (eq .Annotations.command "utility") (eq .Name "help") }}
|
||||
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableLocalFlags}}
|
||||
|
||||
Flags:
|
||||
{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasAvailableInheritedFlags}}
|
||||
|
||||
Global Flags:
|
||||
{{.InheritedFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasHelpSubCommands}}
|
||||
|
||||
Additional help topics:{{range .Commands}}{{if .IsHelpCommand}}
|
||||
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableSubCommands }}
|
||||
|
||||
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
|
||||
`
|
||||
|
||||
var cmdUsageTemplate = `Usage:{{if .Runnable}}
|
||||
{{if .HasAvailableFlags}}{{appendIfNotPresent .UseLine "[flags]"}}{{else}}{{.UseLine}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
|
||||
{{ .CommandPath}} [command]{{end}}{{if gt .Aliases 0}}
|
||||
|
||||
Aliases:
|
||||
{{.NameAndAliases}}{{end}}{{if .HasExample}}
|
||||
|
||||
Examples:
|
||||
{{ .Example }}{{end}}{{ if .HasAvailableSubCommands}}
|
||||
|
||||
Available Commands:{{range .Commands}}{{if .IsAvailableCommand}}
|
||||
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableLocalFlags}}
|
||||
|
||||
Flags:
|
||||
{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasAvailableInheritedFlags}}
|
||||
|
||||
Global Flags:
|
||||
{{.InheritedFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasHelpSubCommands}}
|
||||
|
||||
Additional help topics:{{range .Commands}}{{if .IsHelpCommand}}
|
||||
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableSubCommands }}
|
||||
|
||||
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
|
||||
`
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: util.RootCommandName,
|
||||
Short: "Odo (Openshift Do)",
|
||||
Long: `Odo (OpenShift Do) is a CLI tool for running OpenShift applications in a fast and automated matter. Odo reduces the complexity of deployment by adding iterative development without the worry of deploying your source code.
|
||||
|
||||
Find more information at https://github.com/redhat-developer/odo`,
|
||||
Example: ` # Creating and deploying a Node.js project
|
||||
git clone https://github.com/openshift/nodejs-ex && cd nodejs-ex
|
||||
odo create nodejs
|
||||
odo push
|
||||
|
||||
# Accessing your Node.js component
|
||||
odo url create`,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
},
|
||||
}
|
||||
|
||||
// RootCmd exposes the root command to main package to allow inspection by completion code
|
||||
func RootCmd() *cobra.Command {
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
// 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() {
|
||||
|
||||
// checking the value of updatenotification in config
|
||||
// before proceeding with fetching the latest version
|
||||
cfg, err := config.New()
|
||||
if err != nil {
|
||||
util.CheckError(err, "")
|
||||
}
|
||||
if cfg.GetUpdateNotification() == true {
|
||||
updateInfo := make(chan string)
|
||||
go getLatestReleaseInfo(updateInfo)
|
||||
|
||||
util.CheckError(rootCmd.Execute(), "")
|
||||
select {
|
||||
case message := <-updateInfo:
|
||||
fmt.Println(message)
|
||||
default:
|
||||
glog.V(4).Info("Could not get the latest release information in time. Never mind, exiting gracefully :)")
|
||||
}
|
||||
} else {
|
||||
util.CheckError(rootCmd.Execute(), "")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func init() {
|
||||
// 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/.odo.yaml)")
|
||||
|
||||
rootCmd.PersistentFlags().Bool(util.SkipConnectionCheckFlagName, false, "Skip cluster check")
|
||||
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
|
||||
pflag.CommandLine.Set("logtostderr", "true")
|
||||
|
||||
// Override the verbosity flag description
|
||||
verbosity := pflag.Lookup("v")
|
||||
verbosity.Usage += ". Level varies from 0 to 9 (default 0)."
|
||||
|
||||
rootCmd.SetUsageTemplate(rootUsageTemplate)
|
||||
flag.CommandLine.Parse([]string{})
|
||||
}
|
||||
|
||||
func getLatestReleaseInfo(info chan<- string) {
|
||||
newTag, err := notify.CheckLatestReleaseTag(VERSION)
|
||||
if err != nil {
|
||||
// The error is intentionally not being handled because we don't want
|
||||
// to stop the execution of the program because of this failure
|
||||
glog.V(4).Infof("Error checking if newer odo release is available: %v", err)
|
||||
}
|
||||
if len(newTag) > 0 {
|
||||
info <- "---\n" +
|
||||
"A newer version of odo (version: " + fmt.Sprint(newTag) + ") is available.\n" +
|
||||
"Update using your package manager, or run\n" +
|
||||
"curl " + notify.InstallScriptURL + " | sh\n" +
|
||||
"to update manually, or visit https://github.com/redhat-developer/odo/releases\n" +
|
||||
"---\n" +
|
||||
"If you wish to disable the update notifications, you can disable it by running\n" +
|
||||
"'odo utils config set UpdateNotification false'\n"
|
||||
}
|
||||
}
|
||||
211
cmd/service.go
211
cmd/service.go
@@ -1,211 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/golang/glog"
|
||||
svc "github.com/redhat-developer/odo/pkg/service"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
serviceForceDeleteFlag bool
|
||||
parameters []string
|
||||
plan string
|
||||
)
|
||||
|
||||
// serviceCmd represents the service command
|
||||
var serviceCmd = &cobra.Command{
|
||||
Use: "service",
|
||||
Short: "Perform service catalog operations",
|
||||
Long: ` Perform service catalog operations, Limited to template service broker only.`,
|
||||
Example: fmt.Sprintf("%s\n%s\n%s",
|
||||
serviceCreateCmd.Example,
|
||||
serviceDeleteCmd.Example,
|
||||
serviceListCmd.Example),
|
||||
Args: cobra.RangeArgs(1, 3),
|
||||
}
|
||||
|
||||
var serviceCreateCmd = &cobra.Command{
|
||||
Use: "create <service_type> --plan <plan_name> [service_name]",
|
||||
Short: "Create a new service",
|
||||
Long: `Create a new service from service catalog using the plan defined and deploy it on OpenShift.
|
||||
|
||||
If service name is not provided, service type value will be used. The plan to be used must be passed along the service type
|
||||
using this convention <service_type>/<plan>. The parameters to configure the service are passed as a list of key=value pairs.
|
||||
The list of the parameters and their type is defined according to the plan selected.
|
||||
|
||||
A full list of service types that can be deployed are available using: 'odo catalog list services'`,
|
||||
Example: ` # Create new postgresql service from service catalog using dev plan and name my-postgresql-db.
|
||||
odo service create dh-postgresql-apb my-postgresql-db --plan dev -p postgresql_user=luke -p postgresql_password=secret
|
||||
`,
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContextCreatingAppIfNeeded(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
|
||||
// make sure the service type exists
|
||||
serviceType := args[0]
|
||||
matchingService, err := svc.GetSvcByType(client, serviceType)
|
||||
util.CheckError(err, "unable to create service because Service Catalog is not enabled in your cluster")
|
||||
if matchingService == nil {
|
||||
fmt.Printf("Service %v doesn't exist\nRun 'odo service catalog' to see a list of supported services.\n", serviceType)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if len(plan) == 0 {
|
||||
// when the plan has not been supplied, if there is only one available plan, we select it
|
||||
if len(matchingService.PlanList) == 1 {
|
||||
plan = matchingService.PlanList[0]
|
||||
glog.V(4).Infof("Plan %s was automatically selected since it's the only one available for service %s", plan, serviceType)
|
||||
} else {
|
||||
fmt.Printf("No plan was supplied for service %v.\nPlease select one of: %v\n", serviceType, strings.Join(matchingService.PlanList, ","))
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
// when the plan has been supplied, we need to make sure it exists
|
||||
planFound := false
|
||||
for _, candidatePlan := range matchingService.PlanList {
|
||||
if plan == candidatePlan {
|
||||
planFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !planFound {
|
||||
fmt.Printf("Plan %s is invalid for service %v.\nPlease select one of: %v\n", plan, serviceType, strings.Join(matchingService.PlanList, ","))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// if only one arg is given, then it is considered as service name and service type both
|
||||
serviceName := serviceType
|
||||
// if two args are given, first is service type and second one is service name
|
||||
if len(args) == 2 {
|
||||
serviceName = args[1]
|
||||
}
|
||||
//validate service name
|
||||
err = validateName(serviceName)
|
||||
util.CheckError(err, "")
|
||||
exists, err := svc.SvcExists(client, serviceName, applicationName)
|
||||
|
||||
util.CheckError(err, "")
|
||||
if exists {
|
||||
fmt.Printf("%s service already exists in the current application.\n", serviceName)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = svc.CreateService(client, serviceName, serviceType, plan, parameters, applicationName)
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf(`Service '%s' was created.
|
||||
Progress of the provisioning will not be reported and might take a long time.
|
||||
You can see the current status by executing 'odo service list'`, serviceName)
|
||||
},
|
||||
}
|
||||
|
||||
var serviceDeleteCmd = &cobra.Command{
|
||||
Use: "delete <service_name>",
|
||||
Short: "Delete an existing service",
|
||||
Long: "Delete an existing service",
|
||||
Example: ` # Delete the service named 'mysql-persistent'
|
||||
odo service delete mysql-persistent
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
glog.V(4).Infof("service delete called\n args: %#v", strings.Join(args, " "))
|
||||
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
|
||||
serviceName := args[0]
|
||||
|
||||
// Checks to see if the service actually exists
|
||||
exists, err := svc.SvcExists(client, serviceName, applicationName)
|
||||
util.CheckError(err, "unable to delete service because Service Catalog is not enabled in your cluster")
|
||||
if !exists {
|
||||
fmt.Printf("Service with the name %s does not exist in the current application\n", serviceName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var confirmDeletion string
|
||||
if serviceForceDeleteFlag {
|
||||
confirmDeletion = "y"
|
||||
} else {
|
||||
fmt.Printf("Are you sure you want to delete %v from %v? [y/N] ", serviceName, applicationName)
|
||||
fmt.Scanln(&confirmDeletion)
|
||||
}
|
||||
|
||||
if strings.ToLower(confirmDeletion) == "y" {
|
||||
err := svc.DeleteService(client, serviceName, applicationName)
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf("Service %s from application %s has been deleted\n", serviceName, applicationName)
|
||||
|
||||
} else {
|
||||
fmt.Printf("Aborting deletion of service: %v\n", serviceName)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var serviceListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List all services in the current application",
|
||||
Long: "List all services in the current application",
|
||||
Example: ` # List all services in the application
|
||||
odo service list
|
||||
`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
|
||||
services, err := svc.ListWithDetailedStatus(client, applicationName)
|
||||
util.CheckError(err, "Service Catalog is not enabled in your cluster")
|
||||
|
||||
if len(services) == 0 {
|
||||
fmt.Println("There are no services deployed for this application")
|
||||
return
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent)
|
||||
fmt.Fprintln(w, "NAME", "\t", "TYPE", "\t", "STATUS")
|
||||
for _, comp := range services {
|
||||
fmt.Fprintln(w, comp.Name, "\t", comp.Type, "\t", comp.Status)
|
||||
}
|
||||
w.Flush()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
serviceDeleteCmd.Flags().BoolVarP(&serviceForceDeleteFlag, "force", "f", false, "Delete service without prompting")
|
||||
serviceCreateCmd.Flags().StringVar(&plan, "plan", "", "The name of the plan of the service to be created")
|
||||
serviceCreateCmd.Flags().StringSliceVarP(¶meters, "parameters", "p", []string{}, "Parameters of the plan where a parameter is expressed as <key>=<value")
|
||||
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
serviceCmd.Annotations = map[string]string{"command": "other"}
|
||||
serviceCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
serviceCmd.AddCommand(serviceCreateCmd)
|
||||
serviceCmd.AddCommand(serviceDeleteCmd)
|
||||
serviceCmd.AddCommand(serviceListCmd)
|
||||
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(serviceCreateCmd)
|
||||
addProjectFlag(serviceDeleteCmd)
|
||||
addProjectFlag(serviceListCmd)
|
||||
|
||||
//Adding `--application` flag
|
||||
addApplicationFlag(serviceCreateCmd)
|
||||
addApplicationFlag(serviceDeleteCmd)
|
||||
addApplicationFlag(serviceListCmd)
|
||||
|
||||
rootCmd.AddCommand(serviceCmd)
|
||||
|
||||
completion.RegisterCommandHandler(serviceCreateCmd, completion.ServiceClassCompletionHandler)
|
||||
completion.RegisterCommandHandler(serviceDeleteCmd, completion.ServiceCompletionHandler)
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog/v1beta1"
|
||||
"github.com/posener/complete"
|
||||
componentlabels "github.com/redhat-developer/odo/pkg/component/labels"
|
||||
"github.com/redhat-developer/odo/pkg/occlient"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ktesting "k8s.io/client-go/testing"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompletions(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
handler completion.ContextualizedPredictor
|
||||
cmd *cobra.Command
|
||||
last string
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "Completing service create without input returns all available service class external names",
|
||||
handler: completion.ServiceClassCompletionHandler,
|
||||
cmd: serviceCreateCmd,
|
||||
want: []string{"foo", "bar", "boo"},
|
||||
},
|
||||
{
|
||||
name: "Completing service delete without input returns all available service instances",
|
||||
handler: completion.ServiceCompletionHandler,
|
||||
cmd: serviceDeleteCmd,
|
||||
want: []string{"foo"},
|
||||
},
|
||||
}
|
||||
|
||||
client, fakeClientSet := occlient.FakeNew()
|
||||
fakeClientSet.ServiceCatalogClientSet.PrependReactor("list", "clusterserviceclasses", func(action ktesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, &v1beta1.ClusterServiceClassList{
|
||||
Items: []v1beta1.ClusterServiceClass{
|
||||
fakeClusterServiceClass("foo"),
|
||||
fakeClusterServiceClass("bar"),
|
||||
fakeClusterServiceClass("boo"),
|
||||
},
|
||||
}, nil
|
||||
})
|
||||
fakeClientSet.ServiceCatalogClientSet.PrependReactor("list", "serviceinstances", func(action ktesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, &v1beta1.ServiceInstanceList{
|
||||
Items: []v1beta1.ServiceInstance{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"app.kubernetes.io/name": "foo", componentlabels.ComponentLabel: "foo", componentlabels.ComponentTypeLabel: "service"},
|
||||
},
|
||||
Status: v1beta1.ServiceInstanceStatus{
|
||||
Conditions: []v1beta1.ServiceInstanceCondition{
|
||||
{
|
||||
Reason: "some reason",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
})
|
||||
context := genericclioptions.NewFakeContext("", "", "", client)
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := complete.Args{Last: tt.last}
|
||||
|
||||
got := tt.handler(tt.cmd, completion.NewParsedArgs(a, tt.cmd), context)
|
||||
|
||||
if !equal(got, tt.want) {
|
||||
t.Errorf("Failed %s: got: %q, want: %q", t.Name(), got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func fakeClusterServiceClass(name string) v1beta1.ClusterServiceClass {
|
||||
return v1beta1.ClusterServiceClass{
|
||||
Spec: v1beta1.ClusterServiceClassSpec{
|
||||
CommonServiceClassSpec: v1beta1.CommonServiceClassSpec{
|
||||
ExternalName: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func equal(s1, s2 []string) bool {
|
||||
sort.Strings(s1)
|
||||
sort.Strings(s2)
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
for i := range s1 {
|
||||
if s1[i] != s2[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
288
cmd/storage.go
288
cmd/storage.go
@@ -1,288 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
odoutil "github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/storage"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
storageSize string
|
||||
storagePath string
|
||||
storageForceDeleteflag bool
|
||||
storageAllListflag bool
|
||||
)
|
||||
|
||||
var storageCmd = &cobra.Command{
|
||||
Use: "storage",
|
||||
Short: "Perform storage operations",
|
||||
Long: "Perform storage operations",
|
||||
Example: fmt.Sprintf("%s\n%s\n%s\n%s",
|
||||
storageCreateCmd.Example,
|
||||
storageDeleteCmd.Example,
|
||||
storageUnmountCmd.Example,
|
||||
storageListCmd.Example),
|
||||
}
|
||||
|
||||
var storageCreateCmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Create storage and mount to a component",
|
||||
Long: "Create storage and mount to a component",
|
||||
Example: ` # Create storage of size 1Gb to a component
|
||||
odo storage create mystorage --path=/opt/app-root/src/storage/ --size=1Gi
|
||||
`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
componentName := context.Component()
|
||||
|
||||
var storageName string
|
||||
if len(args) != 0 {
|
||||
storageName = args[0]
|
||||
} else {
|
||||
storageName = componentName + "-" + util.GenerateRandomString(4)
|
||||
}
|
||||
// validate storage path
|
||||
err := validateStoragePath(client, storagePath, componentName, applicationName)
|
||||
odoutil.CheckError(err, "")
|
||||
|
||||
_, err = storage.Create(client, storageName, storageSize, storagePath, componentName, applicationName)
|
||||
odoutil.CheckError(err, "")
|
||||
fmt.Printf("Added storage %v to %v\n", storageName, componentName)
|
||||
},
|
||||
}
|
||||
|
||||
var storageUnmountCmd = &cobra.Command{
|
||||
Use: "unmount PATH | STORAGE_NAME",
|
||||
Short: "Unmount storage from the given path or identified by its name, from the current component",
|
||||
Long: `Unmount storage from the given path or identified by its name, from the current component.
|
||||
|
||||
The storage and the contents are not deleted, the storage or storage with the given path, is only unmounted from the component, and hence is no longer accessible by the component.`,
|
||||
Example: ` # Unmount storage 'dbstorage' from current component
|
||||
odo storage unmount dbstorage
|
||||
|
||||
# Unmount storage 'database' from component 'mongodb'
|
||||
odo storage unmount database --component mongodb
|
||||
|
||||
# Unmount storage mounted to path '/data' from current component
|
||||
odo storage unmount /data
|
||||
|
||||
# Unmount storage mounted to path '/data' from component 'mongodb'
|
||||
odo storage unmount /data --component mongodb
|
||||
`,
|
||||
Aliases: []string{"umount"},
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
componentName := context.Component()
|
||||
|
||||
var storageName string
|
||||
var err error
|
||||
// checking if the first character in the argument is a "/", indicating a path or not, indicating a storage name
|
||||
if string(args[0][0]) == "/" {
|
||||
path := args[0]
|
||||
storageName, err = storage.GetStorageNameFromMountPath(client, path, componentName, applicationName)
|
||||
odoutil.CheckError(err, "Unable to get storage name from mount path")
|
||||
if storageName == "" {
|
||||
fmt.Printf("No storage is mounted to %s in the component %s\n", path, componentName)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
storageName = args[0]
|
||||
exists, err := storage.IsMounted(client, storageName, componentName, applicationName)
|
||||
odoutil.CheckError(err, "Unable to check if storage is mounted or not")
|
||||
if !exists {
|
||||
fmt.Printf("Storage %v does not exist in component %v\n", storageName, componentName)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
err = storage.Unmount(client, storageName, componentName, applicationName, true)
|
||||
odoutil.CheckError(err, "Unable to unmount storage %v from component %v", storageName, componentName)
|
||||
|
||||
fmt.Printf("Unmounted storage %v from %v\n", storageName, componentName)
|
||||
},
|
||||
}
|
||||
|
||||
var storageDeleteCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Short: "Delete storage from component",
|
||||
Example: ` # Delete storage mystorage from the currently active component
|
||||
odo storage delete mystorage
|
||||
|
||||
# Delete storage mystorage from component 'mongodb'
|
||||
odo storage delete mystorage --component mongodb
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
|
||||
storageName := args[0]
|
||||
|
||||
exists, err := storage.Exists(client, storageName, applicationName)
|
||||
odoutil.CheckError(err, "")
|
||||
if !exists {
|
||||
|
||||
fmt.Printf("The storage %v does not exists in the application %v\n", storageName, applicationName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
componentName, err := storage.GetComponentNameFromStorageName(client, storageName)
|
||||
if err != nil {
|
||||
odoutil.CheckError(err, "Unable to get component associated with %s storage.", storageName)
|
||||
}
|
||||
|
||||
var confirmDeletion string
|
||||
if storageForceDeleteflag {
|
||||
confirmDeletion = "y"
|
||||
} else {
|
||||
if componentName != "" {
|
||||
mPath := storage.GetMountPath(client, storageName, componentName, applicationName)
|
||||
fmt.Printf("Are you sure you want to delete the storage %v mounted to %v in %v component? [y/N] ", storageName, mPath, componentName)
|
||||
} else {
|
||||
fmt.Printf("Are you sure you want to delete the storage %v that is not currently mounted to any component? [y/N] ", storageName)
|
||||
}
|
||||
fmt.Scanln(&confirmDeletion)
|
||||
}
|
||||
if strings.ToLower(confirmDeletion) == "y" {
|
||||
componentName, err = storage.Delete(client, storageName, applicationName)
|
||||
odoutil.CheckError(err, "failed to delete storage")
|
||||
if componentName != "" {
|
||||
fmt.Printf("Deleted storage %v from %v\n", storageName, componentName)
|
||||
} else {
|
||||
fmt.Printf("Deleted storage %v\n", storageName)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Aborting deletion of storage: %v\n", storageName)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var storageListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List storage attached to a component",
|
||||
Long: "List storage attached to a component",
|
||||
Example: ` # List all storage attached or mounted to the current component and
|
||||
# all unattached or unmounted storage in the current application
|
||||
odo storage list
|
||||
`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
|
||||
if storageAllListflag {
|
||||
if len(genericclioptions.FlagValueIfSet(cmd, odoutil.ComponentFlagName)) > 0 {
|
||||
fmt.Println("Invalid arguments. Component name is not needed")
|
||||
os.Exit(1)
|
||||
}
|
||||
printMountedStorageInAllComponent(client, applicationName)
|
||||
} else {
|
||||
// storageComponent is the input component name
|
||||
componentName := context.Component()
|
||||
printMountedStorageInComponent(client, componentName, applicationName)
|
||||
}
|
||||
printUnmountedStorage(client, applicationName)
|
||||
},
|
||||
}
|
||||
|
||||
var storageMountCmd = &cobra.Command{
|
||||
Use: "mount [storage name]",
|
||||
Short: "mount storage to a component",
|
||||
Example: ` # Mount storage 'dbstorage' to current component
|
||||
odo storage mount dbstorage --path /data
|
||||
|
||||
# Mount storage 'database' to component 'mongodb'
|
||||
odo storage mount database --component mongodb --path /data`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
componentName := context.Component()
|
||||
|
||||
storageName := args[0]
|
||||
|
||||
exists, err := storage.Exists(client, storageName, applicationName)
|
||||
odoutil.CheckError(err, "unable to check if the storage exists in the current application")
|
||||
if !exists {
|
||||
fmt.Printf("The storage %v does not exists in the current application '%v'", storageName, applicationName)
|
||||
os.Exit(1)
|
||||
}
|
||||
isMounted, err := storage.IsMounted(client, storageName, componentName, applicationName)
|
||||
odoutil.CheckError(err, "unable to check if the component is already mounted or not")
|
||||
if isMounted {
|
||||
fmt.Printf("The storage %v is already mounted on the current component '%v'\n", storageName, componentName)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = storage.Mount(client, storagePath, storageName, componentName, applicationName)
|
||||
odoutil.CheckError(err, "")
|
||||
fmt.Printf("The storage %v is successfully mounted to the current component '%v'\n", storageName, componentName)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
storageCreateCmd.Flags().StringVar(&storageSize, "size", "", "Size of storage to add")
|
||||
storageCreateCmd.Flags().StringVar(&storagePath, "path", "", "Path to mount the storage on")
|
||||
storageCreateCmd.MarkFlagRequired("path")
|
||||
storageCreateCmd.MarkFlagRequired("size")
|
||||
|
||||
storageDeleteCmd.Flags().BoolVarP(&storageForceDeleteflag, "force", "f", false, "Delete storage without prompting")
|
||||
|
||||
storageListCmd.Flags().BoolVarP(&storageAllListflag, "all", "a", false, "List all storage in all components")
|
||||
|
||||
storageMountCmd.Flags().StringVar(&storagePath, "path", "", "Path to mount the storage on")
|
||||
storageMountCmd.MarkFlagRequired("path")
|
||||
|
||||
storageCmd.AddCommand(storageCreateCmd)
|
||||
storageCmd.AddCommand(storageDeleteCmd)
|
||||
storageCmd.AddCommand(storageUnmountCmd)
|
||||
storageCmd.AddCommand(storageListCmd)
|
||||
storageCmd.AddCommand(storageMountCmd)
|
||||
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(storageCreateCmd)
|
||||
addProjectFlag(storageDeleteCmd)
|
||||
addProjectFlag(storageListCmd)
|
||||
addProjectFlag(storageMountCmd)
|
||||
addProjectFlag(storageUnmountCmd)
|
||||
|
||||
//Adding `--application` flag
|
||||
addApplicationFlag(storageCreateCmd)
|
||||
addApplicationFlag(storageDeleteCmd)
|
||||
addApplicationFlag(storageListCmd)
|
||||
addApplicationFlag(storageMountCmd)
|
||||
addApplicationFlag(storageUnmountCmd)
|
||||
|
||||
//Adding `--component` flag
|
||||
addComponentFlag(storageCreateCmd)
|
||||
addComponentFlag(storageDeleteCmd)
|
||||
addComponentFlag(storageListCmd)
|
||||
addComponentFlag(storageMountCmd)
|
||||
addComponentFlag(storageUnmountCmd)
|
||||
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
storageCmd.Annotations = map[string]string{"command": "other"}
|
||||
storageCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
rootCmd.AddCommand(storageCmd)
|
||||
|
||||
completion.RegisterCommandHandler(storageDeleteCmd, completion.StorageDeleteCompletionHandler)
|
||||
completion.RegisterCommandHandler(storageMountCmd, completion.StorageMountCompletionHandler)
|
||||
completion.RegisterCommandHandler(storageUnmountCmd, completion.StorageUnMountCompletionHandler)
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// terminalCmd represents the terminal command
|
||||
var terminalCmd = &cobra.Command{
|
||||
Use: "terminal",
|
||||
Short: "Add Odo terminal support to your development environment",
|
||||
Long: `Add Odo terminal support to your development environment.
|
||||
|
||||
This will append your PS1 environment variable with Odo component and application information.`,
|
||||
Example: ` # Bash terminal PS1 support
|
||||
source <(odo utils terminal bash)
|
||||
|
||||
# Zsh terminal PS1 support
|
||||
source <(odo utils terminal zsh)
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
err := TerminalGenerate(os.Stdout, cmd, args)
|
||||
util.CheckError(err, "")
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// Generates the PS1 output for Odo terminal support (appends to current PS1 environment variable)
|
||||
func TerminalGenerate(out io.Writer, cmd *cobra.Command, args []string) error {
|
||||
// Check the passed in arguments
|
||||
if len(args) == 0 {
|
||||
return fmt.Errorf("Shell not specified. ex. odo completion [bash|zsh]")
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("Too many arguments. Expected only the shell type. ex. odo completion [bash|zsh]")
|
||||
}
|
||||
shell := args[0]
|
||||
|
||||
// sh function for retrieving component information
|
||||
var PS1 = `
|
||||
__odo_ps1() {
|
||||
|
||||
# Get application context
|
||||
APP=$(odo application get -q --skip-connection-check)
|
||||
|
||||
if [ "$APP" = "" ]; then
|
||||
APP="<no application>"
|
||||
fi
|
||||
|
||||
# Get current context
|
||||
COMPONENT=$(odo component get -q --skip-connection-check)
|
||||
|
||||
if [ "$COMPONENT" = "" ]; then
|
||||
COMPONENT="<no component>"
|
||||
fi
|
||||
|
||||
if [ -n "$COMPONENT" ] || [ -n "$APP" ]; then
|
||||
echo "[${APP}/${COMPONENT}]"
|
||||
fi
|
||||
}
|
||||
`
|
||||
|
||||
// Bash output
|
||||
var bashPS1Output = PS1 + `
|
||||
PS1='$(__odo_ps1)'$PS1
|
||||
`
|
||||
|
||||
// Zsh output
|
||||
var zshPS1Output = PS1 + `
|
||||
setopt prompt_subst
|
||||
PROMPT='$(__odo_ps1)'$PROMPT
|
||||
`
|
||||
|
||||
if shell == "bash" {
|
||||
out.Write([]byte(bashPS1Output))
|
||||
} else if shell == "zsh" {
|
||||
out.Write([]byte(zshPS1Output))
|
||||
} else {
|
||||
return fmt.Errorf("not a compatible shell, bash and zsh are only supported")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
118
cmd/update.go
118
cmd/update.go
@@ -1,118 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var updateCmd = &cobra.Command{
|
||||
Use: "update",
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Short: "Update the source code path of a component",
|
||||
Long: "Update the source code path of a component",
|
||||
Example: ` # Change the source code path of a currently active component to local (use the current directory as a source)
|
||||
odo update --local
|
||||
|
||||
# Change the source code path of the frontend component to local with source in ./frontend directory
|
||||
odo update frontend --local ./frontend
|
||||
|
||||
# Change the source code path of a currently active component to git
|
||||
odo update --git https://github.com/openshift/nodejs-ex.git
|
||||
|
||||
# Change the source code path of the component named node-ex to git
|
||||
odo update node-ex --git https://github.com/openshift/nodejs-ex.git
|
||||
|
||||
# Change the source code path of the component named wildfly to a binary named sample.war in ./downloads directory
|
||||
odo update wildfly --binary ./downloads/sample.war
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
|
||||
stdout := color.Output
|
||||
|
||||
checkFlag := 0
|
||||
|
||||
if len(componentBinary) != 0 {
|
||||
checkFlag++
|
||||
}
|
||||
if len(componentGit) != 0 {
|
||||
checkFlag++
|
||||
}
|
||||
if len(componentLocal) != 0 {
|
||||
checkFlag++
|
||||
}
|
||||
|
||||
if checkFlag != 1 {
|
||||
fmt.Println("The source can be either --binary or --local or --git")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var componentName string
|
||||
if len(args) == 0 {
|
||||
componentName = context.Component()
|
||||
} else {
|
||||
componentName = context.Component(args[0])
|
||||
}
|
||||
|
||||
if len(applicationName) == 0 {
|
||||
fmt.Println("Cannot update as no application is set as active")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if len(componentGit) != 0 {
|
||||
err := component.Update(client, componentName, applicationName, "git", componentGit, stdout)
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf("The component %s was updated successfully\n", componentName)
|
||||
} else if len(componentLocal) != 0 {
|
||||
// we want to use and save absolute path for component
|
||||
dir, err := filepath.Abs(componentLocal)
|
||||
util.CheckError(err, "")
|
||||
fileInfo, err := os.Stat(dir)
|
||||
util.CheckError(err, "")
|
||||
if !fileInfo.IsDir() {
|
||||
fmt.Println("Please provide a path to the directory")
|
||||
os.Exit(1)
|
||||
}
|
||||
err = component.Update(client, componentName, applicationName, "local", dir, stdout)
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf("The component %s was updated successfully, please use 'odo push' to push your local changes\n", componentName)
|
||||
} else if len(componentBinary) != 0 {
|
||||
path, err := filepath.Abs(componentBinary)
|
||||
util.CheckError(err, "")
|
||||
err = component.Update(client, componentName, applicationName, "binary", path, stdout)
|
||||
util.CheckError(err, "")
|
||||
fmt.Printf("The component %s was updated successfully, please use 'odo push' to push your local changes\n", componentName)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
updateCmd.Flags().StringVarP(&componentBinary, "binary", "b", "", "binary artifact")
|
||||
updateCmd.Flags().StringVarP(&componentGit, "git", "g", "", "git source")
|
||||
updateCmd.Flags().StringVarP(&componentLocal, "local", "l", "", "Use local directory as a source for component.")
|
||||
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
updateCmd.Annotations = map[string]string{"command": "component"}
|
||||
updateCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
//Adding `--application` flag
|
||||
addApplicationFlag(updateCmd)
|
||||
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(updateCmd)
|
||||
|
||||
completion.RegisterCommandFlagHandler(updateCmd, "local", completion.FileCompletionHandler)
|
||||
completion.RegisterCommandFlagHandler(updateCmd, "binary", completion.FileCompletionHandler)
|
||||
|
||||
rootCmd.AddCommand(updateCmd)
|
||||
}
|
||||
206
cmd/url.go
206
cmd/url.go
@@ -1,206 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util/completion"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
odoutil "github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/url"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
urlForceDeleteFlag bool
|
||||
urlOpenFlag bool
|
||||
urlPort int
|
||||
)
|
||||
|
||||
var urlCmd = &cobra.Command{
|
||||
Use: "url",
|
||||
Short: "Expose component to the outside world",
|
||||
Long: `Expose component to the outside world.
|
||||
|
||||
The URLs that are generated using this command, can be used to access the deployed components from outside the cluster.`,
|
||||
Example: fmt.Sprintf("%s\n%s\n%s",
|
||||
urlCreateCmd.Example,
|
||||
urlDeleteCmd.Example,
|
||||
urlListCmd.Example),
|
||||
}
|
||||
|
||||
var urlCreateCmd = &cobra.Command{
|
||||
Use: "create [component name]",
|
||||
Short: "Create a URL for a component",
|
||||
Long: `Create a URL for a component.
|
||||
|
||||
The created URL can be used to access the specified component from outside the OpenShift cluster.
|
||||
`,
|
||||
Example: ` # Create a URL for the current component with a specific port
|
||||
odo url create --port 8080
|
||||
|
||||
# Create a URL with a specific name and port
|
||||
odo url create example --port 8080
|
||||
|
||||
# Create a URL with a specific name by automatic detection of port (only for components which expose only one service port)
|
||||
odo url create example
|
||||
|
||||
# Create a URL with a specific name and port for component frontend
|
||||
odo url create example --port 8080 --component frontend
|
||||
`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
componentName := context.Component()
|
||||
|
||||
var urlName string
|
||||
switch len(args) {
|
||||
case 0:
|
||||
urlName = componentName
|
||||
case 1:
|
||||
urlName = args[0]
|
||||
default:
|
||||
fmt.Println("unable to get component")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
exists, err := url.Exists(client, urlName, "", applicationName)
|
||||
|
||||
if exists {
|
||||
fmt.Printf("The url %s already exists in the application: %s\n", urlName, applicationName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("Adding URL to component: %v\n", componentName)
|
||||
urlRoute, err := url.Create(client, urlName, urlPort, componentName, applicationName)
|
||||
odoutil.CheckError(err, "")
|
||||
|
||||
urlCreated := url.GetUrlString(*urlRoute)
|
||||
fmt.Printf("URL created for component: %v\n\n"+
|
||||
"%v - %v\n", componentName, urlRoute.Name, urlCreated)
|
||||
|
||||
if urlOpenFlag {
|
||||
err := util.OpenBrowser(urlCreated)
|
||||
odoutil.CheckError(err, "Unable to open URL within default browser")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var urlDeleteCmd = &cobra.Command{
|
||||
Use: "delete <url-name>",
|
||||
Short: "Delete a URL",
|
||||
Long: `Delete the given URL, hence making the service inaccessible.`,
|
||||
Example: ` # Delete a URL to a component
|
||||
odo url delete myurl
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
componentName := context.Component()
|
||||
|
||||
urlName := args[0]
|
||||
|
||||
exists, err := url.Exists(client, urlName, componentName, applicationName)
|
||||
odoutil.CheckError(err, "")
|
||||
|
||||
if !exists {
|
||||
fmt.Printf("The URL %s does not exist within the component %s\n", urlName, componentName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var confirmDeletion string
|
||||
if urlForceDeleteFlag {
|
||||
confirmDeletion = "y"
|
||||
} else {
|
||||
fmt.Printf("Are you sure you want to delete the url %v? [y/N] ", urlName)
|
||||
fmt.Scanln(&confirmDeletion)
|
||||
}
|
||||
|
||||
if strings.ToLower(confirmDeletion) == "y" {
|
||||
|
||||
err = url.Delete(client, urlName, applicationName)
|
||||
odoutil.CheckError(err, "")
|
||||
fmt.Printf("Deleted URL: %v\n", urlName)
|
||||
} else {
|
||||
fmt.Printf("Aborting deletion of url: %v\n", urlName)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var urlListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List URLs",
|
||||
Long: `Lists all the available URLs which can be used to access the components.`,
|
||||
Example: ` # List the available URLs
|
||||
odo url list
|
||||
`,
|
||||
Args: cobra.ExactArgs(0),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
applicationName := context.Application
|
||||
componentName := context.Component()
|
||||
|
||||
urls, err := url.List(client, componentName, applicationName)
|
||||
odoutil.CheckError(err, "")
|
||||
|
||||
if len(urls) == 0 {
|
||||
fmt.Printf("No URLs found for component %v in application %v\n", componentName, applicationName)
|
||||
} else {
|
||||
fmt.Printf("Found the following URLs for component %v in application %v:\n", componentName, applicationName)
|
||||
|
||||
tabWriterURL := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent)
|
||||
|
||||
//create headers
|
||||
fmt.Fprintln(tabWriterURL, "NAME", "\t", "URL", "\t", "PORT")
|
||||
|
||||
for _, u := range urls {
|
||||
fmt.Fprintln(tabWriterURL, u.Name, "\t", url.GetUrlString(u), "\t", u.Port)
|
||||
}
|
||||
tabWriterURL.Flush()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
urlCreateCmd.Flags().IntVarP(&urlPort, "port", "", -1, "port number for the url of the component, required in case of components which expose more than one service port")
|
||||
urlCreateCmd.Flags().BoolVar(&urlOpenFlag, "open", false, "open the created link with your default browser")
|
||||
|
||||
urlDeleteCmd.Flags().BoolVarP(&urlForceDeleteFlag, "force", "f", false, "Delete url without prompting")
|
||||
|
||||
urlCmd.AddCommand(urlListCmd)
|
||||
urlCmd.AddCommand(urlDeleteCmd)
|
||||
urlCmd.AddCommand(urlCreateCmd)
|
||||
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
urlCmd.Annotations = map[string]string{"command": "other"}
|
||||
urlCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(urlListCmd)
|
||||
addProjectFlag(urlCreateCmd)
|
||||
addProjectFlag(urlDeleteCmd)
|
||||
|
||||
//Adding `--application` flag
|
||||
addApplicationFlag(urlListCmd)
|
||||
addApplicationFlag(urlDeleteCmd)
|
||||
addApplicationFlag(urlCreateCmd)
|
||||
|
||||
//Adding `--component` flag
|
||||
addComponentFlag(urlDeleteCmd)
|
||||
addComponentFlag(urlListCmd)
|
||||
addComponentFlag(urlCreateCmd)
|
||||
|
||||
rootCmd.AddCommand(urlCmd)
|
||||
|
||||
completion.RegisterCommandHandler(urlDeleteCmd, completion.URLCompletionHandler)
|
||||
}
|
||||
31
cmd/utils.go
31
cmd/utils.go
@@ -1,31 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// utilsCmd represents the utils command
|
||||
var utilsCmd = &cobra.Command{
|
||||
Use: "utils",
|
||||
Short: "Utilities for terminal commands and modifying Odo configurations",
|
||||
Long: `Utilities for terminal commands and modifying Odo configurations`,
|
||||
Example: fmt.Sprintf("%s\n%s\n%s",
|
||||
terminalCmd.Example,
|
||||
configurationSetCmd.Example,
|
||||
configurationViewCmd.Example),
|
||||
}
|
||||
|
||||
func init() {
|
||||
utilsCmd.Annotations = map[string]string{"command": "utility"}
|
||||
utilsCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
configurationCmd.AddCommand(configurationViewCmd)
|
||||
configurationCmd.AddCommand(configurationSetCmd)
|
||||
|
||||
configurationCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
utilsCmd.AddCommand(configurationCmd)
|
||||
utilsCmd.AddCommand(terminalCmd)
|
||||
rootCmd.AddCommand(utilsCmd)
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"github.com/redhat-developer/odo/pkg/odo/util"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// VERSION is version number that will be displayed when running ./odo version
|
||||
VERSION = "v0.0.16"
|
||||
|
||||
// GITCOMMIT is hash of the commit that wil be displayed when running ./odo version
|
||||
// this will be overwritten when running build like this: go build -ldflags="-X github.com/redhat-developer/odo/cmd.GITCOMMIT=$(GITCOMMIT)"
|
||||
// HEAD is default indicating that this was not set during build
|
||||
GITCOMMIT = "HEAD"
|
||||
)
|
||||
|
||||
var clientFlag bool
|
||||
|
||||
// versionCmd represents the version command
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print the client version information",
|
||||
Long: "Print the client version information",
|
||||
Example: ` # Print the client version of Odo
|
||||
odo version
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
// If verbose mode is enabled, dump all KUBECLT_* env variables
|
||||
// this is usefull for debuging oc plugin integration
|
||||
for _, v := range os.Environ() {
|
||||
if strings.HasPrefix(v, "KUBECTL_") {
|
||||
glog.V(4).Info(v)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("odo " + VERSION + " (" + GITCOMMIT + ")")
|
||||
|
||||
if !clientFlag {
|
||||
// Lets fetch the info about the server
|
||||
serverInfo, err := genericclioptions.ClientWithConnectionCheck(cmd, true).GetServerVersion()
|
||||
util.CheckError(err, "")
|
||||
// make sure we only include Openshift info if we actually have it
|
||||
openshiftStr := ""
|
||||
if len(serverInfo.OpenShiftVersion) > 0 {
|
||||
openshiftStr = fmt.Sprintf("OpenShift: %v\n", serverInfo.OpenShiftVersion)
|
||||
}
|
||||
fmt.Printf("\n"+
|
||||
"Server: %v\n"+
|
||||
"%v"+
|
||||
"Kubernetes: %v\n",
|
||||
serverInfo.Address,
|
||||
openshiftStr,
|
||||
serverInfo.KubernetesVersion)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
versionCmd.Annotations = map[string]string{"command": "utility"}
|
||||
versionCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
versionCmd.Flags().BoolVar(&clientFlag, "client", false, "Client version only (no server required).")
|
||||
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
}
|
||||
96
cmd/watch.go
96
cmd/watch.go
@@ -1,96 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/redhat-developer/odo/pkg/odo/genericclioptions"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
odoutil "github.com/redhat-developer/odo/pkg/odo/util"
|
||||
|
||||
"github.com/redhat-developer/odo/pkg/component"
|
||||
"github.com/redhat-developer/odo/pkg/util"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
ignores []string
|
||||
delay int
|
||||
)
|
||||
|
||||
var watchCmd = &cobra.Command{
|
||||
Use: "watch [component name]",
|
||||
Short: "Watch for changes, update component on change",
|
||||
Long: `Watch for changes, update component on change.`,
|
||||
Example: ` # Watch for changes in directory for current component
|
||||
odo watch
|
||||
|
||||
# Watch for changes in directory for component called frontend
|
||||
odo watch frontend
|
||||
`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
stdout := os.Stdout
|
||||
context := genericclioptions.NewContext(cmd)
|
||||
client := context.Client
|
||||
projectName := context.Project
|
||||
applicationName := context.Application
|
||||
|
||||
// TODO: check if we can use context.Component() here
|
||||
var componentName string
|
||||
if len(args) == 0 {
|
||||
var err error
|
||||
glog.V(4).Info("No component name passed, assuming current component")
|
||||
componentName, err = component.GetCurrent(applicationName, projectName)
|
||||
odoutil.CheckError(err, "")
|
||||
if componentName == "" {
|
||||
fmt.Println("No component is set as active.")
|
||||
fmt.Println("Use 'odo component set <component name> to set and existing component as active or call this command with component name as and argument.")
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
componentName = args[0]
|
||||
}
|
||||
|
||||
sourceType, sourcePath, err := component.GetComponentSource(client, componentName, applicationName)
|
||||
odoutil.CheckError(err, "Unable to get source for %s component.", componentName)
|
||||
|
||||
if sourceType != "binary" && sourceType != "local" {
|
||||
fmt.Printf("Watch is supported by binary and local components only and source type of component %s is %s\n", componentName, sourceType)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
u, err := url.Parse(sourcePath)
|
||||
odoutil.CheckError(err, "Unable to parse source %s from component %s.", sourcePath, componentName)
|
||||
|
||||
if u.Scheme != "" && u.Scheme != "file" {
|
||||
fmt.Printf("Component %s has invalid source path %s.", componentName, u.Scheme)
|
||||
os.Exit(1)
|
||||
}
|
||||
watchPath := util.ReadFilePath(u, runtime.GOOS)
|
||||
|
||||
err = component.WatchAndPush(client, componentName, applicationName, watchPath, stdout, ignores, delay, make(chan string), component.PushLocal)
|
||||
odoutil.CheckError(err, "Error while trying to watch %s", watchPath)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
// ignore git as it can change even if no source file changed
|
||||
// for example some plugins providing git info in PS1 doing that
|
||||
watchCmd.Flags().StringSliceVar(&ignores, "ignore", []string{".*\\.git.*"}, "Files or folders to be ignored via regular expressions.")
|
||||
watchCmd.Flags().IntVar(&delay, "delay", 1, "Time in seconds between a detection of code change and push.delay=0 means changes will be pushed as soon as they are detected which can cause performance issues")
|
||||
// Add a defined annotation in order to appear in the help menu
|
||||
watchCmd.Annotations = map[string]string{"command": "component"}
|
||||
watchCmd.SetUsageTemplate(cmdUsageTemplate)
|
||||
|
||||
//Adding `--application` flag
|
||||
addApplicationFlag(watchCmd)
|
||||
|
||||
//Adding `--project` flag
|
||||
addProjectFlag(watchCmd)
|
||||
|
||||
rootCmd.AddCommand(watchCmd)
|
||||
}
|
||||
Reference in New Issue
Block a user