Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

job: add job support for unit kill #218

Merged
merged 1 commit into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
310 changes: 0 additions & 310 deletions tsuru/client/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -1641,313 +1641,3 @@ func addCName(cnames []string, g cmd.AppNameMixIn, client *cmd.Client) error {
_, err = client.Do(request)
return err
}

type UnitAdd struct {
cmd.AppNameMixIn
fs *gnuflag.FlagSet
process string
version string
}

func (c *UnitAdd) Info() *cmd.Info {
return &cmd.Info{
Name: "unit-add",
Usage: "unit add <# of units> [-a/--app appname] [-p/--process processname] [--version version]",
Desc: `Adds new units to a process of an application. You need to have access to the
app to be able to add new units to it.`,
MinArgs: 1,
}
}

func (c *UnitAdd) Flags() *gnuflag.FlagSet {
if c.fs == nil {
c.fs = c.AppNameMixIn.Flags()
c.fs.StringVar(&c.process, "process", "", "Process name")
c.fs.StringVar(&c.process, "p", "", "Process name")
c.fs.StringVar(&c.version, "version", "", "Version number")
}
return c.fs
}

func (c *UnitAdd) Run(context *cmd.Context, client *cmd.Client) error {
context.RawOutput()
appName, err := c.AppName()
if err != nil {
return err
}
u, err := cmd.GetURL(fmt.Sprintf("/apps/%s/units", appName))
if err != nil {
return err
}
val := url.Values{}
val.Add("units", context.Args[0])
val.Add("process", c.process)
val.Set("version", c.version)
request, err := http.NewRequest("PUT", u, bytes.NewBufferString(val.Encode()))
if err != nil {
return err
}
request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
response, err := client.Do(request)
if err != nil {
return err
}
defer response.Body.Close()
return cmd.StreamJSONResponse(context.Stdout, response)
}

type UnitRemove struct {
cmd.AppNameMixIn
fs *gnuflag.FlagSet
process string
version string
}

func (c *UnitRemove) Info() *cmd.Info {
return &cmd.Info{
Name: "unit-remove",
Usage: "unit remove <# of units> [-a/--app appname] [-p/-process processname] [--version version]",
Desc: `Removes units from a process of an application. You need to have access to the
app to be able to remove units from it.`,
MinArgs: 1,
}
}

func (c *UnitRemove) Flags() *gnuflag.FlagSet {
if c.fs == nil {
c.fs = c.AppNameMixIn.Flags()
c.fs.StringVar(&c.process, "process", "", "Process name")
c.fs.StringVar(&c.process, "p", "", "Process name")
c.fs.StringVar(&c.version, "version", "", "Version number")
}
return c.fs
}

func (c *UnitRemove) Run(context *cmd.Context, client *cmd.Client) error {
context.RawOutput()
appName, err := c.AppName()
if err != nil {
return err
}
val := url.Values{}
val.Add("units", context.Args[0])
val.Add("process", c.process)
val.Set("version", c.version)
url, err := cmd.GetURL(fmt.Sprintf("/apps/%s/units?%s", appName, val.Encode()))
if err != nil {
return err
}
request, err := http.NewRequest(http.MethodDelete, url, nil)
if err != nil {
return err
}
response, err := client.Do(request)
if err != nil {
return err
}
return cmd.StreamJSONResponse(context.Stdout, response)
}

type UnitKill struct {
cmd.AppNameMixIn
fs *gnuflag.FlagSet
force bool
}

func (c *UnitKill) Info() *cmd.Info {
return &cmd.Info{
Name: "unit-kill",
Usage: "unit kill [-a/--app appname] [-f/--force] <unit>",
Desc: `Kills units from a process of an application. You need to have access to the
app to be able to remove unit from it.`,
MinArgs: 1,
}
}

func (c *UnitKill) Flags() *gnuflag.FlagSet {
if c.fs == nil {
c.fs = c.AppNameMixIn.Flags()
c.fs.BoolVar(&c.force, "f", false, "Forces the termination of unit.")
}
return c.fs
}

