initial commit
This commit is contained in:
126
cmd/poke/config.go
Normal file
126
cmd/poke/config.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/coreos/poke/connector"
|
||||
"github.com/coreos/poke/connector/github"
|
||||
"github.com/coreos/poke/connector/ldap"
|
||||
"github.com/coreos/poke/connector/mock"
|
||||
"github.com/coreos/poke/storage"
|
||||
"github.com/coreos/poke/storage/kubernetes"
|
||||
)
|
||||
|
||||
// Config is the config format for the main application.
|
||||
type Config struct {
|
||||
Issuer string `yaml:"issuer"`
|
||||
Storage Storage `yaml:"storage"`
|
||||
Connectors []Connector `yaml:"connectors"`
|
||||
Web Web `yaml:"web"`
|
||||
}
|
||||
|
||||
// Web is the config format for the HTTP server.
|
||||
type Web struct {
|
||||
HTTP string `yaml:"http"`
|
||||
HTTPS string `yaml:"https"`
|
||||
TLSCert string `yaml:"tlsCert"`
|
||||
TLSKey string `yaml:"tlsKey"`
|
||||
}
|
||||
|
||||
// Storage holds app's storage configuration.
|
||||
type Storage struct {
|
||||
Type string `yaml:"type"`
|
||||
Config StorageConfig `yaml:"config"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML allows Storage to unmarshal its config field dynamically
|
||||
// depending on the type of storage.
|
||||
func (s *Storage) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var storageMeta struct {
|
||||
Type string `yaml:"type"`
|
||||
}
|
||||
if err := unmarshal(&storageMeta); err != nil {
|
||||
return err
|
||||
}
|
||||
s.Type = storageMeta.Type
|
||||
var c struct {
|
||||
Config StorageConfig `yaml:"config"`
|
||||
}
|
||||
switch storageMeta.Type {
|
||||
case "kubernetes":
|
||||
c.Config = &kubernetes.Config{}
|
||||
default:
|
||||
return fmt.Errorf("unknown storage type %q", storageMeta.Type)
|
||||
}
|
||||
if err := unmarshal(c); err != nil {
|
||||
return err
|
||||
}
|
||||
s.Config = c.Config
|
||||
return nil
|
||||
}
|
||||
|
||||
// StorageConfig is a configuration that can create a storage.
|
||||
type StorageConfig interface {
|
||||
Open() (storage.Storage, error)
|
||||
}
|
||||
|
||||
// Connector is a magical type that can unmarshal YAML dynamically. The
|
||||
// Type field determines the connector type, which is then customized for Config.
|
||||
type Connector struct {
|
||||
Type string `yaml:"type"`
|
||||
Name string `yaml:"name"`
|
||||
ID string `yaml:"id"`
|
||||
|
||||
Config ConnectorConfig `yaml:"config"`
|
||||
}
|
||||
|
||||
// ConnectorConfig is a configuration that can open a connector.
|
||||
type ConnectorConfig interface {
|
||||
Open() (connector.Connector, error)
|
||||
}
|
||||
|
||||
// UnmarshalYAML allows Connector to unmarshal its config field dynamically
|
||||
// depending on the type of connector.
|
||||
func (c *Connector) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var connectorMetadata struct {
|
||||
Type string `yaml:"type"`
|
||||
Name string `yaml:"name"`
|
||||
ID string `yaml:"id"`
|
||||
}
|
||||
if err := unmarshal(&connectorMetadata); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Type = connectorMetadata.Type
|
||||
c.Name = connectorMetadata.Name
|
||||
c.ID = connectorMetadata.ID
|
||||
|
||||
switch c.Type {
|
||||
case "mock":
|
||||
var config struct {
|
||||
Config mock.Config `yaml:"config"`
|
||||
}
|
||||
if err := unmarshal(&config); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Config = &config.Config
|
||||
case "ldap":
|
||||
var config struct {
|
||||
Config ldap.Config `yaml:"config"`
|
||||
}
|
||||
if err := unmarshal(&config); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Config = &config.Config
|
||||
case "github":
|
||||
var config struct {
|
||||
Config github.Config `yaml:"config"`
|
||||
}
|
||||
if err := unmarshal(&config); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Config = &config.Config
|
||||
default:
|
||||
return fmt.Errorf("unknown connector type %q", c.Type)
|
||||
}
|
||||
return nil
|
||||
}
|
1
cmd/poke/init.go
Normal file
1
cmd/poke/init.go
Normal file
@@ -0,0 +1 @@
|
||||
package main
|
28
cmd/poke/poke.go
Normal file
28
cmd/poke/poke.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func commandRoot() *cobra.Command {
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "poke",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmd.Help()
|
||||
os.Exit(2)
|
||||
},
|
||||
}
|
||||
rootCmd.AddCommand(commandServe())
|
||||
rootCmd.AddCommand(commandVersion())
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := commandRoot().Execute(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
111
cmd/poke/serve.go
Normal file
111
cmd/poke/serve.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/coreos/poke/server"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func commandServe() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "serve [ config file ]",
|
||||
Short: "Connect to the storage and begin serving requests.",
|
||||
Long: ``,
|
||||
Example: "poke serve c.yaml",
|
||||
RunE: serve,
|
||||
}
|
||||
}
|
||||
|
||||
func serve(cmd *cobra.Command, args []string) error {
|
||||
switch len(args) {
|
||||
default:
|
||||
return errors.New("surplus arguments")
|
||||
case 0:
|
||||
// TODO(ericchiang): Consider having a default config file location.
|
||||
return errors.New("no config file specified")
|
||||
case 1:
|
||||
}
|
||||
|
||||
configFile := args[0]
|
||||
configData, err := ioutil.ReadFile(configFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read config file %s: %v", configFile, err)
|
||||
}
|
||||
|
||||
var c Config
|
||||
if err := yaml.Unmarshal(configData, &c); err != nil {
|
||||
return fmt.Errorf("parse config file %s: %v", configFile, err)
|
||||
}
|
||||
|
||||
// Fast checks. Perform these first for a more responsive CLI.
|
||||
checks := []struct {
|
||||
bad bool
|
||||
errMsg string
|
||||
}{
|
||||
{c.Issuer == "", "no issuer specified in config file"},
|
||||
{len(c.Connectors) == 0, "no connectors supplied in config file"},
|
||||
{c.Storage.Config == nil, "no storage suppied in config file"},
|
||||
{c.Web.HTTP == "" && c.Web.HTTPS == "", "must supply a HTTP/HTTPS address to listen on"},
|
||||
{c.Web.HTTPS != "" && c.Web.TLSCert == "", "no cert specified for HTTPS"},
|
||||
{c.Web.HTTPS != "" && c.Web.TLSKey == "", "no private key specified for HTTPS"},
|
||||
}
|
||||
|
||||
for _, check := range checks {
|
||||
if check.bad {
|
||||
return errors.New(check.errMsg)
|
||||
}
|
||||
}
|
||||
|
||||
connectors := make([]server.Connector, len(c.Connectors))
|
||||
for i, conn := range c.Connectors {
|
||||
if conn.Config == nil {
|
||||
return fmt.Errorf("no config field for connector %q", conn.ID)
|
||||
}
|
||||
c, err := conn.Config.Open()
|
||||
if err != nil {
|
||||
return fmt.Errorf("open %s: %v", conn.ID, err)
|
||||
}
|
||||
connectors[i] = server.Connector{
|
||||
ID: conn.ID,
|
||||
DisplayName: conn.Name,
|
||||
Connector: c,
|
||||
}
|
||||
}
|
||||
|
||||
s, err := c.Storage.Config.Open()
|
||||
if err != nil {
|
||||
return fmt.Errorf("initializing storage: %v", err)
|
||||
}
|
||||
|
||||
serverConfig := server.Config{
|
||||
Issuer: c.Issuer,
|
||||
Connectors: connectors,
|
||||
Storage: s,
|
||||
}
|
||||
|
||||
serv, err := server.New(serverConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("initializing server: %v", err)
|
||||
}
|
||||
errc := make(chan error, 2)
|
||||
if c.Web.HTTP != "" {
|
||||
go func() {
|
||||
log.Printf("listening on %s", c.Web.HTTP)
|
||||
errc <- http.ListenAndServe(c.Web.HTTP, serv)
|
||||
}()
|
||||
}
|
||||
if c.Web.HTTPS != "" {
|
||||
go func() {
|
||||
log.Printf("listening on %s", c.Web.HTTPS)
|
||||
errc <- http.ListenAndServeTLS(c.Web.HTTPS, c.Web.TLSCert, c.Web.TLSKey, serv)
|
||||
}()
|
||||
}
|
||||
return <-errc
|
||||
}
|
19
cmd/poke/version.go
Normal file
19
cmd/poke/version.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/coreos/poke/version"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func commandVersion() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "version",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Printf(`v%s %s %s %s
|
||||
`, version.Version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||
},
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user