Skip to content

Commit 71cbe30

Browse files
authored
Merge pull request #172 from jrasell/f_gh_124
Addition of scale-out and scale-in commands.
2 parents 20f24e4 + 82f70dc commit 71cbe30

File tree

11 files changed

+569
-29
lines changed

11 files changed

+569
-29
lines changed

Diff for: client/nomad.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package client
2+
3+
import (
4+
nomad "github.com/hashicorp/nomad/api"
5+
)
6+
7+
// NewNomadClient is used to create a new client to interact with Nomad.
8+
func NewNomadClient(addr string) (*nomad.Client, error) {
9+
config := nomad.DefaultConfig()
10+
11+
if addr != "" {
12+
config.Address = addr
13+
}
14+
15+
c, err := nomad.NewClient(config)
16+
if err != nil {
17+
return nil, err
18+
}
19+
20+
return c, nil
21+
}

Diff for: command/deploy.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func (c *DeployCommand) Run(args []string) int {
129129
}
130130
}
131131

132-
success := levant.TriggerDeployment(config)
132+
success := levant.TriggerDeployment(config, nil)
133133
if !success {
134134
return 1
135135
}

Diff for: command/scale_in.go

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package command
2+
3+
import (
4+
"strings"
5+
6+
"github.com/jrasell/levant/levant/structs"
7+
"github.com/jrasell/levant/logging"
8+
"github.com/jrasell/levant/scale"
9+
)
10+
11+
// ScaleInCommand is the command implementation that allows users to scale a
12+
// Nomad job out.
13+
type ScaleInCommand struct {
14+
Meta
15+
}
16+
17+
// Help provides the help information for the scale-in command.
18+
func (c *ScaleInCommand) Help() string {
19+
helpText := `
20+
Usage: levant scale-in [options] <job-id>
21+
22+
Scale a Nomad job and optional task group out.
23+
24+
General Options:
25+
26+
-address=<http_address>
27+
The Nomad HTTP API address including port which Levant will use to make
28+
calls.
29+
30+
-log-level=<level>
31+
Specify the verbosity level of Levant's logs. Valid values include DEBUG,
32+
INFO, and WARN, in decreasing order of verbosity. The default is INFO.
33+
34+
-log-format=<format>
35+
Specify the format of Levant's logs. Valid values are HUMAN or JSON. The
36+
default is HUMAN.
37+
38+
Scale In Options:
39+
40+
-count=<num>
41+
The count by which the job and task groups should be scaled in by. Only
42+
one of count or percent can be passed.
43+
44+
-percent=<num>
45+
A percentage value by which the job and task groups should be scaled in
46+
by. Counts will be rounded up, to ensure required capacity is met. Only
47+
one of count or percent can be passed.
48+
49+
-task-group=<name>
50+
The name of the task group you wish to target for scaling. Is this is not
51+
speicified all task groups within the job will be scaled.
52+
`
53+
return strings.TrimSpace(helpText)
54+
}
55+
56+
// Synopsis is provides a brief summary of the scale-in command.
57+
func (c *ScaleInCommand) Synopsis() string {
58+
return "Scale in a Nomad job"
59+
}
60+
61+
// Run triggers a run of the Levant scale-in functions.
62+
func (c *ScaleInCommand) Run(args []string) int {
63+
64+
var err error
65+
var logL, logF string
66+
67+
config := &structs.ScalingConfig{}
68+
config.Direction = structs.ScalingDirectionIn
69+
70+
flags := c.Meta.FlagSet("scale-in", FlagSetVars)
71+
flags.Usage = func() { c.UI.Output(c.Help()) }
72+
73+
flags.StringVar(&config.Addr, "address", "", "")
74+
flags.StringVar(&logL, "log-level", "INFO", "")
75+
flags.StringVar(&logF, "log-format", "HUMAN", "")
76+
flags.IntVar(&config.Count, "count", 0, "")
77+
flags.IntVar(&config.Percent, "percent", 0, "")
78+
flags.StringVar(&config.TaskGroup, "task-group", "", "")
79+
80+
if err = flags.Parse(args); err != nil {
81+
return 1
82+
}
83+
84+
args = flags.Args()
85+
86+
if len(args) != 1 {
87+
c.UI.Error("This command takes one argument: <job-name>")
88+
return 1
89+
}
90+
91+
config.JobID = args[0]
92+
93+
if config.Count == 0 && config.Percent == 0 || config.Count > 0 && config.Percent > 0 ||
94+
config.Count < 0 || config.Percent < 0 {
95+
c.UI.Error("You must set either -count or -percent flag to scale-in")
96+
return 1
97+
}
98+
99+
if config.Count > 0 {
100+
config.DirectionType = structs.ScalingDirectionTypeCount
101+
}
102+
103+
if config.Percent > 0 {
104+
config.DirectionType = structs.ScalingDirectionTypePercent
105+
}
106+
107+
if err = logging.SetupLogger(logL, logF); err != nil {
108+
c.UI.Error(err.Error())
109+
return 1
110+
}
111+
112+
success := scale.TriggerScalingEvent(config)
113+
if !success {
114+
return 1
115+
}
116+
117+
return 0
118+
}

