pkg/cmd/infra/router/f5.go
7104d31d
 package router
 
 import (
 	"errors"
f88e8dc5
 	"fmt"
131728ad
 	"os"
7104d31d
 
5958daa5
 	"github.com/golang/glog"
f88e8dc5
 	"github.com/spf13/cobra"
7104d31d
 	"github.com/spf13/pflag"
 
f88e8dc5
 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 
131728ad
 	ocmd "github.com/openshift/origin/pkg/cmd/cli/cmd"
6267dded
 	"github.com/openshift/origin/pkg/cmd/templates"
7104d31d
 	"github.com/openshift/origin/pkg/cmd/util"
f88e8dc5
 	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
90e3620d
 	"github.com/openshift/origin/pkg/router/controller"
a398a60d
 	f5plugin "github.com/openshift/origin/pkg/router/f5"
7104d31d
 )
 
6267dded
 var (
 	f5Long = templates.LongDesc(`
 		Start an F5 route synchronizer
f88e8dc5
 
6267dded
 		This command launches a process that will synchronize an F5 to the route configuration of your master.
30f5837b
 
6267dded
 		You may restrict the set of routes exposed to a single project (with --namespace), projects your client has
 		access to with a set of labels (--project-labels), namespaces matching a label (--namespace-labels), or all
 		namespaces (no argument). You can limit the routes to those matching a --labels or --fields selector. Note
 		that you must have a cluster-wide administrative role to view all namespaces.`)
f88e8dc5
 )
 
 // F5RouterOptions represent the complete structure needed to start an F5 router
 // sync process.
 type F5RouterOptions struct {
 	Config *clientcmd.Config
 
 	F5Router
 	RouterSelection
 }
 
 // F5Router is the config necessary to start an F5 router plugin.
 type F5Router struct {
7d07c18b
 	RouterName string
 
7104d31d
 	// Host specifies the hostname or IP address of the F5 BIG-IP host.
 	Host string
 
 	// Username specifies the username with which the plugin should authenticate
 	// with the F5 BIG-IP host.
 	Username string
 
 	// Password specifies the password with which the plugin should authenticate
 	// with the F5 BIG-IP host.
 	Password string
 
 	// HttpVserver specifies the name of the vserver object in F5 BIG-IP that the
 	// plugin will configure for HTTP connections.
 	HttpVserver string
 
 	// HttpsVserver specifies the name of the vserver object in F5 BIG-IP that the
 	// plugin will configure for HTTPS connections.
 	HttpsVserver string
 
 	// PrivateKey specifies the filename of an SSH private key for
 	// authenticating with F5.  This key is required to copy certificates
 	// to the F5 BIG-IP host.
 	PrivateKey string
 
 	// Insecure specifies whether the F5 plugin should perform strict certificate
 	// validation for connections to the F5 BIG-IP host.
 	Insecure bool
5958daa5
 
2eabbdc5
 	// PartitionPath specifies the path to the F5 partition. This is
5958daa5
 	// normally used to create access control boundaries for users
 	// and applications.
 	PartitionPath string
7104d31d
 }
 
f88e8dc5
 // Bind binds F5Router arguments to flags
 func (o *F5Router) Bind(flag *pflag.FlagSet) {
7d07c18b
 	flag.StringVar(&o.RouterName, "name", util.Env("ROUTER_SERVICE_NAME", "public"), "The name the router will identify itself with in the route status")
f88e8dc5
 	flag.StringVar(&o.Host, "f5-host", util.Env("ROUTER_EXTERNAL_HOST_HOSTNAME", ""), "The host of F5 BIG-IP's management interface")
 	flag.StringVar(&o.Username, "f5-username", util.Env("ROUTER_EXTERNAL_HOST_USERNAME", ""), "The username for F5 BIG-IP's management utility")
 	flag.StringVar(&o.Password, "f5-password", util.Env("ROUTER_EXTERNAL_HOST_PASSWORD", ""), "The password for F5 BIG-IP's management utility")
 	flag.StringVar(&o.HttpVserver, "f5-http-vserver", util.Env("ROUTER_EXTERNAL_HOST_HTTP_VSERVER", "ose-vserver"), "The F5 BIG-IP virtual server for HTTP connections")
 	flag.StringVar(&o.HttpsVserver, "f5-https-vserver", util.Env("ROUTER_EXTERNAL_HOST_HTTPS_VSERVER", "https-ose-vserver"), "The F5 BIG-IP virtual server for HTTPS connections")
 	flag.StringVar(&o.PrivateKey, "f5-private-key", util.Env("ROUTER_EXTERNAL_HOST_PRIVKEY", ""), "The path to the F5 BIG-IP SSH private key file")
 	flag.BoolVar(&o.Insecure, "f5-insecure", util.Env("ROUTER_EXTERNAL_HOST_INSECURE", "") == "true", "Skip strict certificate verification")
2eabbdc5
 	flag.StringVar(&o.PartitionPath, "f5-partition-path", util.Env("ROUTER_EXTERNAL_HOST_PARTITION_PATH", f5plugin.F5DefaultPartitionPath), "The F5 BIG-IP partition path to use")
7104d31d
 }
 
