#variant (2020-05)

https://github.com/mumoshu/variant

Discuss variant (the “Universal CLI”) https://github.com/mumoshu/variant

Archive: https://archive.sweetops.com/variant/

2020-05-07

2020-05-01

johncblandii (Cloud Posse) avatar
johncblandii (Cloud Posse)

@Erik Osterman (Cloud Posse) @mumoshu here is an example of a CLI call not waiting for input.

I don’t have the exact code in play right here, but my guess it is the workspace running then it immediately goes to a init which also skips waiting for the input.

Initializing modules...

Initializing the backend...
Backend configuration changed!

Terraform has detected that the configuration specified for the backend
has changed. Terraform will now check for existing state in the backends.


Do you want to migrate all workspaces to "s3"?
  Both the existing "s3" backend and the newly configured "s3" backend
  support workspaces. When migrating between backends, Terraform will copy
  all workspaces (with the same names). THIS WILL OVERWRITE any conflicting
  states in the destination.
  
  Terraform initialization doesn't currently migrate only select workspaces.
  If you want to migrate a select number of workspaces, you must manually
  pull and push those states.
  
  If you answer "yes", Terraform will migrate all states. If you answer
  "no", Terraform will abort.

  Enter a value: 
Do you want to migrate all workspaces to "s3"?
  Both the existing "s3" backend and the newly configured "s3" backend
  support workspaces. When migrating between backends, Terraform will copy
  all workspaces (with the same names). THIS WILL OVERWRITE any conflicting
  states in the destination.
  
  Terraform initialization doesn't currently migrate only select workspaces.
  If you want to migrate a select number of workspaces, you must manually
  pull and push those states.
  
  If you answer "yes", Terraform will migrate all states. If you answer
  "no", Terraform will abort.

  Enter a value: 

Error: Migration aborted by user.
johncblandii (Cloud Posse) avatar
johncblandii (Cloud Posse)
job "terraform init" {
  description = "Runs terraform init for a tenant project"

  parameter "tenant" {
    description = "Tenant to operate on"
    type        = string
  }

  parameter "project" {
    description = "Terraform project to process"
    type        = string
  }

  run "terraform subcommand" {
    args    = []
    command = "init"
    project = param.project
    tenant  = param.tenant
  }
}
johncblandii (Cloud Posse) avatar
johncblandii (Cloud Posse)
job "terraform subcommand" {
  description = "Execute a terraform subcommand"
  private     = true

  option "args" {
    default     = []
    description = "args to pass to subcommand"
    type        = list(string)
  }

  parameter "command" {
    type        = string
    description = "A terraform command to execute"
  }

  parameter "project" {
    description = "Terraform project to process"
    type        = string
  }

  option "env" {
    default     = {}
    description = "Environment variables for the command"
    type        = map(string)
  }

  variable "cmd-name" {
    value = "terraform"
  }

  variable "cmd" {
    value = opt.dry-run ? "echo" : var.cmd-name
  }

  variable "cmd-args" {
    value = compact(concat(list(opt.dry-run ? var.cmd-name : ""), list(param.command), opt.args))
  }

  exec {
    args    = var.cmd-args
    command = var.cmd
    dir     = "${opt.tenants-dir}/projects/${param.project}"
    env     = opt.env
  }
}

job "terraform shell" {
  description = "Run a terraform subcommand in a shell targeted specifically at a tenants/projects project"
  private     = true

  parameter "tenant" {
    description = "Tenant to operate on"
    type        = string
  }

  parameter "project" {
    description = "Terraform project to process"
    type        = string
  }

  parameter "commands" {
    description = "List of commands to execute"
    type        = list(string)
  }

  run "shell" {
    commands = param.commands
    dir      = "${opt.tenants-dir}/projects/${param.project}"
  }
}
johncblandii (Cloud Posse) avatar
johncblandii (Cloud Posse)

\#!/usr/bin/env variant

\# vim: filetype=hcl