Diff for: command/scale_out.go

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package command
2+
3+
import (
4+
"strings"
5+
6+
"github.com/jrasell/levant/levant/structs"
7+
"github.com/jrasell/levant/logging"
8+
"github.com/jrasell/levant/scale"
9+
)
10+
11+
// ScaleOutCommand is the command implementation that allows users to scale a
12+
// Nomad job out.
13+
type ScaleOutCommand struct {
14+
Meta
15+
}
16+
17+
// Help provides the help information for the scale-out command.
18+
func (c *ScaleOutCommand) Help() string {
19+
helpText := `
20+
Usage: levant scale-out [options] <job-id>
21+
22+
Scale a Nomad job and optional task group out.
23+
24+
General Options:
25+
26+
-address=<http_address>
27+
The Nomad HTTP API address including port which Levant will use to make
28+
calls.
29+
30+
-log-level=<level>
31+
Specify the verbosity level of Levant's logs. Valid values include DEBUG,
32+
INFO, and WARN, in decreasing order of verbosity. The default is INFO.
33+
34+
-log-format=<format>
35+
Specify the format of Levant's logs. Valid values are HUMAN or JSON. The
36+
default is HUMAN.
37+
38+
Scale Out Options:
39+
40+
-count=<num>
41+
The count by which the job and task groups should be scaled out by. Only
42+
one of count or percent can be passed.
43+
44+
-percent=<num>
45+
A percentage value by which the job and task groups should be scaled out
46+
by. Counts will be rounded up, to ensure required capacity is met. Only
47+
one of count or percent can be passed.
48+
49+
-task-group=<name>
50+
The name of the task group you wish to target for scaling. Is this is not
51+
speicified all task groups within the job will be scaled.
52+
`
53+
return strings.TrimSpace(helpText)
54+
}
55+
56+
// Synopsis is provides a brief summary of the scale-out command.
57+
func (c *ScaleOutCommand) Synopsis() string {
58+
return "Scale out a Nomad job"
59+
}
60+
61+
// Run triggers a run of the Levant scale-out functions.
62+
func (c *ScaleOutCommand) Run(args []string) int {
63+
64+
var err error
65+
var logL, logF string
66+
67+
config := &structs.ScalingConfig{}
68+
config.Direction = structs.ScalingDirectionOut
69+
70+
flags := c.Meta.FlagSet("scale-out", FlagSetVars)
71+
flags.Usage = func() { c.UI.Output(c.Help()) }
72+
73+
flags.StringVar(&config.Addr, "address", "", "")
74+
flags.StringVar(&logL, "log-level", "INFO", "")
75+
flags.StringVar(&logF, "log-format", "HUMAN", "")
76+
flags.IntVar(&config.Count, "count", 0, "")
77+
flags.IntVar(&config.Percent, "percent", 0, "")
78+
flags.StringVar(&config.TaskGroup, "task-group", "", "")
79+
80+
if err = flags.Parse(args); err != nil {
81+
return 1
82+
}
83+
84+
args = flags.Args()
85+
86+
if len(args) != 1 {
87+
c.UI.Error("This command takes one argument: <job-name>")
88+
return 1
89+
}
90+
91+
config.JobID = args[0]
92+
93+
if config.Count == 0 && config.Percent == 0 || config.Count > 0 && config.Percent > 0 {
94+
c.UI.Error("You must set either -count or -percent flag to scale-out")
95+
return 1
96+
}
97+
98+
if config.Count > 0 {
99+
config.DirectionType = structs.ScalingDirectionTypeCount
100+
}
101+
102+
if config.Percent > 0 {
103+
config.DirectionType = structs.ScalingDirectionTypePercent
104+
}
105+
106+
if err = logging.SetupLogger(logL, logF); err != nil {
107+
c.UI.Error(err.Error())
108+
return 1
109+
}
110+
111+
success := scale.TriggerScalingEvent(config)
112+
if !success {
113+
return 1
114+
}
115+
116+
return 0
117+
}

