2015-02-17 21:31:37 +00:00
|
|
|
package control
|
|
|
|
|
|
|
|
import (
|
2017-03-03 04:02:44 +00:00
|
|
|
"fmt"
|
2015-02-17 21:31:37 +00:00
|
|
|
"os"
|
2017-03-04 13:15:10 +00:00
|
|
|
"sort"
|
2015-02-17 21:31:37 +00:00
|
|
|
|
2017-03-03 04:02:44 +00:00
|
|
|
yaml "github.com/cloudfoundry-incubator/candiedyaml"
|
|
|
|
|
2015-02-17 21:31:37 +00:00
|
|
|
"github.com/codegangsta/cli"
|
2017-03-04 13:15:10 +00:00
|
|
|
composeApp "github.com/docker/libcompose/cli/app"
|
2017-03-03 04:02:44 +00:00
|
|
|
libcomposeConfig "github.com/docker/libcompose/config"
|
2017-03-04 13:15:10 +00:00
|
|
|
serviceApp "github.com/rancher/os/cmd/control/service/app"
|
2017-03-03 04:02:44 +00:00
|
|
|
|
2016-10-22 04:17:40 +00:00
|
|
|
"github.com/rancher/os/cmd/control/service"
|
2017-03-04 13:15:10 +00:00
|
|
|
|
2015-10-12 11:50:17 +00:00
|
|
|
"github.com/rancher/os/config"
|
2016-11-23 10:49:35 +00:00
|
|
|
"github.com/rancher/os/log"
|
2017-03-03 04:02:44 +00:00
|
|
|
"github.com/rancher/os/util/network"
|
2015-02-17 21:31:37 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func Main() {
|
2016-11-23 10:49:35 +00:00
|
|
|
log.InitLogger()
|
2015-02-17 21:31:37 +00:00
|
|
|
app := cli.NewApp()
|
|
|
|
|
|
|
|
app.Name = os.Args[0]
|
|
|
|
app.Usage = "Control and configure RancherOS"
|
2016-11-28 08:06:00 +00:00
|
|
|
app.Version = config.Version
|
2015-02-17 21:31:37 +00:00
|
|
|
app.Author = "Rancher Labs, Inc."
|
2015-02-23 03:56:25 +00:00
|
|
|
app.EnableBashCompletion = true
|
2016-03-16 09:48:57 +00:00
|
|
|
app.Before = func(c *cli.Context) error {
|
|
|
|
if os.Geteuid() != 0 {
|
|
|
|
log.Fatalf("%s: Need to be root", os.Args[0])
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2015-02-17 21:31:37 +00:00
|
|
|
|
2017-03-13 05:57:57 +00:00
|
|
|
//factory := &service.ProjectFactory{}
|
|
|
|
|
|
|
|
app.Commands = []cli.Command{}
|
|
|
|
app.Commands = append(app.Commands, originalCli...)
|
|
|
|
app.Commands = append(app.Commands, hiddenInternalCommands...)
|
|
|
|
|
|
|
|
app.Run(os.Args)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewMain() {
|
|
|
|
log.InitLogger()
|
|
|
|
app := cli.NewApp()
|
|
|
|
|
|
|
|
app.Name = os.Args[0]
|
|
|
|
app.Usage = "Control and configure RancherOS"
|
|
|
|
app.Version = config.Version
|
|
|
|
app.Author = "Rancher Labs, Inc."
|
|
|
|
app.EnableBashCompletion = true
|
|
|
|
app.Before = func(c *cli.Context) error {
|
|
|
|
if os.Geteuid() != 0 {
|
|
|
|
log.Fatalf("%s: Need to be root", os.Args[0])
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-03-04 13:15:10 +00:00
|
|
|
factory := &service.ProjectFactory{}
|
|
|
|
|
2015-02-17 21:31:37 +00:00
|
|
|
app.Commands = []cli.Command{
|
2016-10-17 21:47:44 +00:00
|
|
|
{
|
2017-03-03 04:02:44 +00:00
|
|
|
Name: "fetch",
|
|
|
|
ShortName: "f",
|
|
|
|
Usage: "fetch configs from repos",
|
|
|
|
HideHelp: true,
|
|
|
|
Action: fetchServices,
|
2015-07-21 07:56:55 +00:00
|
|
|
},
|
2017-03-03 04:02:44 +00:00
|
|
|
// service
|
2016-10-20 18:58:34 +00:00
|
|
|
{
|
2017-03-03 04:02:44 +00:00
|
|
|
Name: "list",
|
|
|
|
ShortName: "",
|
|
|
|
Usage: "list services and states",
|
|
|
|
HideHelp: true,
|
|
|
|
Action: listServices,
|
|
|
|
}, {
|
2017-03-06 02:52:52 +00:00
|
|
|
Name: "install",
|
2017-03-04 13:15:10 +00:00
|
|
|
// TODO: add an --apply or --up ...
|
|
|
|
// TODO: also support the repo-name prefix
|
2017-03-03 04:02:44 +00:00
|
|
|
ShortName: "",
|
|
|
|
Usage: "install/upgrade service / RancherOS",
|
|
|
|
HideHelp: true,
|
2017-03-04 13:15:10 +00:00
|
|
|
Action: service.Enable,
|
2017-03-06 02:52:52 +00:00
|
|
|
Flags: []cli.Flag{
|
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "apply",
|
|
|
|
Usage: "Switch console/engine, or start service.",
|
|
|
|
},
|
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "force",
|
|
|
|
Usage: "Don't ask questions.",
|
|
|
|
},
|
|
|
|
},
|
2017-03-03 04:02:44 +00:00
|
|
|
}, {
|
2017-03-06 02:52:52 +00:00
|
|
|
Name: "remove",
|
2017-03-03 04:02:44 +00:00
|
|
|
ShortName: "",
|
|
|
|
Usage: "remove service",
|
|
|
|
HideHelp: true,
|
2017-03-04 13:15:10 +00:00
|
|
|
Action: service.Del,
|
2017-03-03 04:02:44 +00:00
|
|
|
}, {
|
2017-03-06 02:52:52 +00:00
|
|
|
Name: "logs",
|
2017-03-04 13:15:10 +00:00
|
|
|
Usage: "View output from containers",
|
|
|
|
//Before: verifyOneOrMoreServices,
|
|
|
|
Action: composeApp.WithProject(factory, serviceApp.ProjectLog),
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
cli.IntFlag{
|
|
|
|
Name: "lines",
|
|
|
|
Usage: "number of lines to tail",
|
|
|
|
Value: 100,
|
|
|
|
},
|
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "follow",
|
|
|
|
Usage: "Follow log output.",
|
|
|
|
},
|
|
|
|
},
|
2016-10-20 18:58:34 +00:00
|
|
|
},
|
2017-03-04 13:15:10 +00:00
|
|
|
// settings / partial configs
|
2016-08-15 22:06:26 +00:00
|
|
|
{
|
2017-03-04 13:15:10 +00:00
|
|
|
Name: "get",
|
|
|
|
// TODO: also add the merge command functionality
|
2017-03-03 04:02:44 +00:00
|
|
|
ShortName: "",
|
|
|
|
Usage: "get config value(s)",
|
|
|
|
HideHelp: true,
|
2017-03-04 13:15:10 +00:00
|
|
|
Action: configGet,
|
2017-03-03 04:02:44 +00:00
|
|
|
}, {
|
|
|
|
Name: "set",
|
|
|
|
ShortName: "",
|
|
|
|
Usage: "set config value(s)",
|
|
|
|
HideHelp: true,
|
2017-03-04 13:15:10 +00:00
|
|
|
Action: configSet,
|
2016-08-15 02:17:24 +00:00
|
|
|
},
|
2017-03-03 04:02:44 +00:00
|
|
|
// complete config
|
2015-04-29 10:32:12 +00:00
|
|
|
{
|
2017-03-04 13:15:10 +00:00
|
|
|
Name: "export",
|
|
|
|
Usage: "export configuration",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
cli.StringFlag{
|
|
|
|
Name: "output, o",
|
|
|
|
Usage: "File to which to save",
|
|
|
|
},
|
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "private, p",
|
|
|
|
Usage: "Include the generated private keys",
|
|
|
|
},
|
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "full, f",
|
|
|
|
Usage: "Export full configuration, including internal and default settings",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: export,
|
|
|
|
}, {
|
|
|
|
Name: "validate",
|
|
|
|
Usage: "validate configuration from stdin",
|
|
|
|
Action: validate,
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
cli.StringFlag{
|
|
|
|
Name: "input, i",
|
|
|
|
Usage: "File from which to read",
|
|
|
|
},
|
|
|
|
},
|
2017-03-03 04:02:44 +00:00
|
|
|
}, {
|
|
|
|
Name: "apply",
|
|
|
|
ShortName: "",
|
|
|
|
Usage: "apply service&config changes",
|
|
|
|
HideHelp: true,
|
|
|
|
Action: dummy,
|
2015-04-29 10:32:12 +00:00
|
|
|
},
|
2015-02-17 21:31:37 +00:00
|
|
|
}
|
2017-03-03 04:02:44 +00:00
|
|
|
app.Commands = append(app.Commands, hiddenInternalCommands...)
|
2015-02-17 21:31:37 +00:00
|
|
|
|
|
|
|
app.Run(os.Args)
|
|
|
|
}
|
2017-03-03 04:02:44 +00:00
|
|
|
|
|
|
|
func dummy(c *cli.Context) error {
|
2017-03-04 13:15:10 +00:00
|
|
|
fmt.Printf("Not implemented yet - use the `ros old` commands for now\n")
|
2017-03-03 04:02:44 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func fetchServices(c *cli.Context) error {
|
|
|
|
// fetch all the index.yml files, and the service.yml files that they refer to
|
|
|
|
// and put into a cache dir.
|
|
|
|
// Q - should there be one dir per index.yml so that you can have more than one service with the same name..
|
|
|
|
|
|
|
|
//TODO: need a --purge
|
|
|
|
//TODO: also need to fetch the rancher/os choices
|
|
|
|
|
|
|
|
return network.FetchAllServices()
|
|
|
|
}
|
|
|
|
|
|
|
|
func listServices(c *cli.Context) error {
|
|
|
|
//get the current cfg, and the make a cfg with all cached services
|
|
|
|
//then iterate through, listing all possible services, and what version is running, vs what version they could run
|
|
|
|
//Can't just merge current cfg and cached services, as we lose service.yml version info
|
2017-03-04 13:15:10 +00:00
|
|
|
|
2017-03-03 04:02:44 +00:00
|
|
|
currentConfig := config.LoadConfig()
|
|
|
|
cachedConfigs := GetAllServices()
|
|
|
|
// TODO: sort them!
|
2017-03-04 13:15:10 +00:00
|
|
|
fmt.Printf("Enabled\n")
|
|
|
|
enabledServices := make([]string, len(currentConfig.Rancher.Services)+len(currentConfig.Rancher.ServicesInclude))
|
|
|
|
i := 0
|
|
|
|
for k, _ := range currentConfig.Rancher.Services {
|
|
|
|
enabledServices[i] = k
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
for k, _ := range currentConfig.Rancher.ServicesInclude {
|
|
|
|
enabledServices[i] = k
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
sort.Strings(enabledServices)
|
|
|
|
for _, serviceName := range enabledServices {
|
|
|
|
// TODO: add running / stopped, error etc state
|
|
|
|
// TODO: separate the volumes out too (they don't need the image listed - list the volumes instead)
|
|
|
|
serviceConfig, _ := currentConfig.Rancher.Services[serviceName]
|
|
|
|
if serviceConfig != nil {
|
|
|
|
fmt.Printf("\t%s: %s\n", serviceName, serviceConfig.Image)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
fmt.Printf("\t%s\n", serviceName)
|
|
|
|
|
|
|
|
}
|
2017-03-03 04:02:44 +00:00
|
|
|
if len(cachedConfigs[serviceName]) > 0 {
|
|
|
|
fmt.Printf("\t\tAlternatives: ")
|
|
|
|
for serviceLongName, _ := range cachedConfigs[serviceName] {
|
|
|
|
fmt.Printf("%s, ", serviceLongName)
|
|
|
|
}
|
|
|
|
fmt.Printf("\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fmt.Printf("Available\n")
|
|
|
|
for serviceName, service := range cachedConfigs {
|
|
|
|
if _, ok := currentConfig.Rancher.Services[serviceName]; ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
for serviceLongName, _ := range service {
|
|
|
|
fmt.Printf("\t%s: %s\n", serviceName, serviceLongName)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetAllServices() map[string]map[string]*libcomposeConfig.ServiceConfigV1 {
|
|
|
|
//result := make(map[string]*libcomposeConfig.ServiceConfig)
|
|
|
|
result := make(map[string]map[string]*libcomposeConfig.ServiceConfigV1)
|
|
|
|
|
|
|
|
cfg := config.LoadConfig()
|
|
|
|
for repoName, _ := range cfg.Rancher.Repositories {
|
|
|
|
indexPath := fmt.Sprintf("%s/index.yml", repoName)
|
|
|
|
//content, err := network.LoadResource(indexPath, false)
|
|
|
|
content, err := network.CacheLookup(indexPath)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Failed to load %s: %v", indexPath, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
services := make(map[string][]string)
|
|
|
|
err = yaml.Unmarshal(content, &services)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Failed to unmarshal %s: %v", indexPath, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
for serviceType, serviceList := range services {
|
|
|
|
for _, serviceLongName := range serviceList {
|
2017-03-06 02:52:52 +00:00
|
|
|
p, err := service.LoadService(repoName, serviceLongName)
|
2017-03-03 04:02:44 +00:00
|
|
|
if err != nil {
|
2017-03-06 02:52:52 +00:00
|
|
|
log.Errorf("Failed to load %s/%s : %v", repoName, serviceLongName, err)
|
2017-03-03 04:02:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// yes, the serviceLongName is really only the yml file name
|
|
|
|
// and each yml file can contain more than one actual service
|
|
|
|
for serviceName, service := range p.Rancher.Services {
|
|
|
|
//service, _ := p.ServiceConfigs.Get(serviceName)
|
|
|
|
n := fmt.Sprintf("%s/%s", repoName, serviceLongName)
|
|
|
|
if result[serviceName] == nil {
|
|
|
|
result[serviceName] = map[string]*libcomposeConfig.ServiceConfigV1{}
|
|
|
|
}
|
|
|
|
result[serviceName][n] = service
|
|
|
|
log.Debugf("loaded %s(%s): %s", n, serviceType, serviceName)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
var originalCli = []cli.Command{
|
|
|
|
{
|
|
|
|
Name: "config",
|
|
|
|
ShortName: "c",
|
|
|
|
Usage: "configure settings",
|
|
|
|
HideHelp: true,
|
|
|
|
Subcommands: configSubcommands(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "console",
|
|
|
|
Usage: "manage which console container is used",
|
|
|
|
HideHelp: true,
|
|
|
|
Subcommands: consoleSubcommands(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "engine",
|
|
|
|
Usage: "manage which Docker engine is used",
|
|
|
|
HideHelp: true,
|
|
|
|
Subcommands: engineSubcommands(),
|
|
|
|
},
|
|
|
|
service.Commands(),
|
|
|
|
{
|
|
|
|
Name: "os",
|
|
|
|
Usage: "operating system upgrade/downgrade",
|
|
|
|
HideHelp: true,
|
|
|
|
Subcommands: osSubcommands(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "tls",
|
|
|
|
Usage: "setup tls configuration",
|
|
|
|
HideHelp: true,
|
|
|
|
Subcommands: tlsConfCommands(),
|
|
|
|
},
|
|
|
|
installCommand,
|
|
|
|
selinuxCommand(),
|
|
|
|
}
|
|
|
|
|
|
|
|
var hiddenInternalCommands = []cli.Command{
|
|
|
|
{
|
|
|
|
Name: "bootstrap",
|
|
|
|
Hidden: true,
|
|
|
|
HideHelp: true,
|
|
|
|
SkipFlagParsing: true,
|
|
|
|
Action: bootstrapAction,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "udev-settle",
|
|
|
|
Hidden: true,
|
|
|
|
HideHelp: true,
|
|
|
|
SkipFlagParsing: true,
|
|
|
|
Action: udevSettleAction,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "user-docker",
|
|
|
|
Hidden: true,
|
|
|
|
HideHelp: true,
|
|
|
|
SkipFlagParsing: true,
|
|
|
|
Action: userDockerAction,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "preload-images",
|
|
|
|
Hidden: true,
|
|
|
|
HideHelp: true,
|
|
|
|
SkipFlagParsing: true,
|
|
|
|
Action: preloadImagesAction,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "switch-console",
|
|
|
|
Hidden: true,
|
|
|
|
HideHelp: true,
|
|
|
|
SkipFlagParsing: true,
|
|
|
|
Action: switchConsoleAction,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "entrypoint",
|
|
|
|
Hidden: true,
|
|
|
|
HideHelp: true,
|
|
|
|
SkipFlagParsing: true,
|
|
|
|
Action: entrypointAction,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "env",
|
|
|
|
Hidden: true,
|
|
|
|
HideHelp: true,
|
|
|
|
SkipFlagParsing: true,
|
|
|
|
Action: envAction,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "console-init",
|
|
|
|
Hidden: true,
|
|
|
|
HideHelp: true,
|
|
|
|
SkipFlagParsing: true,
|
|
|
|
Action: consoleInitAction,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "dev",
|
|
|
|
Hidden: true,
|
|
|
|
HideHelp: true,
|
|
|
|
SkipFlagParsing: true,
|
|
|
|
Action: devAction,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "docker-init",
|
|
|
|
Hidden: true,
|
|
|
|
HideHelp: true,
|
|
|
|
SkipFlagParsing: true,
|
|
|
|
Action: dockerInitAction,
|
|
|
|
},
|
|
|
|
}
|