2022-02-10 14:33:27 +00:00
package cli
import (
"fmt"
2023-05-10 19:57:11 +00:00
"net/http"
2022-02-10 14:33:27 +00:00
"time"
2022-09-07 20:01:18 +00:00
"unicode/utf8"
2022-02-10 14:33:27 +00:00
"golang.org/x/xerrors"
2023-09-07 21:28:22 +00:00
"github.com/coder/pretty"
2024-03-15 16:24:38 +00:00
"github.com/coder/serpent"
2023-09-07 21:28:22 +00:00
2023-08-18 18:55:43 +00:00
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/coderd/util/ptr"
"github.com/coder/coder/v2/codersdk"
2022-02-10 14:33:27 +00:00
)
2024-03-17 14:45:26 +00:00
func ( r * RootCmd ) templateCreate ( ) * serpent . Command {
2022-02-12 19:34:04 +00:00
var (
2023-10-19 22:16:15 +00:00
provisioner string
provisionerTags [ ] string
variablesFile string
2023-12-15 13:55:24 +00:00
commandLineVariables [ ] string
2023-10-19 22:16:15 +00:00
disableEveryone bool
requireActiveVersion bool
2023-08-25 16:00:38 +00:00
2023-11-22 00:20:01 +00:00
defaultTTL time . Duration
failureTTL time . Duration
dormancyThreshold time . Duration
dormancyAutoDeletion time . Duration
2023-01-16 20:32:11 +00:00
uploadFlags templateUploadFlags
2022-02-12 19:34:04 +00:00
)
2023-03-23 22:42:20 +00:00
client := new ( codersdk . Client )
2024-03-17 14:45:26 +00:00
cmd := & serpent . Command {
2022-04-14 17:23:20 +00:00
Use : "create [name]" ,
2024-01-05 21:04:14 +00:00
Short : "DEPRECATED: Create a template from the current directory or as specified by flag" ,
2024-03-15 16:24:38 +00:00
Middleware : serpent . Chain (
serpent . RequireRangeArgs ( 0 , 1 ) ,
2024-01-05 21:04:14 +00:00
cliui . DeprecationWarning (
"Use `coder templates push` command for creating and updating templates. \n" +
"Use `coder templates edit` command for editing template settings. " ,
) ,
2023-03-23 22:42:20 +00:00
r . InitClient ( client ) ,
) ,
2024-03-15 16:24:38 +00:00
Handler : func ( inv * serpent . Invocation ) error {
2024-03-20 15:37:57 +00:00
isTemplateSchedulingOptionsSet := failureTTL != 0 || dormancyThreshold != 0 || dormancyAutoDeletion != 0
2023-10-19 22:16:15 +00:00
if isTemplateSchedulingOptionsSet || requireActiveVersion {
2023-05-10 19:57:11 +00:00
entitlements , err := client . Entitlements ( inv . Context ( ) )
2023-10-19 22:16:15 +00:00
if cerr , ok := codersdk . AsError ( err ) ; ok && cerr . StatusCode ( ) == http . StatusNotFound {
return xerrors . Errorf ( "your deployment appears to be an AGPL deployment, so you cannot set enterprise-only flags" )
2023-05-10 19:57:11 +00:00
} else if err != nil {
return xerrors . Errorf ( "get entitlements: %w" , err )
}
2023-10-19 22:16:15 +00:00
if isTemplateSchedulingOptionsSet {
if ! entitlements . Features [ codersdk . FeatureAdvancedTemplateScheduling ] . Enabled {
2024-03-20 15:37:57 +00:00
return xerrors . Errorf ( "your license is not entitled to use advanced template scheduling, so you cannot set --failure-ttl, or --inactivity-ttl" )
2023-10-19 22:16:15 +00:00
}
}
if requireActiveVersion {
if ! entitlements . Features [ codersdk . FeatureAccessControl ] . Enabled {
return xerrors . Errorf ( "your license is not entitled to use enterprise access control, so you cannot set --require-active-version" )
}
2023-05-10 19:57:11 +00:00
}
}
2024-02-26 16:03:49 +00:00
organization , err := CurrentOrganization ( r , inv , client )
2022-02-10 14:33:27 +00:00
if err != nil {
return err
}
2022-04-14 17:23:20 +00:00
2023-03-23 22:42:20 +00:00
templateName , err := uploadFlags . templateName ( inv . Args )
2023-01-16 20:32:11 +00:00
if err != nil {
return err
2022-03-22 19:17:50 +00:00
}
2022-04-14 17:23:20 +00:00
2024-01-30 10:47:10 +00:00
if utf8 . RuneCountInString ( templateName ) > 32 {
return xerrors . Errorf ( "Template name must be no more than 32 characters" )
2022-09-07 20:01:18 +00:00
}
2023-03-23 22:42:20 +00:00
_ , err = client . TemplateByName ( inv . Context ( ) , organization . ID , templateName )
2022-03-22 19:17:50 +00:00
if err == nil {
2022-04-06 17:42:40 +00:00
return xerrors . Errorf ( "A template already exists named %q!" , templateName )
2022-02-10 14:33:27 +00:00
}
2023-06-20 15:02:44 +00:00
err = uploadFlags . checkForLockfile ( inv )
if err != nil {
return xerrors . Errorf ( "check for lockfile: %w" , err )
}
2023-07-11 10:11:08 +00:00
message := uploadFlags . templateMessage ( inv )
2024-01-12 14:08:23 +00:00
var varsFiles [ ] string
if ! uploadFlags . stdin ( ) {
varsFiles , err = DiscoverVarsFiles ( uploadFlags . directory )
if err != nil {
return err
}
if len ( varsFiles ) > 0 {
_ , _ = fmt . Fprintln ( inv . Stdout , "Auto-discovered Terraform tfvars files. Make sure to review and clean up any unused files." )
}
}
2022-05-12 11:54:58 +00:00
// Confirm upload of the directory.
2023-03-23 22:42:20 +00:00
resp , err := uploadFlags . upload ( inv , client )
2022-04-11 23:54:30 +00:00
if err != nil {
return err
}
2022-11-16 22:34:06 +00:00
tags , err := ParseProvisionerTags ( provisionerTags )
if err != nil {
return err
}
2023-12-15 13:55:24 +00:00
userVariableValues , err := ParseUserVariableValues (
2024-01-12 14:08:23 +00:00
varsFiles ,
2023-12-15 13:55:24 +00:00
variablesFile ,
commandLineVariables )
if err != nil {
return err
}
2023-06-02 09:16:46 +00:00
job , err := createValidTemplateVersion ( inv , createValidTemplateVersionArgs {
2023-12-15 13:55:24 +00:00
Message : message ,
Client : client ,
Organization : organization ,
Provisioner : codersdk . ProvisionerType ( provisioner ) ,
FileID : resp . ID ,
ProvisionerTags : tags ,
UserVariableValues : userVariableValues ,
2022-06-17 17:22:28 +00:00
} )
2022-02-10 14:33:27 +00:00
if err != nil {
return err
}
2023-01-16 20:32:11 +00:00
if ! uploadFlags . stdin ( ) {
2023-03-23 22:42:20 +00:00
_ , err = cliui . Prompt ( inv , cliui . PromptOptions {
2023-01-16 20:32:11 +00:00
Text : "Confirm create?" ,
IsConfirm : true ,
} )
if err != nil {
return err
}
2022-02-10 14:33:27 +00:00
}
2022-06-07 12:37:45 +00:00
createReq := codersdk . CreateTemplateRequest {
2023-11-22 00:20:01 +00:00
Name : templateName ,
VersionID : job . ID ,
DefaultTTLMillis : ptr . Ref ( defaultTTL . Milliseconds ( ) ) ,
FailureTTLMillis : ptr . Ref ( failureTTL . Milliseconds ( ) ) ,
TimeTilDormantMillis : ptr . Ref ( dormancyThreshold . Milliseconds ( ) ) ,
TimeTilDormantAutoDeleteMillis : ptr . Ref ( dormancyAutoDeletion . Milliseconds ( ) ) ,
DisableEveryoneGroupAccess : disableEveryone ,
RequireActiveVersion : requireActiveVersion ,
2022-06-07 12:37:45 +00:00
}
2023-03-23 22:42:20 +00:00
_ , err = client . CreateTemplate ( inv . Context ( ) , organization . ID , createReq )
2022-02-10 14:33:27 +00:00
if err != nil {
2022-02-12 19:34:04 +00:00
return err
2022-02-10 14:33:27 +00:00
}
2023-09-07 21:28:22 +00:00
_ , _ = fmt . Fprintln ( inv . Stdout , "\n" + pretty . Sprint ( cliui . DefaultStyles . Wrap ,
"The " + pretty . Sprint (
cliui . DefaultStyles . Keyword , templateName ) + " template has been created at " +
pretty . Sprint ( cliui . DefaultStyles . DateTimeStamp , time . Now ( ) . Format ( time . Stamp ) ) + "! " +
2022-04-11 23:54:30 +00:00
"Developers can provision a workspace with this template using:" ) + "\n" )
2023-09-07 21:28:22 +00:00
_ , _ = fmt . Fprintln ( inv . Stdout , " " + pretty . Sprint ( cliui . DefaultStyles . Code , fmt . Sprintf ( "coder create --template=%q [workspace name]" , templateName ) ) )
2023-03-23 22:42:20 +00:00
_ , _ = fmt . Fprintln ( inv . Stdout )
2022-04-11 23:54:30 +00:00
2022-02-10 14:33:27 +00:00
return nil
} ,
}
2024-03-15 16:24:38 +00:00
cmd . Options = serpent . OptionSet {
2023-06-14 16:08:58 +00:00
{
Flag : "private" ,
Description : "Disable the default behavior of granting template access to the 'everyone' group. " +
"The template permissions must be updated to allow non-admin users to use this template." ,
2024-03-15 16:24:38 +00:00
Value : serpent . BoolOf ( & disableEveryone ) ,
2023-06-14 16:08:58 +00:00
} ,
2023-03-23 22:42:20 +00:00
{
Flag : "variables-file" ,
Description : "Specify a file path with values for Terraform-managed variables." ,
2024-03-15 16:24:38 +00:00
Value : serpent . StringOf ( & variablesFile ) ,
2023-03-23 22:42:20 +00:00
} ,
{
Flag : "variable" ,
Description : "Specify a set of values for Terraform-managed variables." ,
2024-03-15 16:24:38 +00:00
Value : serpent . StringArrayOf ( & commandLineVariables ) ,
2023-03-23 22:42:20 +00:00
} ,
2023-07-25 14:36:02 +00:00
{
Flag : "var" ,
Description : "Alias of --variable." ,
2024-03-15 16:24:38 +00:00
Value : serpent . StringArrayOf ( & commandLineVariables ) ,
2023-07-25 14:36:02 +00:00
} ,
2023-03-23 22:42:20 +00:00
{
Flag : "provisioner-tag" ,
Description : "Specify a set of tags to target provisioner daemons." ,
2024-03-15 16:24:38 +00:00
Value : serpent . StringArrayOf ( & provisionerTags ) ,
2023-03-23 22:42:20 +00:00
} ,
{
Flag : "default-ttl" ,
2023-08-25 17:39:12 +00:00
Description : "Specify a default TTL for workspaces created from this template. It is the default time before shutdown - workspaces created from this template default to this value. Maps to \"Default autostop\" in the UI." ,
2023-03-23 22:42:20 +00:00
Default : "24h" ,
2024-03-15 16:24:38 +00:00
Value : serpent . DurationOf ( & defaultTTL ) ,
2023-03-23 22:42:20 +00:00
} ,
2023-05-10 19:57:11 +00:00
{
Flag : "failure-ttl" ,
2023-08-25 17:39:12 +00:00
Description : "Specify a failure TTL for workspaces created from this template. It is the amount of time after a failed \"start\" build before coder automatically schedules a \"stop\" build to cleanup.This licensed feature's default is 0h (off). Maps to \"Failure cleanup\"in the UI." ,
2023-05-10 19:57:11 +00:00
Default : "0h" ,
2024-03-15 16:24:38 +00:00
Value : serpent . DurationOf ( & failureTTL ) ,
2023-05-10 19:57:11 +00:00
} ,
{
2023-11-22 00:20:01 +00:00
Flag : "dormancy-threshold" ,
Description : "Specify a duration workspaces may be inactive prior to being moved to the dormant state. This licensed feature's default is 0h (off). Maps to \"Dormancy threshold\" in the UI." ,
2023-05-10 19:57:11 +00:00
Default : "0h" ,
2024-03-15 16:24:38 +00:00
Value : serpent . DurationOf ( & dormancyThreshold ) ,
2023-05-10 19:57:11 +00:00
} ,
2023-11-22 00:20:01 +00:00
{
Flag : "dormancy-auto-deletion" ,
Description : "Specify a duration workspaces may be in the dormant state prior to being deleted. This licensed feature's default is 0h (off). Maps to \"Dormancy Auto-Deletion\" in the UI." ,
Default : "0h" ,
2024-03-15 16:24:38 +00:00
Value : serpent . DurationOf ( & dormancyAutoDeletion ) ,
2023-11-22 00:20:01 +00:00
} ,
2023-03-23 22:42:20 +00:00
{
Flag : "test.provisioner" ,
Description : "Customize the provisioner backend." ,
Default : "terraform" ,
2024-03-15 16:24:38 +00:00
Value : serpent . StringOf ( & provisioner ) ,
2023-03-23 22:42:20 +00:00
Hidden : true ,
} ,
2023-10-19 22:16:15 +00:00
{
Flag : "require-active-version" ,
Description : "Requires workspace builds to use the active template version. This setting does not apply to template admins. This is an enterprise-only feature." ,
2024-03-15 16:24:38 +00:00
Value : serpent . BoolOf ( & requireActiveVersion ) ,
2023-10-19 22:16:15 +00:00
Default : "false" ,
} ,
2023-03-23 22:42:20 +00:00
cliui . SkipPromptOption ( ) ,
2022-02-12 19:34:04 +00:00
}
2023-06-20 15:02:44 +00:00
cmd . Options = append ( cmd . Options , uploadFlags . options ( ) ... )
2022-02-12 19:34:04 +00:00
return cmd
}