Diff for: commands.go

+10
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory {
4141
Meta: meta,
4242
}, nil
4343
},
44+
"scale-in": func() (cli.Command, error) {
45+
return &command.ScaleInCommand{
46+
Meta: meta,
47+
}, nil
48+
},
49+
"scale-out": func() (cli.Command, error) {
50+
return &command.ScaleOutCommand{
51+
Meta: meta,
52+
}, nil
53+
},
4454
"version": func() (cli.Command, error) {
4555
ver := version.Version
4656
rel := version.VersionPrerelease

Diff for: levant/deploy.go

+12-27
Original file line numberDiff line numberDiff line change
@@ -7,63 +7,48 @@ import (
77

88
nomad "github.com/hashicorp/nomad/api"
99
nomadStructs "github.com/hashicorp/nomad/nomad/structs"
10+
"github.com/jrasell/levant/client"
1011
"github.com/jrasell/levant/levant/structs"
1112
"github.com/rs/zerolog/log"
1213
)
1314

14-
const (
15-
jobIDContextField = "job_id"
16-
)
17-
1815
// levantDeployment is the all deployment related objects for this Levant
1916
// deployment invoction.
2017
type levantDeployment struct {
2118
nomad *nomad.Client
2219
config *structs.Config
2320
}
2421

25-
// newNomadClient is used to create a new client to interact with Nomad.
26-
func newNomadClient(addr string) (*nomad.Client, error) {
27-
config := nomad.DefaultConfig()
28-
29-
if addr != "" {
30-
config.Address = addr
31-
}
32-
33-
c, err := nomad.NewClient(config)
34-
if err != nil {
35-
return nil, err
36-
}
37-
38-
return c, nil
39-
}
40-
4122
// newLevantDeployment sets up the Levant deployment object and Nomad client
4223
// to interact with the Nomad API.
43-
func newLevantDeployment(config *structs.Config) (*levantDeployment, error) {
24+
func newLevantDeployment(config *structs.Config, nomadClient *nomad.Client) (*levantDeployment, error) {
4425

4526
var err error
4627

4728
dep := &levantDeployment{}
4829
dep.config = config
4930

50-
dep.nomad, err = newNomadClient(config.Addr)
51-
if err != nil {
52-
return nil, err
31+
if nomadClient == nil {
32+
dep.nomad, err = client.NewNomadClient(config.Addr)
33+
if err != nil {
34+
return nil, err
35+
}
36+
} else {
37+
dep.nomad = nomadClient
5338
}
5439

5540
// Add the JobID as a log context field.
56-
log.Logger = log.With().Str(jobIDContextField, *config.Job.ID).Logger()
41+
log.Logger = log.With().Str(structs.JobIDContextField, *config.Job.ID).Logger()
5742

5843
return dep, nil
5944
}
6045

6146
// TriggerDeployment provides the main entry point into a Levant deployment and
6247
// is used to setup the clients before triggering the deployment process.
63-
func TriggerDeployment(config *structs.Config) bool {
48+
func TriggerDeployment(config *structs.Config, nomadClient *nomad.Client) bool {
6449

6550
// Create our new deployment object.
66-
levantDep, err := newLevantDeployment(config)
51+
levantDep, err := newLevantDeployment(config, nomadClient)
6752
if err != nil {
6853
log.Error().Err(err).Msg("levant/deploy: unable to setup Levant deployment")
6954
return false

Diff for: levant/dispatch.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package levant
22

33
import (
44
nomad "github.com/hashicorp/nomad/api"
5+
"github.com/jrasell/levant/client"
56
"github.com/jrasell/levant/levant/structs"
67
"github.com/rs/zerolog/log"
78
)
@@ -10,7 +11,7 @@ import (
1011
// is used to setup the clients before triggering the dispatch process.
1112
func TriggerDispatch(job string, metaMap map[string]string, payload []byte, address string) bool {
1213

13-
client, err := newNomadClient(address)
14+
client, err := client.NewNomadClient(address)
1415
if err != nil {
1516
log.Error().Msgf("levant/dispatch: unable to setup Levant dispatch: %v", err)
1617
return false

Diff for: levant/structs/config.go

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ package structs
22

33
import nomad "github.com/hashicorp/nomad/api"
44

5+
const (
6+
// JobIDContextField is the logging context feild added when interacting
7+
// with jobs.
8+
JobIDContextField = "job_id"
9+
)
10+
511
// Config is the main struct used to configure and run a Levant deployment on
612
// a given target job.
713
type Config struct {

0 commit comments

Comments
 (0)