diff --git a/module/move/willbe/src/action/deploy_renew.rs b/module/move/willbe/src/action/deploy_renew.rs index 2a6d3b52fd..56bf766550 100644 --- a/module/move/willbe/src/action/deploy_renew.rs +++ b/module/move/willbe/src/action/deploy_renew.rs @@ -5,146 +5,80 @@ mod private use error::{ untyped::Context }; use tool::template::*; - // /// Template for creating deploy files. - // /// - // /// Includes terraform deploy options to GCP, and Hetzner, - // /// a Makefile for useful commands, and a key directory. - // #[ derive( Debug ) ] - // pub struct DeployTemplate - // { - // files : DeployTemplateFiles, - // parameters : TemplateParameters, - // values : TemplateValues, - // } - - // // qqq : for Viktor : why DeployTemplate can't be part of template.rs? - - // impl Template< DeployTemplateFiles > for DeployTemplate - // { - // fn create_all( self, path : &Path ) -> error::untyped::Result< () > - // { - // self.files.create_all( path, &self.values ) - // } - - // fn parameters( &self ) -> &TemplateParameters - // { - // &self.parameters - // } - - // fn set_values( &mut self, values : TemplateValues ) - // { - // self.values = values - // } - - // fn get_values( &self ) -> &TemplateValues - // { - // &self.values - // } - - // fn get_values_mut( &mut self ) -> &mut TemplateValues - // { - // &mut self.values - // } - - // fn parameter_storage( &self ) -> &Path { - // "./.deploy_template.toml".as_ref() - // } - - // fn template_name( &self ) -> &'static str { - // "deploy" - // } - // } - - // impl Default for DeployTemplate - // { - // fn default() -> Self - // { - // let parameters = TemplateParameters::former() - // .parameter( "gcp_project_id" ).is_mandatory( true ).end() - // .parameter( "gcp_region" ).end() - // .parameter( "gcp_artifact_repo_name" ).end() - // .parameter( "docker_image_name" ).end() - // .form(); - - // Self - // { - // files : Default::default(), - // parameters, - // values : Default::default(), - // } - // } - // } - - // // qqq : for Viktor : is that structure required? - // /// Files for the deploy template. - // /// - // /// Default implementation contains all required files. - // #[ derive( Debug ) ] - // pub struct DeployTemplateFiles( Vec< TemplateFileDescriptor > ); - - // impl Default for DeployTemplateFiles - // { - // fn default() -> Self - // { - // let formed = TemplateFilesBuilder::former() - // // root - // .file().data( include_str!( "../../template/deploy/.deploy_template.toml.hbs" ) ).path( "./.deploy_template.toml" ).mode( WriteMode::TomlExtend ).is_template( true ).end() - // .file().data( include_str!( "../../template/deploy/Makefile.hbs" ) ).path( "./Makefile" ).is_template( true ).end() - // // /key - // .file().data( include_str!( "../../template/deploy/key/pack.sh" ) ).path( "./key/pack.sh" ).end() - // .file().data( include_str!( "../../template/deploy/key/Readme.md" ) ).path( "./key/Readme.md" ).end() - // // /deploy/ - // .file().data( include_str!( "../../template/deploy/deploy/Dockerfile" ) ).path( "./deploy/Dockerfile" ).end() - // .file().data( include_str!( "../../template/deploy/deploy/Readme.md" ) ).path( "./deploy/Readme.md" ).end() - // // /deploy/gar - // .file().data( include_str!( "../../template/deploy/deploy/gar/Readme.md" ) ).path( "./deploy/gar/Readme.md" ).end() - // .file().data( include_str!( "../../template/deploy/deploy/gar/main.tf" ) ).path( "./deploy/gar/main.tf" ).end() - // .file().data( include_str!( "../../template/deploy/deploy/gar/outputs.tf" ) ).path( "./deploy/gar/outputs.tf" ).end() - // .file().data( include_str!( "../../template/deploy/deploy/gar/variables.tf" ) ).path( "./deploy/gar/variables.tf" ).end() - // // /deploy/gce - // .file().data( include_str!( "../../template/deploy/deploy/gce/Readme.md" ) ).path( "./deploy/gce/Readme.md" ).end() - // .file().data( include_str!( "../../template/deploy/deploy/gce/main.tf" ) ).path( "./deploy/gce/main.tf" ).end() - // .file().data( include_str!( "../../template/deploy/deploy/gce/outputs.tf" ) ).path( "./deploy/gce/outputs.tf" ).end() - // .file().data( include_str!( "../../template/deploy/deploy/gce/variables.tf" ) ).path( "./deploy/gce/variables.tf" ).end() - // // /deploy/gce/templates - // .file().data( include_str!( "../../template/deploy/deploy/gce/templates/cloud-init.tpl" ) ).path( "./deploy/gce/templates/cloud-init.tpl" ).end() - // // /deploy/gcs - // .file().data( include_str!( "../../template/deploy/deploy/gcs/main.tf" ) ).path( "./deploy/gcs/main.tf" ).end() - // // /deploy/hetzner - // .file().data( include_str!( "../../template/deploy/deploy/hetzner/main.tf" ) ).path( "./deploy/hetzner/main.tf" ).end() - // .file().data( include_str!( "../../template/deploy/deploy/hetzner/outputs.tf" ) ).path( "./deploy/hetzner/outputs.tf" ).end() - // .file().data( include_str!( "../../template/deploy/deploy/hetzner/variables.tf" ) ).path( "./deploy/hetzner/variables.tf" ).end() - // // /deploy/hetzner/templates - // .file().data( include_str!( "../../template/deploy/deploy/hetzner/templates/cloud-init.tpl" ) ).path( "./deploy/hetzner/templates/cloud-init.tpl" ).end() - // // /deploy/aws - // .file().data( include_str!( "../../template/deploy/deploy/aws/main.tf" ) ).path( "./deploy/aws/main.tf" ).end() - // .file().data( include_str!( "../../template/deploy/deploy/aws/outputs.tf" ) ).path( "./deploy/aws/outputs.tf" ).end() - // .file().data( include_str!( "../../template/deploy/deploy/aws/variables.tf" ) ).path( "./deploy/aws/variables.tf" ).end() - // // /deploy/aws/templates - // .file().data( include_str!( "../../template/deploy/deploy/aws/templates/cloud-init.tpl" ) ).path( "./deploy/aws/templates/cloud-init.tpl" ).end() - // .form(); - - // Self( formed.files ) - // } - // } - - // // qqq : for Viktor : should not be required - // impl TemplateFiles for DeployTemplateFiles {} - // // qqq : for Viktor : should not be required - // impl IntoIterator for DeployTemplateFiles - // { - // type Item = TemplateFileDescriptor; - - // type IntoIter = std::vec::IntoIter< Self::Item >; - - // fn into_iter( self ) -> Self::IntoIter - // { - // self.0.into_iter() - // } - // } + /// Template for creating deploy files. + /// + /// Includes terraform deploy options to GCP, and Hetzner, + /// a Makefile for useful commands, and a key directory. + #[ derive( Debug ) ] + pub struct DeployTemplate; + + impl DeployTemplate + { + /// Creates am instance of `[TemplateHolder]` for deployment template. + /// + /// Used for properly initializing a template + pub fn default() -> TemplateHolder + { + let parameters = TemplateParameters::former() + .parameter( "gcp_project_id" ).is_mandatory( true ).end() + .parameter( "gcp_region" ).end() + .parameter( "gcp_artifact_repo_name" ).end() + .parameter( "docker_image_name" ).end() + .form(); + + TemplateHolder + { + files : get_deploy_template_files(), + parameters, + values : Default::default(), + parameter_storage : "./.deploy_template.toml".as_ref(), + template_name : "deploy", + } + } + } - // aaa : for Petro : redundant function - // aaa : this function not my, but ok I'll remove it. + fn get_deploy_template_files() -> Vec< TemplateFileDescriptor > + { + let formed = TemplateFilesBuilder::former() + // root + .file().data( include_str!( "../../template/deploy/.deploy_template.toml.hbs" ) ).path( "./.deploy_template.toml" ).mode( WriteMode::TomlExtend ).is_template( true ).end() + .file().data( include_str!( "../../template/deploy/Makefile.hbs" ) ).path( "./Makefile" ).is_template( true ).end() + // /key + .file().data( include_str!( "../../template/deploy/key/pack.sh" ) ).path( "./key/pack.sh" ).end() + .file().data( include_str!( "../../template/deploy/key/Readme.md" ) ).path( "./key/Readme.md" ).end() + // /deploy/ + .file().data( include_str!( "../../template/deploy/deploy/Dockerfile" ) ).path( "./deploy/Dockerfile" ).end() + .file().data( include_str!( "../../template/deploy/deploy/Readme.md" ) ).path( "./deploy/Readme.md" ).end() + // /deploy/gar + .file().data( include_str!( "../../template/deploy/deploy/gar/Readme.md" ) ).path( "./deploy/gar/Readme.md" ).end() + .file().data( include_str!( "../../template/deploy/deploy/gar/main.tf" ) ).path( "./deploy/gar/main.tf" ).end() + .file().data( include_str!( "../../template/deploy/deploy/gar/outputs.tf" ) ).path( "./deploy/gar/outputs.tf" ).end() + .file().data( include_str!( "../../template/deploy/deploy/gar/variables.tf" ) ).path( "./deploy/gar/variables.tf" ).end() + // /deploy/gce + .file().data( include_str!( "../../template/deploy/deploy/gce/Readme.md" ) ).path( "./deploy/gce/Readme.md" ).end() + .file().data( include_str!( "../../template/deploy/deploy/gce/main.tf" ) ).path( "./deploy/gce/main.tf" ).end() + .file().data( include_str!( "../../template/deploy/deploy/gce/outputs.tf" ) ).path( "./deploy/gce/outputs.tf" ).end() + .file().data( include_str!( "../../template/deploy/deploy/gce/variables.tf" ) ).path( "./deploy/gce/variables.tf" ).end() + // /deploy/gce/templates + .file().data( include_str!( "../../template/deploy/deploy/gce/templates/cloud-init.tpl" ) ).path( "./deploy/gce/templates/cloud-init.tpl" ).end() + // /deploy/gcs + .file().data( include_str!( "../../template/deploy/deploy/gcs/main.tf" ) ).path( "./deploy/gcs/main.tf" ).end() + // /deploy/hetzner + .file().data( include_str!( "../../template/deploy/deploy/hetzner/main.tf.hbs" ) ).path( "./deploy/hetzner/main.tf" ).is_template( true ).end() + .file().data( include_str!( "../../template/deploy/deploy/hetzner/outputs.tf.hbs" ) ).path( "./deploy/hetzner/outputs.tf" ).is_template( true ).end() + .file().data( include_str!( "../../template/deploy/deploy/hetzner/variables.tf" ) ).path( "./deploy/hetzner/variables.tf" ).end() + // /deploy/hetzner/templates + .file().data( include_str!( "../../template/deploy/deploy/hetzner/templates/cloud-init.tpl.hbs" ) ).path( "./deploy/hetzner/templates/cloud-init.tpl" ).end() + // /deploy/aws + .file().data( include_str!( "../../template/deploy/deploy/aws/main.tf" ) ).path( "./deploy/aws/main.tf" ).end() + .file().data( include_str!( "../../template/deploy/deploy/aws/outputs.tf" ) ).path( "./deploy/aws/outputs.tf" ).end() + .file().data( include_str!( "../../template/deploy/deploy/aws/variables.tf" ) ).path( "./deploy/aws/variables.tf" ).end() + // /deploy/aws/templates + .file().data( include_str!( "../../template/deploy/deploy/aws/templates/cloud-init.tpl.hbs" ) ).path( "./deploy/aws/templates/cloud-init.tpl" ).is_template( true ).end() + .form(); + + formed.files + } fn dir_name_to_formatted( dir_name : &str, separator : &str ) -> String { @@ -179,7 +113,6 @@ mod private template .values .insert_if_empty( "gcp_artifact_repo_name", wca::Value::String( artifact_repo_name ) ); - template .values .insert_if_empty( "docker_image_name", wca::Value::String( docker_image_name ) ); @@ -187,7 +120,7 @@ mod private .values .insert_if_empty( "gcp_region", wca::Value::String( "europe-central2".into() ) ); } - template.create_all( path )?; + template.files.create_all( path, &template.values )?; Ok( () ) } @@ -196,5 +129,5 @@ mod private crate::mod_interface! { orphan use deploy_renew; - //orphan use DeployTemplate; + orphan use DeployTemplate; } diff --git a/module/move/willbe/src/command/deploy_renew.rs b/module/move/willbe/src/command/deploy_renew.rs index c66107fe8d..7e1e68e476 100644 --- a/module/move/willbe/src/command/deploy_renew.rs +++ b/module/move/willbe/src/command/deploy_renew.rs @@ -4,9 +4,7 @@ mod private use wca::VerifiedCommand; use error::{ untyped::Context }; - use tool::TemplateHolder; - //use tool::template::Template; - // use action::deploy_renew::*; + use action::deploy_renew::*; /// /// Create new deploy. @@ -17,7 +15,7 @@ mod private { let current_dir = std::env::current_dir()?; - let mut template = TemplateHolder::default(); + let mut template = DeployTemplate::default(); _ = template.load_existing_params( ¤t_dir ); let parameters = template.parameters(); let mut values = parameters.values_from_props( &o.props ); diff --git a/module/move/willbe/src/command/mod.rs b/module/move/willbe/src/command/mod.rs index f6115c3f10..6b87d5877b 100644 --- a/module/move/willbe/src/command/mod.rs +++ b/module/move/willbe/src/command/mod.rs @@ -225,7 +225,7 @@ with_gitpod: If set to 1, a column with a link to Gitpod will be added. Clicking .command( "deploy.renew" ) .hint( "Create deploy template" ) - .long_hint( "Creates static files and directories.\nDeployment to different hosts is done via Makefile." ) + .long_hint( "Creates static files and directories.\nDeployment to different hosts is done via Makefile.\n\nUsage example: deploy.renew gcp_project_id:wtools" ) .property( "gcp_project_id" ) .hint( "Google Cloud Platform Project id for image deployment, terraform state bucket, and, if specified, GCE instance deployment." ) .kind( Type::String ) @@ -239,12 +239,12 @@ with_gitpod: If set to 1, a column with a link to Gitpod will be added. Clicking .property( "gcp_artifact_repo_name" ) .hint( "Google Cloud Platform Artifact Repository to store docker image in. Will be generated from current directory name if unspecified." ) .kind( Type::String ) - .optional( false ) + .optional( true ) .end() .property( "docker_image_name" ) .hint( "Docker image name to build and deploy. Will be generated from current directory name if unspecified." ) .kind( Type::String ) - .optional( false ) + .optional( true ) .end() .routine( command::deploy_renew ) .end() diff --git a/module/move/willbe/src/tool/template.rs b/module/move/willbe/src/tool/template.rs index affe4072be..bd90b0b5d7 100644 --- a/module/move/willbe/src/tool/template.rs +++ b/module/move/willbe/src/tool/template.rs @@ -15,15 +15,10 @@ mod private }; use error::untyped::Context; - // qqq : for Nikita : is that trait really necessary? - // Template - remove - // DeployTemplate - move here - // DeployTemplateFiles - remove - - /// Template for creating deploy files. + /// Container for templates. /// - /// Includes terraform deploy options to GCP, and Hetzner, - /// a Makefile for useful commands, and a key directory. + /// Includes files to create, parameters that those templates accept, + /// and values for those parameters. #[ derive( Debug ) ] pub struct TemplateHolder { @@ -33,11 +28,15 @@ mod private pub parameters : TemplateParameters, /// The values associated with the template. pub values : TemplateValues, + /// Path to the parameter storage for recovering values + /// for already generated templated files. + pub parameter_storage : &'static Path, + /// Name of the template to generate + pub template_name : &'static str, } impl TemplateFiles for Vec< TemplateFileDescriptor > {} - // qqq : for Viktor : why DeployTemplate can't be part of template.rs? impl TemplateHolder { @@ -95,27 +94,6 @@ mod private &mut self.values } - /// Returns the path to the parameter storage file. - /// - /// # Returns - /// - /// A reference to a `Path` representing the parameter storage file. - pub fn parameter_storage( &self ) -> &Path - { - "./.deploy_template.toml".as_ref() - // qqq : for Mykyta : hardcode? - } - - /// Returns the name of the template. - /// - /// # Returns - /// - /// A static string slice representing the template name. - pub fn template_name( &self ) -> &'static str - { - "deploy" - } - /// Loads existing parameters from the specified path and updates the template values. /// /// # Parameters @@ -127,10 +105,10 @@ mod private /// An `Option` which is `Some(())` if the parameters are loaded successfully, or `None` otherwise. pub fn load_existing_params( &mut self, path : &Path ) -> Option< () > { - let data = fs::read_to_string( path.join( self.parameter_storage() ) ).ok()?; + let data = fs::read_to_string( path.join( self.parameter_storage ) ).ok()?; let document = data.parse::< toml_edit::Document >().ok()?; let parameters : Vec< _ > = self.parameters().descriptors.iter().map( | d | &d.parameter ).cloned().collect(); - let template_table = document.get( self.template_name() )?; + let template_table = document.get( self.template_name )?; for parameter in parameters { let value = template_table.get( ¶meter ) @@ -164,26 +142,6 @@ mod private } } - impl Default for TemplateHolder - { - fn default() -> Self - { - let parameters = TemplateParameters::former() - .parameter( "gcp_project_id" ).is_mandatory( true ).end() - .parameter( "gcp_region" ).end() - .parameter( "gcp_artifact_repo_name" ).end() - .parameter( "docker_image_name" ).end() - .form(); - - Self - { - files : Default::default(), - parameters, - values : Default::default(), - } - } - } - /// Files stored in a template. /// /// Can be iterated over, consuming the owner of the files. diff --git a/module/move/willbe/template/deploy/Makefile.hbs b/module/move/willbe/template/deploy/Makefile.hbs index 2f3461aea8..f3cc528435 100644 --- a/module/move/willbe/template/deploy/Makefile.hbs +++ b/module/move/willbe/template/deploy/Makefile.hbs @@ -26,7 +26,7 @@ export TF_VAR_IMAGE_NAME ?= {{docker_image_name}} # Path to the service account credentials export google_sa_creds ?= key/service_account.json # Cloud Storage bucket name -export TF_VAR_BUCKET_NAME ?= uaconf_tfstate +export TF_VAR_BUCKET_NAME ?= {{docker_image_name}}_tfstate # Specifies where to deploy the project. Possible values: `hetzner`, `gce`, `aws` export CSP ?= hetzner diff --git a/module/move/willbe/template/deploy/deploy/aws/templates/cloud-init.tpl b/module/move/willbe/template/deploy/deploy/aws/templates/cloud-init.tpl.hbs similarity index 95% rename from module/move/willbe/template/deploy/deploy/aws/templates/cloud-init.tpl rename to module/move/willbe/template/deploy/deploy/aws/templates/cloud-init.tpl.hbs index 7a19732c3a..78a74e4837 100644 --- a/module/move/willbe/template/deploy/deploy/aws/templates/cloud-init.tpl +++ b/module/move/willbe/template/deploy/deploy/aws/templates/cloud-init.tpl.hbs @@ -43,4 +43,4 @@ write_files: runcmd: -- nohup /root/init.sh > /var/log/uaconf-instance-init.log 2>&1 & +- nohup /root/init.sh > /var/log/{{docker_image_name}}-instance-init.log 2>&1 & diff --git a/module/move/willbe/template/deploy/deploy/hetzner/main.tf b/module/move/willbe/template/deploy/deploy/hetzner/main.tf.hbs similarity index 90% rename from module/move/willbe/template/deploy/deploy/hetzner/main.tf rename to module/move/willbe/template/deploy/deploy/hetzner/main.tf.hbs index b0f2f60194..5611dafc2d 100644 --- a/module/move/willbe/template/deploy/deploy/hetzner/main.tf +++ b/module/move/willbe/template/deploy/deploy/hetzner/main.tf.hbs @@ -16,7 +16,7 @@ provider "hcloud" { # Static IP for the instance resource "hcloud_primary_ip" "primary_ip" { - name = "uaconf-2024-ip" + name = "{{docker_image_name}}-ip" datacenter = "hel1-dc2" type = "ipv4" assignee_type = "server" @@ -24,8 +24,8 @@ resource "hcloud_primary_ip" "primary_ip" { } # Hetzner instance itself -resource "hcloud_server" "uaconf" { - name = "uaconf-2024" +resource "hcloud_server" "{{docker_image_name}}" { + name = "{{docker_image_name}}" image = "ubuntu-22.04" server_type = "cx22" datacenter = "hel1-dc2" diff --git a/module/move/willbe/template/deploy/deploy/hetzner/outputs.tf b/module/move/willbe/template/deploy/deploy/hetzner/outputs.tf.hbs similarity index 86% rename from module/move/willbe/template/deploy/deploy/hetzner/outputs.tf rename to module/move/willbe/template/deploy/deploy/hetzner/outputs.tf.hbs index f6d2ebd5e8..ba994920c7 100644 --- a/module/move/willbe/template/deploy/deploy/hetzner/outputs.tf +++ b/module/move/willbe/template/deploy/deploy/hetzner/outputs.tf.hbs @@ -1,5 +1,5 @@ locals { - ip = hcloud_server.uaconf.ipv4_address + ip = hcloud_server.{{docker_image_name}}.ipv4_address } # Output that we get after applying. diff --git a/module/move/willbe/template/deploy/deploy/hetzner/templates/cloud-init.tpl b/module/move/willbe/template/deploy/deploy/hetzner/templates/cloud-init.tpl.hbs similarity index 95% rename from module/move/willbe/template/deploy/deploy/hetzner/templates/cloud-init.tpl rename to module/move/willbe/template/deploy/deploy/hetzner/templates/cloud-init.tpl.hbs index 37cb18d6e9..081db47304 100644 --- a/module/move/willbe/template/deploy/deploy/hetzner/templates/cloud-init.tpl +++ b/module/move/willbe/template/deploy/deploy/hetzner/templates/cloud-init.tpl.hbs @@ -43,4 +43,4 @@ write_files: runcmd: -- nohup /root/init.sh > /var/log/uaconf-instance-init.log 2>&1 & +- nohup /root/init.sh > /var/log/{{docker_image_name}}-instance-init.log 2>&1 &