job "echo" {
  description = "Echoes the param.message to the console"
  private     = true

  parameter "message" {
    description = "A message to output"
    type        = string
  }

  exec {
    command = "echo"
    args    = [param.message]
  }
}

job "shell" {
  description = "Run a command in bash"
  private     = true

  option "dir" {
    default     = ""
    description = "Directory to run the command"
    type        = string
  }

  option "env" {
    default     = {}
    description = "Environment variables for the command"
    type        = map(string)
  }

  parameter "commands" {
    description = "List of commands to execute"
    type        = list(string)
  }

  variable "cmd-name" {
    value = "bash"
  }

  variable "cmd" {
    value = opt.dry-run ? "echo" : var.cmd-name
  }

  variable "cmd-args" {
    type = list(string)
    value = compact(concat(list(opt.dry-run ? var.cmd-name : ""), ["-c", join("\n", param.commands)]))
  }

  exec {
    args    = var.cmd-args
    command = var.cmd
    dir     = opt.dir
    env     = opt.env
  }
}
mumoshu avatar
mumoshu

Have you tried interactive = true? It won’t be able to wait for input without that option, cuz interactive = true is the only way for connecting your STDIN to the exec, which is a must for the user input to work at all

johncblandii (Cloud Posse) avatar
johncblandii (Cloud Posse)

ah, right. is it at an issue if it is “sometimes” interactive?

mumoshu avatar
mumoshu

what do you mean by sometimes? does it sometimes wait for the input?

johncblandii (Cloud Posse) avatar
johncblandii (Cloud Posse)

it may not actually prompt

johncblandii (Cloud Posse) avatar
johncblandii (Cloud Posse)

ex:

johncblandii (Cloud Posse) avatar
johncblandii (Cloud Posse)

tf init the first time doesn’t prompt

mumoshu avatar
mumoshu

i thought it would never wait. terraform would produce a prompt asking the user input regardless of STDIN is there or not. but i thought that’s just that

johncblandii (Cloud Posse) avatar
johncblandii (Cloud Posse)

change the backend storage and it’ll ask to migrate storage

mumoshu avatar
mumoshu

yes, but seems like that’s terraform issue?

mumoshu avatar
mumoshu

i.e. terraform is trying to ask for the user input even when there’s no STDIN connected to your terminal?

johncblandii (Cloud Posse) avatar
johncblandii (Cloud Posse)

i just wanted to know if variant2 would had an issue if it doesn’t prompt and i still put interactive on it

mumoshu avatar
mumoshu

afaik, no. but im interested. did you observe anything that might be caused by a potential variant2 issue? (did you actually see variant2 not handling user input correctly even when interactive = true is set?

mumoshu avatar
mumoshu

im a little confused cuz there seemed no interactive = true set in your example

mumoshu avatar
mumoshu

btw variant2 should never wait for input if thre’s no interactive =true set

johncblandii (Cloud Posse) avatar
johncblandii (Cloud Posse)

no, there is a stdin. this is on my local system so tf waiting is expected

mumoshu avatar
mumoshu

yeah, but you also need interactive = true to actually pass your STDIN to those terraform commands run via exec:

  exec {
    interactive = true
    args    = var.cmd-args
    command = var.cmd
    dir     = "${opt.tenants-dir}/projects/${param.project}"
    env     = opt.env
  }
mumoshu avatar
mumoshu

in your example it doesn’t have one

  exec {
    args    = var.cmd-args
    command = var.cmd
    dir     = "${opt.tenants-dir}/projects/${param.project}"
    env     = opt.env
  }
mumoshu avatar
mumoshu

oh, or are you saying that variant2 should automatically set interactive = true whenever STDIN is connected to a tty?

mumoshu avatar
mumoshu

(i intentionally avoided that cuz it doesn’t always work

mumoshu avatar
mumoshu

@johncblandii (Cloud Posse) Hey! Could you revisit this? I’m still thinking that this is behaving as expected given you don’t have interactive = true set in execs. But I’m open to suggestions like e.g. make interactive = true default, or anything else.

    keyboard_arrow_up