diff --git a/docs/README.md b/docs/README.md index fe67a0f0..2f03823b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,4 +7,4 @@ - [Troubleshooting](troubleshooting/README.md) - [For contributors](for-contributors.md) - [For maintainers](for-maintainers.md) -- [FAQ](faq.md) +- [FAQ](faq/README.md) diff --git a/docs/faq.md b/docs/faq.md deleted file mode 100644 index a1f736f9..00000000 --- a/docs/faq.md +++ /dev/null @@ -1,14 +0,0 @@ -🔖 [Table of Contents](README.md) - -# FAQ - -## How to spell Zrb? - -You can spell Zrb as `Zaruba`. - -## Why Python? - -Python is a multipurpose language. It gives you a lot of flexibility to define your tasks without being too verbose. - - -🔖 [Table of Contents](README.md) \ No newline at end of file diff --git a/docs/faq/README.md b/docs/faq/README.md new file mode 100644 index 00000000..4bf26dce --- /dev/null +++ b/docs/faq/README.md @@ -0,0 +1,7 @@ +🔖 [Table of Contents](../README.md) + +# FAQ + +- [Why Python](why-python.md) + +🔖 [Table of Contents](../README.md) diff --git a/docs/faq/why-python.md b/docs/faq/why-python.md new file mode 100644 index 00000000..f6e568a3 --- /dev/null +++ b/docs/faq/why-python.md @@ -0,0 +1,92 @@ +🔖 [Table of Contents](../README.md) / [FAQ](README.md) + +# Why Python? + +Python is a general multi-purpose language. It support a lot of pogramming paradigms like OOP/FP, or procedural. Writing a configuration in Python let you do a lot of things like control structure, etc. + +Python has been around since the 90's, and you won't have to worry about the language. Many people already familiar with the language. Even if you are new to the language, learning Python will be highly rewarding. + +However, there are a lot of tools out there that don't use Python. So, why Python? Why not YAML/HCL/anything else? + +# Why not YAML? + +YAML format is widely used because of it's readability and simplicity. Many tools like [Ansible](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_intro.html) or [Docker Compose](https://docs.docker.com/compose/) use YAML files for their configuration. + +Using YAML for simple configuration can be a good idea. + +However, for more complex scenario (like when you need to do looping or branching), using YAML is quite challenging. You need to overcome this with some tricks: + +- Generating the YAML configuration somewhere else +- Using templating language like Jinja or Go template +- Implementing branch/loop structure in your YAML parser configuration + +Compared to this, Python already has built-in control structure. + +Moreover, you can define your Python configuration declaratively, almost like YAML. + +Let's see how Ansible playbook and Zrb config might like similar to each other: + +## Ansible Playbook + +First of all, you need to define your virtual machines + +```ini +[my_vms] +192.168.1.100 ansible_ssh_user=ubuntu +192.168.1.101 ansible_ssh_user=ubuntu +192.168.1.102 ansible_ssh_user=ubuntu +``` + +Then you create a playbook to define what you want to do with the virtual machines + +```yaml +--- +- name: Install curl on VMs + hosts: my_vms + become: true + tasks: + - name: Update package cache + apt: + update_cache: yes + + - name: Install curl + apt: + name: curl + state: present +``` + +Finally, you run the playbook agains the virtual machines: + +```bash +ansible-playbook -i vm_inventory.ini install_curl.yml +``` + +## Zrb configs + +You can define something similar with Zrb: + +```python +from zrb import ( + runner, CmdTask, RemoteCmdTask, RemoteConfig, PasswordInput +) + +remote_configs = [ + RemoteConfig( + host=f'192.168.1.{sub_ip}', + user='ubuntu' + ) for sub_ip in range(100, 103) +] + +install_curl = RemoteCmdTask( + name='install-curl', + remote_configs= remote_configs, + cmd=[ + 'sudo apt update', + 'sudo apt install curl --y' + ] +) +runner.register(install_curl) +``` + + +🔖 [Table of Contents](../README.md) / [FAQ](README.md) diff --git a/src/zrb/action/runner.py b/src/zrb/action/runner.py index 2308a9cc..4da5c99b 100644 --- a/src/zrb/action/runner.py +++ b/src/zrb/action/runner.py @@ -27,7 +27,7 @@ def __init__(self, env_prefix: str = ''): logger.info(colored('Runner created', attrs=['dark'])) def register(self, task: AnyTask): - cmd_name = task.get_cmd_name() + cmd_name = task.get_complete_cmd_name() logger.debug(colored(f'Register task: {cmd_name}', attrs=['dark'])) self._tasks.append(task) task.set_has_cli_interface() diff --git a/src/zrb/task/any_task.py b/src/zrb/task/any_task.py index e3de9228..8185a148 100644 --- a/src/zrb/task/any_task.py +++ b/src/zrb/task/any_task.py @@ -130,6 +130,10 @@ def get_description(self) -> str: def get_cmd_name(self) -> str: pass + @abstractmethod + def get_complete_cmd_name(self) -> str: + pass + @abstractmethod def get_env_files(self) -> List[EnvFile]: pass diff --git a/src/zrb/task/base_task.py b/src/zrb/task/base_task.py index 526bd718..b4602c2c 100644 --- a/src/zrb/task/base_task.py +++ b/src/zrb/task/base_task.py @@ -389,7 +389,7 @@ def _show_run_command(self): kwarg_key = self._get_normalized_input_key(key) quoted_value = double_quote(str(self._kwargs[kwarg_key])) params.append(f'--{key} {quoted_value}') - run_cmd = self._get_complete_name() + run_cmd = self.get_complete_cmd_name() run_cmd_with_param = run_cmd if len(params) > 0: param_str = ' '.join(params) diff --git a/src/zrb/task/base_task_composite.py b/src/zrb/task/base_task_composite.py index 7a5ac076..82764d23 100644 --- a/src/zrb/task/base_task_composite.py +++ b/src/zrb/task/base_task_composite.py @@ -462,11 +462,11 @@ def _get_common_prefix(self, show_time: bool) -> str: def _get_filled_complete_name(self) -> str: if self._filled_complete_name is not None: return self._filled_complete_name - complete_name = self._get_complete_name() + complete_name = self.get_complete_cmd_name() self._filled_complete_name = complete_name.rjust(LOG_NAME_LENGTH, ' ') return self._filled_complete_name - def _get_complete_name(self) -> str: + def get_complete_cmd_name(self) -> str: if self._complete_name is not None: return self._complete_name executable_prefix = ''