# Hacking with Hammer ![](img/claw_hammer.jpg) Tomáš Strachota tstracho@redhat.com
Use arrow keys to switch the slides.
# History **April 2012** ![](img/initial_commit_1.png) **July 2013** ![](img/initial_commit_2.png) # History - 1.5 years later - hammer-cli v0.1.4 - 20 releases - 12 plugins - hammer-cli-foreman - hammer-cli-katello - hammer-cli-discovery - and others... - we have ~ 70% core commands ([http://projects.theforeman.org/projects/hammer-cli/wiki/List_of_Plugins](http://projects.theforeman.org/projects/hammer-cli/wiki/List_of_Plugins)) # Future - improving usability - improving internal API - completing command gaps and catching up with UI features # Tutorial - CLI for Foreman settings ![](img/issue.png) - hammer settings list - hammer settings set # Development setup ### Get the code ![](img/fork.png) ```bash > git clone git@github.com:theforeman/hammer-cli.git ``` ```bash > git clone git@github.com:theforeman/hammer-cli-foreman.git ``` ### Configure hammer ```bash mkdir -p ~/.hammer/cli.modules.d/ cp hammer-cli/config/cli_config.template.yml ~/.hammer/ cp hammer-cli-foreman/config/foreman.yml ~/.hammer/cli.modules.d/ ``` ### Plug the foreman in ```ruby # hammer-cli/Gemgile.local gem 'hammer_cli_foreman', :path => '../hammer-cli-foreman' ``` ```bash alias hammer=bundle exec hammer-cli/bin/hammer ``` # Before we start - Check online api documentation [http://www.theforeman.org/api_v2.html](http://www.theforeman.org/api_v2.html) - We're using **API v2** ! ![Settings API](img/settings_api.png) # Before we start - Hammer reuses information from ApiPie docs ![Settings API](img/settings_api_index_detail.png) # Where to place the command? hammer-cli-foreman structure ```bash > tree -d -L 1 . ├── config # Example configuration files ├── doc # Documentation ├── lib # The code itself ├── locale # Translations └── test # Unit tests ``` # Step 1 - Create a new command file ```bash > cd hammer-cli-foreman/lib && tree . ├── hammer_cli_foreman # One file per first level command │   ├── architecture.rb │   ├── associating_commands.rb │   ├── auth.rb │   ├── auth_source_ldap.rb │   ├── auth_source.rb │   ├── commands.rb │   ├── common_parameter.rb │   ├── compute_resource.rb │   ├── credentials.rb │   ├── dependency_resolver.rb │   ├── domain.rb ``` Create the file under a correct namespace: ```bash touch lib/hammer_cli_foreman/settings.rb ``` # Step 2 - Create a new command class ```ruby #lib/hammer_cli_foreman/settings.rb ``` # Step 2 - Create a new command class ```ruby #lib/hammer_cli_foreman/settings.rb module HammerCLIForeman end ``` Wrap all your commands in a module. # Step 2 - Create a new command class ```ruby #lib/hammer_cli_foreman/settings.rb module HammerCLIForeman # Wraper command class Settings < HammerCLIForeman::Command end end ``` Create wrapper command `hammer settings`. # Step 2 - Create a new command class ```ruby #lib/hammer_cli_foreman/settings.rb module HammerCLIForeman # Wraper command class Settings < HammerCLIForeman::Command # Set API resource resource :settings end end ``` Set the API resource. # Step 2 - Create a new command class ```ruby #lib/hammer_cli_foreman/settings.rb module HammerCLIForeman # Wraper command class Settings < HammerCLIForeman::Command # Set API resource resource :settings class ListCommand < HammerCLIForeman::ListCommand end end end ``` There are base command classes with predefined behavior: `ListCommand`, `ShowCommand`, `CreateCommand`, `UpdateCommand`, `DeleteCommand`. # Step 2 - Create a new command class ```ruby #lib/hammer_cli_foreman/settings.rb module HammerCLIForeman # Wraper command class Settings < HammerCLIForeman::Command # Set API resource resource :settings class ListCommand < HammerCLIForeman::ListCommand end autoload_subcommands # Plug the subcommands in end end ``` There are base command classes with predefined behavior: `ListCommand`, `ShowCommand`, `CreateCommand`, `UpdateCommand`, `DeleteCommand`. # Step 2 - Let's try the new command ```bash > hammer settings -h ``` # Step 2 - Let's try the new command ```bash > hammer settings -h Error: No such sub-command 'settings' See: 'hammer --help' ``` Setting is still missing... # Step 3 - Attach the new command Add magic lines to `lib/hammer_cli_foreman.rb` ... ```ruby HammerCLI::MainCommand.lazy_subcommand('settings', _("Change server settings."), # command description 'HammerCLIForeman::Settings', # command class 'hammer_cli_foreman/settings' # path to the command file ) ``` # Step 3 - Attach the new command Add magic lines to `lib/hammer_cli_foreman.rb` ... ```ruby HammerCLI::MainCommand.lazy_subcommand('settings', _("Change server settings."), # command description 'HammerCLIForeman::Settings', # command class 'hammer_cli_foreman/settings' # path to the command file ) ``` ...and try again. ```bash > hammer settings -h ``` # Step 3 - Attach the new command Add magic lines to `lib/hammer_cli_foreman.rb` ... ```ruby HammerCLI::MainCommand.lazy_subcommand('settings', _("Change server settings."), # command description 'HammerCLIForeman::Settings', # command class 'hammer_cli_foreman/settings' # path to the command file ) ``` ...and try again. ```bash > hammer settings -h Usage: hammer settings [OPTIONS] SUBCOMMAND [ARG] ... Parameters: SUBCOMMAND subcommand [ARG] ... subcommand arguments Subcommands: list List all settings Options: -h, --help print help ``` # Step 4 - Let's try listing ```bash > hammer settings list ``` # Step 4 - Let's try listing ```bash > hammer settings list > ``` ...no output # Step 4 - Let's try listing ```bash > hammer settings list > ``` ...no output ```bash > hammer -d settings list ``` # Step 4 - Let's try listing ```bash > hammer settings list > ``` ...no output ```bash > hammer -d settings list [ INFO 2015-01-28 14:59:40 Init] Initialization of Hammer CLI (0.1.4) has started... [DEBUG 2015-01-28 14:59:40 Init] Running at ruby 1.8.7-p374 [ INFO 2015-01-28 14:59:40 Init] Configuration from the file /etc/hammer/cli_config.yml has been loaded [ INFO 2015-01-28 14:59:40 Init] Configuration from the file /etc/hammer/cli.modules.d/foreman.yml has been loaded [ INFO 2015-01-28 14:59:40 Init] Configuration from the file /root/.hammer/cli_config.yml has been loaded [DEBUG 2015-01-28 14:59:41 Connection] Registered: foreman [DEBUG 2015-01-28 14:59:41 API] Global headers: { "Accept-Language" => "en", :accept => "application/json;version=2", :content_type => "application/json" } [DEBUG 2015-01-28 14:59:41 Init] Apipie cache was cleared [ INFO 2015-01-28 14:59:41 API] GET /apidoc/apipie_checksum [DEBUG 2015-01-28 14:59:41 API] Params: {} [DEBUG 2015-01-28 14:59:41 API] Headers: { :accept => "application/json", :params => {} } [DEBUG 2015-01-28 14:59:41 API] Response: { "checksum" => "0e10ccff1babc8fd126d0c0f0fb2a6cc" } [DEBUG 2015-01-28 14:59:41 API] Response headers: { :x_ua_compatible => "IE=Edge", :apipie_checksum => "0e10ccff1babc8fd126d0c0f0fb2a6cc", :set_cookie => [ [0] "request_method=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT" ], :server => "thin", :connection => "close", :content_type => "application/json; charset=utf-8", :cache_control => "max-age=0, private, must-revalidate", :x_request_id => "d9c19d5a76db080ddcbe435ab97fd84e", :etag => "\"91d0030428a55dfb6417ec20900fc504\"", :x_runtime => "0.011813" } [ INFO 2015-01-28 14:59:41 API] GET /apidoc/v2.en.json [DEBUG 2015-01-28 14:59:41 API] Params: {} [DEBUG 2015-01-28 14:59:41 API] Headers: { :accept => "application/json", :params => {} } [DEBUG 2015-01-28 14:59:41 API] 404 Resource Not Found " " [ INFO 2015-01-28 14:59:41 API] GET /apidoc/v2.json [DEBUG 2015-01-28 14:59:41 API] Params: {} [DEBUG 2015-01-28 14:59:41 API] Headers: { :accept => "application/json", :params => {} } [DEBUG 2015-01-28 14:59:41 API] Response: Received OK [DEBUG 2015-01-28 14:59:41 API] Response headers: { :x_ua_compatible => "IE=Edge", :apipie_checksum => "0e10ccff1babc8fd126d0c0f0fb2a6cc", :content_disposition => "inline; filename=\"v2.json\"", :content_transfer_encoding => "binary", :set_cookie => [ [0] "request_method=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT" ], :server => "thin", :connection => "close", :content_type => "application/json", :cache_control => "private", :x_request_id => "32908515ceba20efbd1e3e285008f386", :x_runtime => "0.008055" } [DEBUG 2015-01-28 14:59:41 API] New apidoc loaded from the server [ INFO 2015-01-28 14:59:41 API] GET /apidoc/apipie_checksum [DEBUG 2015-01-28 14:59:41 API] Params: {} [DEBUG 2015-01-28 14:59:41 API] Headers: { :accept => "application/json", :params => {} } [DEBUG 2015-01-28 14:59:41 API] Response: { "checksum" => "0e10ccff1babc8fd126d0c0f0fb2a6cc" } [DEBUG 2015-01-28 14:59:41 API] Response headers: { :x_ua_compatible => "IE=Edge", :apipie_checksum => "0e10ccff1babc8fd126d0c0f0fb2a6cc", :set_cookie => [ [0] "request_method=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT" ], :server => "thin", :connection => "close", :content_type => "application/json; charset=utf-8", :cache_control => "max-age=0, private, must-revalidate", :x_request_id => "67e406ef26d70767755c72dfeed91c84", :etag => "\"91d0030428a55dfb6417ec20900fc504\"", :x_runtime => "0.011414" } [ INFO 2015-01-28 14:59:41 Modules] Extension module hammer_cli_foreman (0.1.4) loaded [DEBUG 2015-01-28 14:59:41 Init] Using locale 'en' [DEBUG 2015-01-28 14:59:41 Init] 'mo' files for locale domain 'hammer-cli' loaded from '/root/hammer/hammer-cli/locale' [DEBUG 2015-01-28 14:59:41 Init] 'mo' files for locale domain 'hammer-cli@system' loaded from '/usr/share/locale' [DEBUG 2015-01-28 14:59:41 Init] 'mo' files for locale domain 'hammer-cli-foreman' loaded from '/root/hammer/hammer-cli-foreman/locale' [DEBUG 2015-01-28 14:59:41 Init] 'mo' files for locale domain 'hammer-cli-foreman@system' loaded from '/usr/share/locale' [ INFO 2015-01-28 14:59:41 HammerCLI::MainCommand] Called with options: {"option_debug"=>true} [ INFO 2015-01-28 14:59:41 HammerCLIForeman::Settings] Called with options: {} [ INFO 2015-01-28 14:59:41 HammerCLIForeman::Settings::ListCommand] Called with options: {} [ INFO 2015-01-28 14:59:41 API] GET /apidoc/apipie_checksum [DEBUG 2015-01-28 14:59:41 API] Params: {} [DEBUG 2015-01-28 14:59:41 API] Headers: { :accept => "application/json", :params => {} } [DEBUG 2015-01-28 14:59:41 API] Response: { "checksum" => "0e10ccff1babc8fd126d0c0f0fb2a6cc" } [DEBUG 2015-01-28 14:59:41 API] Response headers: { :x_ua_compatible => "IE=Edge", :apipie_checksum => "0e10ccff1babc8fd126d0c0f0fb2a6cc", :set_cookie => [ [0] "request_method=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT" ], :server => "thin", :connection => "close", :content_type => "application/json; charset=utf-8", :cache_control => "max-age=0, private, must-revalidate", :x_request_id => "62d7bc3377fc01af41347be65330e958", :etag => "\"91d0030428a55dfb6417ec20900fc504\"", :x_runtime => "0.011806" } [ INFO 2015-01-28 14:59:41 API] GET /api/settings [DEBUG 2015-01-28 14:59:41 API] Params: {} [DEBUG 2015-01-28 14:59:41 API] Headers: { :params => {} } [DEBUG 2015-01-28 14:59:41 API] Response: { "search" => nil, "per_page" => 20, "page" => 1, "subtotal" => 63, "total" => 63, "results" => [ [ 0] { "created_at" => "2014-06-20T17:29:20+01:00", "updated_at" => "2014-10-20T16:04:06+01:00", "settings_type" => "array", "description" => "Foreman will evaluate host smart variables in this order by default", "value" => [ [0] "fqdn", [1] "hostgroup", [2] "os", [3] "domain" ], "id" => 19, "category" => "Setting::Puppet", "default" => [ [0] "fqdn", [1] "hostgroup", [2] "os", [3] "domain" ], "name" => "Default_variables_Lookup_Path" }, [ 1] { "created_at" => "2014-06-20T17:29:20+01:00", "updated_at" => "2014-10-20T16:04:06+01:00", "settings_type" => "boolean", "description" => "Authorize login delegation with REMOTE_USER environment variable", "value" => false, "id" => 7, "category" => "Setting::General", "default" => false, "name" => "authorize_login_delegation" }, [ 2] { "created_at" => "2014-06-20T17:29:20+01:00", "updated_at" => "2014-10-20T16:04:06+01:00", "settings_type" => "boolean", "description" => "Authorize login delegation with REMOTE_USER environment variable for API calls too", "value" => false, "id" => 8, "category" => "Setting::General", "default" => false, "name" => "authorize_login_delegation_api" }, [ 3] { "created_at" => "2014-06-20T17:29:21+01:00", "updated_at" => "2014-10-20T16:04:07+01:00", "settings_type" => nil, "description" => "Name of the external auth source where unknown externally authentication users (see authorize_login_delegation) should be created (keep unset to prevent the autocreation)", "value" => nil, "id" => 60, "category" => "Setting::Auth", "default" => nil, "name" => "authorize_login_delegation_auth_source_user_autocreate" }, [ 4] { "created_at" => "2014-06-20T17:29:20+01:00", "updated_at" => "2014-10-20T16:04:07+01:00", "settings_type" => "boolean", "description" => "Foreman will create the host when new facts are received", "value" => true, "id" => 27, "category" => "Setting::Puppet", "default" => true, "name" => "create_new_host_when_facts_are_uploaded" } ], "sort" => { "by" => nil, "order" => nil } } [DEBUG 2015-01-28 14:59:41 API] Response headers: { :x_ua_compatible => "IE=Edge", :foreman_version => "1.8.0-develop", :apipie_checksum => "0e10ccff1babc8fd126d0c0f0fb2a6cc", :set_cookie => [ [0] "_session_id=7d26025dfc37197c1b0ec625f348e51b; path=/; HttpOnly", [1] "request_method=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT" ], :server => "thin", :connection => "close", :content_type => "application/json; charset=utf-8", :cache_control => "max-age=0, private, must-revalidate", :x_request_id => "eef017bbf59c52edb877cf6f9bbf968a", :etag => "\"5ca93855e32208e24ee30442357a7194\"", :x_runtime => "0.199984", :foreman_api_version => "2" } ``` # Step 5 - Defining the output Hammer needs to know which fields should be displayed. Where do I get available fields? - examples from API docs - running in debug mode `hammer -d` ```bash [14] { "id" => 15, "category" => "Setting::Puppet", "created_at" => "2014-06-20T17:29:20+01:00", "description" => "Document root where puppetdoc files should be created", "value" => "/root/foreman/public/puppet/rdoc", "updated_at" => "2014-10-20T16:04:06+01:00", "default" => "/root/foreman/public/puppet/rdoc", "settings_type" => "string", "name" => "document_root" }, ``` `name`, `value` and `description` seem to be important # Step 5 - Defining output fields ```ruby #lib/hammer_cli_foreman/settings.rb module HammerCLIForeman class Settings < HammerCLIForeman::Command resource :settings class ListCommand < HammerCLIForeman::ListCommand end autoload_subcommands end end ``` # Step 5 - Defining output fields ```ruby #lib/hammer_cli_foreman/settings.rb module HammerCLIForeman class Settings < HammerCLIForeman::Command resource :settings class ListCommand < HammerCLIForeman::ListCommand output do end end autoload_subcommands end end ``` # Step 5 - Defining output fields ```ruby #lib/hammer_cli_foreman/settings.rb module HammerCLIForeman class Settings < HammerCLIForeman::Command resource :settings class ListCommand < HammerCLIForeman::ListCommand output do field :name, _('Name') field :value, _('Value') field :description, _('Description') end end autoload_subcommands end end ``` # Step 5 - Defining output fields ```bash > hammer settings list ``` # Step 5 - Defining output fields ```bash > hammer settings list -------------------------------|------------|------------------- NAME | VALUE | DESCRIPTION -------------------------------|------------|------------------- Default_variables_Lookup_Path | [ "fqdn" ] | Foreman will evalu Enable_Smart_Variables_in_ENC | true | Foreman smart vari Parametrized_Classes_in_ENC | true | Foreman will use t authorize_login_delegation | | Authorize login de authorize_login_delegation_api | | Authorize login de ``` # Step 6 - Updating settings ```ruby #lib/hammer_cli_foreman/settings.rb class UpdateCommand < HammerCLIForeman::UpdateCommand end ``` ```bash > hammer settings update -h ``` # Step 6 - Updating settings ```ruby #lib/hammer_cli_foreman/settings.rb class UpdateCommand < HammerCLIForeman::UpdateCommand end ``` ```bash > hammer settings update -h Usage: hammer settings update [OPTIONS] Options: -h, --help print help ``` # Step 6 - Updating settings ```ruby #lib/hammer_cli_foreman/settings.rb class UpdateCommand < HammerCLIForeman::UpdateCommand # Change the default name command_name 'set' end ``` ```bash > hammer settings set -h ``` # Step 6 - Updating settings ```ruby #lib/hammer_cli_foreman/settings.rb class UpdateCommand < HammerCLIForeman::UpdateCommand # Change the default name command_name 'set' end ``` ```bash > hammer settings set -h Usage: hammer settings set [OPTIONS] Options: -h, --help print help ``` # Step 6 - Updating settings ```ruby #lib/hammer_cli_foreman/settings.rb class UpdateCommand < HammerCLIForeman::UpdateCommand # Change the default name command_name 'set' # Build options based on the API docs build_options end ``` ```bash > hammer settings set -h ``` # Step 6 - Updating settings ```ruby #lib/hammer_cli_foreman/settings.rb class UpdateCommand < HammerCLIForeman::UpdateCommand # Change the default name command_name 'set' # Build options based on the API docs build_options end ``` ```bash > hammer settings set -h Usage: hammer settings set [OPTIONS] Options: --id ID --name NAME Setting name --value VALUE -h, --help print help ``` # Step 6 - Updating settings - test ```bash > hammer settings set --name Default_variables_Lookup_Path --value '[ "fqdn", "os" ]' ``` # Step 6 - Updating settings - test ```bash > hammer settings set --name Default_variables_Lookup_Path --value '[ "fqdn", "os" ]' > ``` No output again! # Step 6 - Updating settings - test ```bash > hammer settings set --name Default_variables_Lookup_Path --value '[ "fqdn", "os" ]' > ``` No output again! ```bash > hammer settings list ``` # Step 6 - Updating settings - test ```bash > hammer settings set --name Default_variables_Lookup_Path --value '[ "fqdn", "os" ]' > ``` No output again! ```bash > hammer settings list -------------------------------|------------------|------------- NAME | VALUE | DESCRIPTION -------------------------------|------------------|------------- Default_variables_Lookup_Path | [ "fqdn", "os" ] | Foreman will Enable_Smart_Variables_in_ENC | true | Foreman smar Parametrized_Classes_in_ENC | true | Foreman will authorize_login_delegation | | Authorize lo authorize_login_delegation_api | | Authorize lo ``` # Step 7 - Better output for settings set ```ruby #lib/hammer_cli_foreman/settings.rb class UpdateCommand < HammerCLIForeman::UpdateCommand command_name 'set' build_options end ``` # Step 7 - Better output for settings set ```ruby #lib/hammer_cli_foreman/settings.rb class UpdateCommand < HammerCLIForeman::UpdateCommand command_name 'set' # Define status messages success_message _("Setting [%{name}] updated to [%{value}]") failure_message _("Could not update the setting") build_options end ``` # Step 7 - Better output for settings set ```ruby #lib/hammer_cli_foreman/settings.rb class UpdateCommand < HammerCLIForeman::UpdateCommand command_name 'set' # Define status messages success_message _("Setting [%{name}] updated to [%{value}]") failure_message _("Could not update the setting") build_options end ``` Success message: ```bash > hammer settings set --name Default_variables_Lookup_Path --value '[ "fqdn", "os" ]' ``` # Step 7 - Better output for settings set ```ruby #lib/hammer_cli_foreman/settings.rb class UpdateCommand < HammerCLIForeman::UpdateCommand command_name 'set' # Define status messages success_message _("Setting [%{name}] updated to [%{value}]") failure_message _("Could not update the setting") build_options end ``` Success message: ```bash > hammer settings set --name Default_variables_Lookup_Path --value '[ "fqdn", "os" ]' Setting [Default_variables_Lookup_Path] updated to [["fqdn", "os"]] ``` # Step 7 - Better output for settings set ```ruby #lib/hammer_cli_foreman/settings.rb class UpdateCommand < HammerCLIForeman::UpdateCommand command_name 'set' # Define status messages success_message _("Setting [%{name}] updated to [%{value}]") failure_message _("Could not update the setting") build_options end ``` Failure message: ```bash > hammer settings set --name Default_variables_Lookup_Path --value '123' ``` # Step 7 - Better output for settings set ```ruby #lib/hammer_cli_foreman/settings.rb class UpdateCommand < HammerCLIForeman::UpdateCommand command_name 'set' # Define status messages success_message _("Setting [%{name}] updated to [%{value}]") failure_message _("Could not update the setting") build_options end ``` Failure message: ```bash > hammer settings set --name Default_variables_Lookup_Path --value '123' Could not update the setting: Value is invalid: must be an array ``` # And that's it! ```bash > hammer settings -h Usage: hammer settings [OPTIONS] SUBCOMMAND [ARG] ... Parameters: SUBCOMMAND subcommand [ARG] ... subcommand arguments Subcommands: list List all settings set Update a setting Options: -h, --help print help ``` # And that's it! ```bash > hammer settings -h Usage: hammer settings [OPTIONS] SUBCOMMAND [ARG] ... Parameters: SUBCOMMAND subcommand [ARG] ... subcommand arguments Subcommands: list List all settings set Update a setting Options: -h, --help print help ``` The last step is: ```bash git commit -m 'Fixes #2918 - Add commands for settings' ``` ![](img/create_pr.png) Check out the code on github http://bit.ly/1E7p8XP

