diff --git a/cmd/compute/instance/instance_create.go b/cmd/compute/instance/instance_create.go index 626b11e9..21a37c5c 100644 --- a/cmd/compute/instance/instance_create.go +++ b/cmd/compute/instance/instance_create.go @@ -31,24 +31,25 @@ type instanceCreateCmd struct { Name string `cli-arg:"#" cli-usage:"NAME"` - AntiAffinityGroups []string `cli-flag:"anti-affinity-group" cli-usage:"instance Anti-Affinity Group NAME|ID (can be specified multiple times)"` - CloudInitFile string `cli-flag:"cloud-init" cli-usage:"instance cloud-init user data configuration file path"` - CloudInitCompress bool `cli-flag:"cloud-init-compress" cli-usage:"compress instance cloud-init user data"` - DeployTarget string `cli-usage:"instance Deploy Target NAME|ID"` - DiskSize int64 `cli-usage:"instance disk size"` - IPv6 bool `cli-flag:"ipv6" cli-usage:"enable IPv6 on instance"` - TPM bool `cli-flag:"tpm" cli-usage:"enable TPM on instance"` - SecureBoot bool `cli-flag:"secureboot" cli-usage:"enable Secure boot on instance"` - InstanceType string `cli-usage:"instance type (format: [FAMILY.]SIZE)"` - Labels map[string]string `cli-flag:"label" cli-usage:"instance label (format: key=value)"` - PrivateNetworks []string `cli-flag:"private-network" cli-usage:"instance Private Network NAME|ID (can be specified multiple times)"` - PrivateInstance bool `cli-flag:"private-instance" cli-usage:"enable private instance to be created"` - SSHKeys []string `cli-flag:"ssh-key" cli-usage:"SSH key to deploy on the instance (can be specified multiple times)"` - Protection bool `cli-flag:"protection" cli-usage:"enable delete protection"` - SecurityGroups []string `cli-flag:"security-group" cli-usage:"instance Security Group NAME|ID (can be specified multiple times)"` - Template string `cli-usage:"instance template NAME|ID"` - TemplateVisibility string `cli-usage:"instance template visibility (public|private)"` - Zone v3.ZoneName `cli-short:"z" cli-usage:"instance zone"` + AppConsistentSnapshot bool `cli-flag:"application-consistent-snapshot-enabled" cli-usage:"enable application-consistent snapshots when supported; false disables; omit for template default"` + AntiAffinityGroups []string `cli-flag:"anti-affinity-group" cli-usage:"instance Anti-Affinity Group NAME|ID (can be specified multiple times)"` + CloudInitFile string `cli-flag:"cloud-init" cli-usage:"instance cloud-init user data configuration file path"` + CloudInitCompress bool `cli-flag:"cloud-init-compress" cli-usage:"compress instance cloud-init user data"` + DeployTarget string `cli-usage:"instance Deploy Target NAME|ID"` + DiskSize int64 `cli-usage:"instance disk size"` + IPv6 bool `cli-flag:"ipv6" cli-usage:"enable IPv6 on instance"` + TPM bool `cli-flag:"tpm" cli-usage:"enable TPM on instance"` + SecureBoot bool `cli-flag:"secureboot" cli-usage:"enable Secure boot on instance"` + InstanceType string `cli-usage:"instance type (format: [FAMILY.]SIZE)"` + Labels map[string]string `cli-flag:"label" cli-usage:"instance label (format: key=value)"` + PrivateNetworks []string `cli-flag:"private-network" cli-usage:"instance Private Network NAME|ID (can be specified multiple times)"` + PrivateInstance bool `cli-flag:"private-instance" cli-usage:"enable private instance to be created"` + SSHKeys []string `cli-flag:"ssh-key" cli-usage:"SSH key to deploy on the instance (can be specified multiple times)"` + Protection bool `cli-flag:"protection" cli-usage:"enable delete protection"` + SecurityGroups []string `cli-flag:"security-group" cli-usage:"instance Security Group NAME|ID (can be specified multiple times)"` + Template string `cli-usage:"instance template NAME|ID"` + TemplateVisibility string `cli-usage:"instance template visibility (public|private)"` + Zone v3.ZoneName `cli-short:"z" cli-usage:"instance zone"` } func (c *instanceCreateCmd) CmdAliases() []string { return exocmd.GCreateAlias } @@ -74,7 +75,7 @@ func (c *instanceCreateCmd) CmdPreRun(cmd *cobra.Command, args []string) error { return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *instanceCreateCmd) CmdRun(_ *cobra.Command, _ []string) error { //nolint:gocyclo +func (c *instanceCreateCmd) CmdRun(cmd *cobra.Command, _ []string) error { //nolint:gocyclo var ( singleUseSSHPrivateKey *rsa.PrivateKey singleUseSSHPublicKey ssh.PublicKey @@ -240,6 +241,10 @@ func (c *instanceCreateCmd) CmdRun(_ *cobra.Command, _ []string) error { //nolin instanceReq.UserData = userData } + if cmd.Flags().Changed(exocmd.MustCLICommandFlagName(c, &c.AppConsistentSnapshot)) { + instanceReq.ApplicationConsistentSnapshotEnabled = &c.AppConsistentSnapshot + } + var instanceID v3.UUID utils.DecorateAsyncOperation(fmt.Sprintf("Creating instance %q...", c.Name), func() { var op *v3.Operation diff --git a/cmd/compute/instance/instance_show.go b/cmd/compute/instance/instance_show.go index aa5e2f89..7019036b 100644 --- a/cmd/compute/instance/instance_show.go +++ b/cmd/compute/instance/instance_show.go @@ -18,27 +18,28 @@ import ( ) type InstanceShowOutput struct { - ID v3.UUID `json:"id"` - Name string `json:"name"` - CreationDate string `json:"creation_date"` - InstanceType string `json:"instance_type"` - Template string `json:"template"` - Zone v3.ZoneName `json:"zone"` - AntiAffinityGroups []string `json:"anti_affinity_groups" outputLabel:"Anti-Affinity Groups"` - DeployTarget string `json:"deploy_target"` - SecurityGroups []string `json:"security_groups"` - PrivateInstance string `json:"private-instance" outputLabel:"Private Instance"` - PrivateNetworks []string `json:"private_networks"` - ElasticIPs []string `json:"elastic_ips" outputLabel:"Elastic IPs"` - IPAddress string `json:"ip_address"` - IPv6Address string `json:"ipv6_address" outputLabel:"IPv6 Address"` - SSHKey string `json:"ssh_key"` - DiskSize string `json:"disk_size"` - State v3.InstanceState `json:"state"` - Labels map[string]string `json:"labels"` - SecureBoot bool `json:"secureboot"` - Tpm bool `json:"tpm"` - ReverseDNS v3.DomainName `json:"reverse_dns" outputLabel:"Reverse DNS"` + ID v3.UUID `json:"id"` + Name string `json:"name"` + CreationDate string `json:"creation_date"` + InstanceType string `json:"instance_type"` + Template string `json:"template"` + Zone v3.ZoneName `json:"zone"` + AntiAffinityGroups []string `json:"anti_affinity_groups" outputLabel:"Anti-Affinity Groups"` + DeployTarget string `json:"deploy_target"` + SecurityGroups []string `json:"security_groups"` + PrivateInstance string `json:"private-instance" outputLabel:"Private Instance"` + PrivateNetworks []string `json:"private_networks"` + ElasticIPs []string `json:"elastic_ips" outputLabel:"Elastic IPs"` + IPAddress string `json:"ip_address"` + IPv6Address string `json:"ipv6_address" outputLabel:"IPv6 Address"` + SSHKey string `json:"ssh_key"` + DiskSize string `json:"disk_size"` + State v3.InstanceState `json:"state"` + Labels map[string]string `json:"labels"` + SecureBoot bool `json:"secureboot"` + Tpm bool `json:"tpm"` + ReverseDNS v3.DomainName `json:"reverse_dns" outputLabel:"Reverse DNS"` + AppConsistentSnapshot bool `json:"application_consistent_snapshot_enabled" outputLabel:"Application-Consistent Snapshot enabled"` } func (o *InstanceShowOutput) Type() string { return "Compute instance" } @@ -142,6 +143,10 @@ func (c *instanceShowCmd) CmdRun(cmd *cobra.Command, _ []string) error { Zone: c.Zone, } + if instance.ApplicationConsistentSnapshotEnabled != nil { + out.AppConsistentSnapshot = *instance.ApplicationConsistentSnapshotEnabled + } + out.PrivateInstance = "No" if instance.PublicIPAssignment == "none" { out.PrivateInstance = "Yes" diff --git a/cmd/compute/instance/instance_snapshot_show.go b/cmd/compute/instance/instance_snapshot_show.go index c4358d68..983eb418 100644 --- a/cmd/compute/instance/instance_snapshot_show.go +++ b/cmd/compute/instance/instance_snapshot_show.go @@ -13,13 +13,14 @@ import ( ) type instanceSnapshotShowOutput struct { - ID string `json:"id"` - Name string `json:"name"` - CreationDate string `json:"creation_date"` - State string `json:"state"` - Size int64 `json:"size" outputLabel:"Size (GB)"` - Instance string `json:"instance"` - Zone string `json:"zone"` + ID string `json:"id"` + Name string `json:"name"` + CreationDate string `json:"creation_date"` + State string `json:"state"` + Size int64 `json:"size" outputLabel:"Size (GB)"` + Instance string `json:"instance"` + Zone string `json:"zone"` + AppConsistentSnapshot bool `json:"application_consistent_snapshot" outputLabel:"Application Consistent Snapshot"` } func (o *instanceSnapshotShowOutput) Type() string { return "Snapshot" } @@ -76,13 +77,14 @@ func (c *instanceSnapshotShowCmd) CmdRun(_ *cobra.Command, _ []string) error { } return c.OutputFunc(&instanceSnapshotShowOutput{ - ID: snapshot.ID.String(), - Name: snapshot.Name, - CreationDate: snapshot.CreatedAT.String(), - State: string(snapshot.State), - Size: snapshot.Size, - Instance: instance.Name, - Zone: c.Zone, + ID: snapshot.ID.String(), + Name: snapshot.Name, + CreationDate: snapshot.CreatedAT.String(), + State: string(snapshot.State), + Size: snapshot.Size, + Instance: instance.Name, + Zone: c.Zone, + AppConsistentSnapshot: *snapshot.ApplicationConsistent, }, nil) } diff --git a/cmd/compute/instance/instance_update.go b/cmd/compute/instance/instance_update.go index 6383f14c..c02db955 100644 --- a/cmd/compute/instance/instance_update.go +++ b/cmd/compute/instance/instance_update.go @@ -21,13 +21,14 @@ type instanceUpdateCmd struct { Instance string `cli-arg:"#" cli-usage:"NAME|ID"` - CloudInitFile string `cli-flag:"cloud-init" cli-short:"c" cli-usage:"instance cloud-init user data configuration file path"` - CloudInitCompress bool `cli-flag:"cloud-init-compress" cli-usage:"compress instance cloud-init user data"` - Labels map[string]string `cli-flag:"label" cli-usage:"instance label (format: key=value)"` - Name string `cli-short:"n" cli-usage:"instance name"` - Protection bool `cli-flag:"protection" cli-usage:"delete protection; set --protection=false to disable instance protection"` - Zone string `cli-short:"z" cli-usage:"instance zone"` - ReverseDNS string `cli-usage:"Reverse DNS Domain"` + AppConsistentSnapshot bool `cli-flag:"application-consistent-snapshot-enabled" cli-usage:"update instance application-consistent snapshots"` + CloudInitFile string `cli-flag:"cloud-init" cli-short:"c" cli-usage:"instance cloud-init user data configuration file path"` + CloudInitCompress bool `cli-flag:"cloud-init-compress" cli-usage:"compress instance cloud-init user data"` + Labels map[string]string `cli-flag:"label" cli-usage:"instance label (format: key=value)"` + Name string `cli-short:"n" cli-usage:"instance name"` + Protection bool `cli-flag:"protection" cli-usage:"delete protection; set --protection=false to disable instance protection"` + Zone string `cli-short:"z" cli-usage:"instance zone"` + ReverseDNS string `cli-usage:"Reverse DNS Domain"` } func (c *instanceUpdateCmd) CmdAliases() []string { return nil } @@ -95,6 +96,11 @@ func (c *instanceUpdateCmd) CmdRun(cmd *cobra.Command, _ []string) error { updatedRDNS = true } + if cmd.Flags().Changed(exocmd.MustCLICommandFlagName(c, &c.AppConsistentSnapshot)) { + updateRequest.ApplicationConsistentSnapshotEnabled = &c.AppConsistentSnapshot + updatedInstance = true + } + if updatedInstance || updatedRDNS || cmd.Flags().Changed(exocmd.MustCLICommandFlagName(c, &c.Protection)) { if updatedInstance { diff --git a/cmd/compute/instance_pool/instance_pool_update.go b/cmd/compute/instance_pool/instance_pool_update.go index ad5e3722..1377e70f 100644 --- a/cmd/compute/instance_pool/instance_pool_update.go +++ b/cmd/compute/instance_pool/instance_pool_update.go @@ -22,25 +22,26 @@ type instancePoolUpdateCmd struct { InstancePool string `cli-arg:"#" cli-usage:"NAME|ID"` - AntiAffinityGroups []string `cli-flag:"anti-affinity-group" cli-short:"a" cli-usage:"managed Compute instances Anti-Affinity Group NAME|ID (can be specified multiple times)"` - CloudInitFile string `cli-flag:"cloud-init" cli-short:"c" cli-usage:"cloud-init user data configuration file path"` - CloudInitCompress bool `cli-flag:"cloud-init-compress" cli-usage:"compress instance cloud-init user data"` - DeployTarget string `cli-usage:"managed Compute instances Deploy Target NAME|ID"` - Description string `cli-usage:"Instance Pool description"` - DiskSize int64 `cli-usage:"managed Compute instances disk size"` - ElasticIPs []string `cli-flag:"elastic-ip" cli-short:"e" cli-usage:"managed Compute instances Elastic IP ADDRESS|ID (can be specified multiple times)"` - IPv6 bool `cli-flag:"ipv6" cli-short:"6" cli-usage:"enable IPv6 on managed Compute instances"` - InstancePrefix string `cli-usage:"string to prefix managed Compute instances names with"` - InstanceType string `cli-usage:"managed Compute instances type (format: [FAMILY.]SIZE)"` - Labels map[string]string `cli-flag:"label" cli-usage:"Instance Pool label (format: key=value)"` - MinAvailable int64 `cli-usage:"Minimum number of running Instances"` - Name string `cli-short:"n" cli-usage:"Instance Pool name"` - PrivateNetworks []string `cli-flag:"private-network" cli-usage:"managed Compute instances Private Network NAME|ID (can be specified multiple times)"` - SSHKey string `cli-flag:"ssh-key" cli-usage:"SSH key to deploy on managed Compute instances"` - SecurityGroups []string `cli-flag:"security-group" cli-short:"s" cli-usage:"managed Compute instances Security Group NAME|ID (can be specified multiple times)"` - Template string `cli-short:"t" cli-usage:"managed Compute instances template NAME|ID"` - TemplateVisibility string `cli-usage:"instance template visibility (public|private)"` - Zone v3.ZoneName `cli-short:"z" cli-usage:"Instance Pool zone"` + AppConsistentSnapshotEnabled bool `cli-flag:"application-consistent-snapshot-enabled" cli-usage:"enable application-consistent snapshots if supported; set false to disable; omit to use template default value"` + AntiAffinityGroups []string `cli-flag:"anti-affinity-group" cli-short:"a" cli-usage:"managed Compute instances Anti-Affinity Group NAME|ID (can be specified multiple times)"` + CloudInitFile string `cli-flag:"cloud-init" cli-short:"c" cli-usage:"cloud-init user data configuration file path"` + CloudInitCompress bool `cli-flag:"cloud-init-compress" cli-usage:"compress instance cloud-init user data"` + DeployTarget string `cli-usage:"managed Compute instances Deploy Target NAME|ID"` + Description string `cli-usage:"Instance Pool description"` + DiskSize int64 `cli-usage:"managed Compute instances disk size"` + ElasticIPs []string `cli-flag:"elastic-ip" cli-short:"e" cli-usage:"managed Compute instances Elastic IP ADDRESS|ID (can be specified multiple times)"` + IPv6 bool `cli-flag:"ipv6" cli-short:"6" cli-usage:"enable IPv6 on managed Compute instances"` + InstancePrefix string `cli-usage:"string to prefix managed Compute instances names with"` + InstanceType string `cli-usage:"managed Compute instances type (format: [FAMILY.]SIZE)"` + Labels map[string]string `cli-flag:"label" cli-usage:"Instance Pool label (format: key=value)"` + MinAvailable int64 `cli-usage:"Minimum number of running Instances"` + Name string `cli-short:"n" cli-usage:"Instance Pool name"` + PrivateNetworks []string `cli-flag:"private-network" cli-usage:"managed Compute instances Private Network NAME|ID (can be specified multiple times)"` + SSHKey string `cli-flag:"ssh-key" cli-usage:"SSH key to deploy on managed Compute instances"` + SecurityGroups []string `cli-flag:"security-group" cli-short:"s" cli-usage:"managed Compute instances Security Group NAME|ID (can be specified multiple times)"` + Template string `cli-short:"t" cli-usage:"managed Compute instances template NAME|ID"` + TemplateVisibility string `cli-usage:"instance template visibility (public|private)"` + Zone v3.ZoneName `cli-short:"z" cli-usage:"Instance Pool zone"` } func (c *instancePoolUpdateCmd) CmdAliases() []string { return nil } @@ -163,6 +164,11 @@ func (c *instancePoolUpdateCmd) CmdRun(cmd *cobra.Command, _ []string) error { / updated = true } + if cmd.Flags().Changed(exocmd.MustCLICommandFlagName(c, &c.AppConsistentSnapshotEnabled)) { + updateReq.ApplicationConsistentSnapshotEnabled = &c.AppConsistentSnapshotEnabled + updated = true + } + if cmd.Flags().Changed(exocmd.MustCLICommandFlagName(c, &c.Labels)) { updateReq.Labels = exocmd.ConvertIfSpecialEmptyMap(c.Labels) updated = true diff --git a/cmd/compute/instance_template/instance_template_register.go b/cmd/compute/instance_template/instance_template_register.go index 32a4c511..3ea96635 100644 --- a/cmd/compute/instance_template/instance_template_register.go +++ b/cmd/compute/instance_template/instance_template_register.go @@ -22,6 +22,8 @@ type instanceTemplateRegisterCmd struct { URL string `cli-arg:"#"` Checksum string `cli-arg:"#"` + AppConsistentSnapshotEnabled bool `json:"application_consistent_snapshot" outputLabel:"Template with support for Application Consistent Snapshot"` + BootMode string `cli-usage:"template boot mode (legacy|uefi)"` Description string `cli-usage:"template description"` Build string `cli-usage:"template build"` @@ -84,16 +86,17 @@ func (c *instanceTemplateRegisterCmd) CmdRun(cmd *cobra.Command, _ []string) err sshKeyEnabled := !c.DisableSSHKey templateRequest = v3.RegisterTemplateRequest{ - Checksum: c.Checksum, - DefaultUser: c.Username, - Description: c.Description, - Build: c.Build, - Version: c.Version, - Maintainer: c.Maintainer, - Name: c.Name, - PasswordEnabled: &passwordEnabled, - SSHKeyEnabled: &sshKeyEnabled, - URL: c.URL, + ApplicationConsistentSnapshotEnabled: &c.AppConsistentSnapshotEnabled, + Checksum: c.Checksum, + DefaultUser: c.Username, + Description: c.Description, + Build: c.Build, + Version: c.Version, + Maintainer: c.Maintainer, + Name: c.Name, + PasswordEnabled: &passwordEnabled, + SSHKeyEnabled: &sshKeyEnabled, + URL: c.URL, } if c.FromSnapshot != "" { @@ -155,6 +158,7 @@ func (c *instanceTemplateRegisterCmd) CmdRun(cmd *cobra.Command, _ []string) err } else { templateRequest.DefaultUser = srcTemplate.DefaultUser } + } if cmd.Flags().Changed(exocmd.MustCLICommandFlagName(c, &c.BootMode)) { diff --git a/cmd/compute/instance_template/instance_template_show.go b/cmd/compute/instance_template/instance_template_show.go index edd6a5b7..b256b000 100644 --- a/cmd/compute/instance_template/instance_template_show.go +++ b/cmd/compute/instance_template/instance_template_show.go @@ -17,22 +17,23 @@ import ( ) type instanceTemplateShowOutput struct { - ID string `json:"id"` - Zone string `json:"zone"` - Name string `json:"name"` - Description string `json:"description"` - Family string `json:"family"` - CreationDate string `json:"creation_date"` - Visibility string `json:"visibility"` - Size int64 `json:"size"` - Version string `json:"version"` - Build string `json:"build"` - Maintainer string `json:"maintainer"` - DefaultUser string `json:"default_user"` - SSHKeyEnabled bool `json:"ssh_key_enabled"` - PasswordEnabled bool `json:"password_enabled"` - BootMode string `json:"boot_mode"` - Checksum string `json:"checksum"` + ID string `json:"id"` + Zone string `json:"zone"` + Name string `json:"name"` + Description string `json:"description"` + Family string `json:"family"` + CreationDate string `json:"creation_date"` + Visibility string `json:"visibility"` + Size int64 `json:"size"` + Version string `json:"version"` + Build string `json:"build"` + Maintainer string `json:"maintainer"` + DefaultUser string `json:"default_user"` + SSHKeyEnabled bool `json:"ssh_key_enabled"` + PasswordEnabled bool `json:"password_enabled"` + BootMode string `json:"boot_mode"` + Checksum string `json:"checksum"` + AppConsistentSnapshotEnabled bool `json:"application_consistent_snapshot_enabled"` } func (o *instanceTemplateShowOutput) ToJSON() { output.JSON(o) } @@ -58,6 +59,7 @@ func (o *instanceTemplateShowOutput) ToTable() { t.Append([]string{"Password enabled", fmt.Sprint(o.PasswordEnabled)}) t.Append([]string{"Boot Mode", o.BootMode}) t.Append([]string{"Checksum", o.Checksum}) + t.Append([]string{"Application Consistent Snapshot Enabled", fmt.Sprint(o.AppConsistentSnapshotEnabled)}) } type instanceTemplateShowCmd struct { @@ -107,22 +109,23 @@ func (c *instanceTemplateShowCmd) CmdRun(_ *cobra.Command, _ []string) error { } return c.OutputFunc(&instanceTemplateShowOutput{ - ID: template.ID.String(), - Zone: c.Zone, - Family: template.Family, - Name: template.Name, - Description: template.Description, - CreationDate: template.CreatedAT.String(), - Visibility: string(template.Visibility), - Size: template.Size, - Version: template.Version, - Build: template.Build, - Maintainer: template.Maintainer, - Checksum: template.Checksum, - DefaultUser: template.DefaultUser, - SSHKeyEnabled: utils.DefaultBool(template.SSHKeyEnabled, false), - PasswordEnabled: utils.DefaultBool(template.PasswordEnabled, false), - BootMode: string(template.BootMode), + ID: template.ID.String(), + Zone: c.Zone, + Family: template.Family, + Name: template.Name, + Description: template.Description, + CreationDate: template.CreatedAT.String(), + Visibility: string(template.Visibility), + Size: template.Size, + Version: template.Version, + Build: template.Build, + Maintainer: template.Maintainer, + Checksum: template.Checksum, + DefaultUser: template.DefaultUser, + SSHKeyEnabled: utils.DefaultBool(template.SSHKeyEnabled, false), + PasswordEnabled: utils.DefaultBool(template.PasswordEnabled, false), + BootMode: string(template.BootMode), + AppConsistentSnapshotEnabled: utils.DefaultBool(template.ApplicationConsistentSnapshotEnabled, false), }, nil) }