func (c *UnitKill) Run(context *cmd.Context, client *cmd.Client) error {
context.RawOutput()
appName, err := c.AppName()
if err != nil {
return err
}
unit := context.Args[0]

v := url.Values{}
if c.force {
v.Set("force", "true")
}

url, err := cmd.GetURLVersion("1.12", fmt.Sprintf("/apps/%s/units/%s?%s", appName, unit, v.Encode()))
if err != nil {
return err
}
request, err := http.NewRequest(http.MethodDelete, url, nil)
if err != nil {
return err
}
response, err := client.Do(request)
if err != nil {
return err
}
return cmd.StreamJSONResponse(context.Stdout, response)
}

type UnitSet struct {
cmd.AppNameMixIn
fs *gnuflag.FlagSet
process string
version int
}

func (c *UnitSet) Info() *cmd.Info {
return &cmd.Info{
Name: "unit-set",
Usage: "unit set <# of units> [-a/--app appname] [-p/--process processname] [--version version]",
Desc: `Set the number of units for a process of an application, adding or removing units as needed. You need to have access to the
app to be able to set the number of units for it. The process flag is optional if the app has only 1 process.`,
MinArgs: 1,
}
}

func (c *UnitSet) Flags() *gnuflag.FlagSet {
if c.fs == nil {
c.fs = c.AppNameMixIn.Flags()
processMessage := "Process name"
c.fs.StringVar(&c.process, "process", "", processMessage)
c.fs.StringVar(&c.process, "p", "", processMessage)
c.fs.IntVar(&c.version, "version", 0, "Version number")
}
return c.fs
}

func (c *UnitSet) Run(context *cmd.Context, client *cmd.Client) error {
context.RawOutput()
appName, err := c.AppName()
if err != nil {
return err
}
u, err := cmd.GetURL(fmt.Sprintf("/apps/%s", appName))
if err != nil {
return err
}
request, err := http.NewRequest(http.MethodGet, u, nil)
if err != nil {
return err
}
response, err := client.Do(request)
if err != nil {
return err
}
result, err := io.ReadAll(response.Body)
if err != nil {
return err
}
var a app
err = json.Unmarshal(result, &a)
if err != nil {
return err
}

unitsByProcess := map[string][]unit{}
unitsByVersion := map[int][]unit{}
for _, u := range a.Units {
unitsByProcess[u.ProcessName] = append(unitsByProcess[u.ProcessName], u)
unitsByVersion[u.Version] = append(unitsByVersion[u.Version], u)
}

if len(unitsByProcess) != 1 && c.process == "" {
return errors.New("Please use the -p/--process flag to specify which process you want to set units for.")
}

if len(unitsByVersion) != 1 && c.version == 0 {
return errors.New("Please use the --version flag to specify which version you want to set units for.")
}

if c.process == "" {
for p := range unitsByProcess {
c.process = p
break
}
}

if c.version == 0 {
for v := range unitsByVersion {
c.version = v
break
}
}

existingUnits := 0
for _, unit := range a.Units {
if unit.ProcessName == c.process && unit.Version == c.version {
existingUnits++
}
}

desiredUnits, err := strconv.Atoi(context.Args[0])
if err != nil {
return err
}

if existingUnits < desiredUnits {
u, err := cmd.GetURL(fmt.Sprintf("/apps/%s/units", appName))
if err != nil {
return err
}

unitsToAdd := desiredUnits - existingUnits
val := url.Values{}
val.Add("units", strconv.Itoa(unitsToAdd))
val.Add("process", c.process)
val.Add("version", strconv.Itoa(c.version))
request, err := http.NewRequest(http.MethodPut, u, bytes.NewBufferString(val.Encode()))
if err != nil {
return err
}

request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
response, err := client.Do(request)
if err != nil {
return err
}

defer response.Body.Close()
return cmd.StreamJSONResponse(context.Stdout, response)
}

if existingUnits > desiredUnits {
unitsToRemove := existingUnits - desiredUnits
val := url.Values{}
val.Add("units", strconv.Itoa(unitsToRemove))
val.Add("process", c.process)
val.Add("version", strconv.Itoa(c.version))
u, err := cmd.GetURL(fmt.Sprintf("/apps/%s/units?%s", appName, val.Encode()))
if err != nil {
return err
}

request, err := http.NewRequest(http.MethodDelete, u, nil)
if err != nil {
return err
}

response, err := client.Do(request)
if err != nil {
return err
}

defer response.Body.Close()
return cmd.StreamJSONResponse(context.Stdout, response)
}

fmt.Fprintf(context.Stdout, "The process %s, version %d already has %d units.\n", c.process, c.version, existingUnits)
return nil
}
Loading