When tuning is needed



![](img/tuning.png)

# When tuning is needed `hammer -d` is your friend ```bash [ INFO 2015-01-28 14:59:40 Init] Initialization of Hammer CLI (0.1.4) has started... [DEBUG 2015-01-28 14:59:40 Init] Running at ruby 1.8.7-p374 [ INFO 2015-01-28 14:59:40 Init] Configuration from the file /etc/hammer/cli_config.yml has been loaded [ INFO 2015-01-28 14:59:40 Init] Configuration from the file /etc/hammer/cli.modules.d/foreman.yml has been loaded [ INFO 2015-01-28 14:59:40 Init] Configuration from the file /root/.hammer/cli_config.yml has been loaded [DEBUG 2015-01-28 14:59:41 Connection] Registered: foreman [DEBUG 2015-01-28 14:59:41 API] Global headers: { "Accept-Language" => "en", :accept => "application/json;version=2", :content_type => "application/json" } ``` # When tuning is needed Extending incoming data ```ruby class ListCommand < HammerCLIForeman::ListCommand output do field :name, _('Name') field :value, _('Value') field :description, _('Description') end build_options end ``` # When tuning is needed Extending incoming data ```ruby class ListCommand < HammerCLIForeman::ListCommand output do field :name, _('Name') field :value, _('Value') field :description, _('Description') end # Individualy change each item def extend_data(data) data['value'] = data['value'].to_s data end build_options end ``` # When tuning is needed Disabling options ```ruby class ListCommand < HammerCLIForeman::ListCommand output do field :name, _('Name') field :value, _('Value') field :description, _('Description') end build_options end ``` # When tuning is needed Disabling options ```ruby class ListCommand < HammerCLIForeman::ListCommand output do field :name, _('Name') field :value, _('Value') field :description, _('Description') end build_options :without => [:search, :order] end ``` # Creating custom plugin - plugins are nothing but gems # Creating custom plugin - plugins are nothing but gems - gem needs to be named `"hammer_cli_<plugin_name>"` # Creating custom plugin - plugins are nothing but gems - gem needs to be named `"hammer_cli_<plugin_name>"` - yaml settings - file placed in `<hammer_cfg_path>/cli.modules.d/` - values nested in a `<plugin_name>` - enabling the plugin in the settings # Creating custom plugin - plugins are nothing but gems - gem needs to be named `"hammer_cli_<plugin_name>"` - yaml settings - file placed in `<hammer_cfg_path>/cli.modules.d/` - values nested in a `<plugin_name>` - enabling the plugin in the settings ```yaml :foreman: # <plugin_name> # Enable/disable foreman commands :enable_module: true # Your foreman server address :host: 'https://localhost/' ``` # Creating custom plugin - plugins are nothing but gems - gem needs to be named `"hammer_cli_<plugin_name>"` - yaml settings - file placed in `<hammer_cfg_path>/cli.modules.d/` - values nested in a `<plugin_name>` - enabling the plugin in the settings ```yaml :foreman: # <plugin_name> # Enable/disable foreman commands :enable_module: true # Your foreman server address :host: 'https://localhost/' ``` - add commands to the `MainCommand` at load time ```ruby HammerCLI::MainCommand.subcommand HammerCLI::MainCommand.lazy_subcommand ```
# Want to know more? ## Documentation: - Clamp [https://github.com/mdub/clamp/](https://github.com/mdub/clamp/) - Hammer CLI [https://github.com/theforeman/hammer-cli/](https://github.com/theforeman/hammer-cli/) - Hammer CLI Foreman [https://github.com/theforeman/hammer-cli-foreman/](https://github.com/theforeman/hammer-cli-foreman/)

## Looking for help? - `#foreman` or `#foreman-dev` on FreeNode - foreman-users@googlegroups.com - foreman-dev@googlegroups.com







Thanks for your attention!

https://github.com/tstrachota/hammer-cli-foreman/compare/tstrachota:cfgmgmt_demo_before...tstrachota:cfgmgmt_demo or http://bit.ly/1E7p8XP