f88e8dc5
 // Validate verifies the required F5 flags are present
 func (o *F5Router) Validate() error {
 	if o.Host == "" {
 		return errors.New("F5 host must be specified")
 	}
 
 	if o.Username == "" {
 		return errors.New("F5 username must be specified")
7104d31d
 	}
 
f88e8dc5
 	if o.Password == "" {
 		return errors.New("F5 password must be specified")
7104d31d
 	}
 
f88e8dc5
 	if len(o.HttpVserver) == 0 && len(o.HttpsVserver) == 0 {
 		return errors.New("F5 HTTP and HTTPS vservers cannot both be blank")
 	}
5958daa5
 
f88e8dc5
 	return nil
 }
 
a064a461
 // NewCommandF5Router provides CLI handler for the F5 router sync plugin.
f88e8dc5
 func NewCommandF5Router(name string) *cobra.Command {
 	options := &F5RouterOptions{
 		Config: clientcmd.NewConfig(),
7104d31d
 	}
f88e8dc5
 	options.Config.FromFile = true
 
 	cmd := &cobra.Command{
 		Use:   fmt.Sprintf("%s%s", name, clientcmd.ConfigSyntax),
 		Short: "Start an F5 route synchronizer",
 		Long:  f5Long,
 		Run: func(c *cobra.Command, args []string) {
 			options.RouterSelection.Namespace = cmdutil.GetFlagString(c, "namespace")
 			cmdutil.CheckErr(options.Complete())
 			cmdutil.CheckErr(options.Validate())
 			cmdutil.CheckErr(options.Run())
 		},
 	}
 
131728ad
 	cmd.AddCommand(ocmd.NewCmdVersion(name, nil, os.Stdout, ocmd.VersionOptions{}))
f88e8dc5
 
 	flag := cmd.Flags()
 	options.Config.Bind(flag)
a064a461
 	options.F5Router.Bind(flag)
f88e8dc5
 	options.RouterSelection.Bind(flag)
 
 	return cmd
 }
 
 func (o *F5RouterOptions) Complete() error {
5958daa5
 	if len(o.PartitionPath) == 0 {
 		o.PartitionPath = f5plugin.F5DefaultPartitionPath
 		glog.Warningf("Partition path was empty, using default: %q",
 			f5plugin.F5DefaultPartitionPath)
 	}
 
f88e8dc5
 	return o.RouterSelection.Complete()
 }
 
 func (o *F5RouterOptions) Validate() error {
 	return o.F5Router.Validate()
 }
7104d31d
 
f88e8dc5
 // Run launches an F5 route sync process using the provided options. It never exits.
 func (o *F5RouterOptions) Run() error {
 	cfg := f5plugin.F5PluginConfig{
5958daa5
 		Host:          o.Host,
 		Username:      o.Username,
 		Password:      o.Password,
 		HttpVserver:   o.HttpVserver,
 		HttpsVserver:  o.HttpsVserver,
 		PrivateKey:    o.PrivateKey,
 		Insecure:      o.Insecure,
 		PartitionPath: o.PartitionPath,
f88e8dc5
 	}
90e3620d
 	f5Plugin, err := f5plugin.NewF5Plugin(cfg)
f88e8dc5
 	if err != nil {
 		return err
7104d31d
 	}
 
f88e8dc5
 	oc, kc, err := o.Config.Clients()
 	if err != nil {
 		return err
7104d31d
 	}
f88e8dc5
 
7d07c18b
 	statusPlugin := controller.NewStatusAdmitter(f5Plugin, oc, o.RouterName)
 	plugin := controller.NewUniqueHost(statusPlugin, o.RouteSelectionFunc(), statusPlugin)
 
f88e8dc5
 	factory := o.RouterSelection.NewFactory(oc, kc)
 	controller := factory.Create(plugin)
 	controller.Run()
 
 	select {}
7104d31d
 }