Modules are blocks of code that do a certain type of task. A
module exports some value in the main code, such as class. The first and
the most common module that you will study is the one that exports Component Class.
app/app.component.ts (excerpt)
exportclassAppComponent { }
Here app.component is a module.
Libraries
Libraries' names start with the @angular prefix. Modules can be a library of other modules. Angular 2 itself has many modules that are libraries of others.
@angular/core is the most important library that contains most of the modules that we need.
Components
A component is basically a class that is used to show an
element on the screen. The components have some properties and by using
them we can manipulate how the element should look and behave on the
screen. We can create a component, destroy, and update as the user moves
in the application. Life Cycle hooks are the modules that we use for
this purpose. Like ngOnInit()
app/app.component.ts (excerpt)
exportclassblogComponent { }
Here blogComponent is a component.
Templates
The view of the component is defined through templates. Templates are basically the HTML we use to show on our page.
app/hero-list.component.html
<h2>Hero List</h2>
<p><i>Pick a hero from the list</i></p>
<ul>
<li*ngFor="let food of foods"(click)="selectedFood(food)">
This is a simple HTML file, but you may wonder: What are these elements?
*ngFor,{{food.name}}, (click), [food], and ?
Metadata
Metadata tells Angular how a class should be processed on the screen. For example:
@Component({
selector: 'food-list',
templateUrl: 'app/food-list.component.html',
directives: [FoodDetailComponent],
providers: [FoodService]
})
To tell Angular that we are using a component with certain metadata, we attach a decorator to it (“@”).
Here @Component will be identified as a component class.
Selector tells Angular to render the HTML that templateURL has at this tag
Directives are other components that this Component will require to render and providers are the services required.
The template, metadata, and component together describe a view.
Data Binding
The main feature of any JavaScript framework is data binding. As Angular 1, Angular 2 also support data binding.
There are 4 ways of binding a data according to the direction to the DOM, from the DOM, or in both directions:
<input [(ngModel)]="food.name">
<li>{{food.name}}</li>
<food-detail [food]="selectedFood"></food-detail>
<li (click)="selectFood(food)"></li>
The {{hero.name}}interpolation display food.name value in li tag.
The [hero] property binding passes the selected food value from parent to child component.
The (click) event binding calls the selectedFood function when a user clicks on it.
Two-way data binding is an important fourth way that combines property and event binding by the ngModel directive.
Directive
Directive helps us to add behavior to the DOM elements. We
can attach multiple directives to the DOM elements. In TypeScript we
define decoratives by @decorative decorator.
There are 3 types of decorative:
Directive-with-a-template
Structural
Attribute
A component is a directive-with-a-template:
Structural directives add, delete and replace DOM elements. For example:
<li*ngFor="let food of foods”>
<food-detail*ngIf="selectedFood"></food-detail>
Attribute directives change the appearance of DOM elements. For example:
<input [(ngModel)]="hero.name">
Services
A service is a class containing any function, feature with a defined, and specific purpose. For example:
exportclassFoodService {
getfoodies(): Food[] {
returnFOODIES;
}
}
Dependency Injections
Dependency injection allows one to inject a dependency as a
service throughout the web application. To inject a dependency we do not
create a service but we have a constructor to request the service. The
framework then provides it. For example:
1: The disksize plugin Ever created a VM with a specific size for the disk and after using it for a while, you find out you would have liked to have a larger size disk? You can resize the VDI in for example. you can ask Vagrant to give you the disk size you want to have? Enter the vagrant-disksize plugin. Install it with vagrant plugin install vagrant-disksize And you can use it in your Vagrant file like: config.disksize.size = '75GB' It will figure out what to do and do it!
2: The vbguest plugin Getting tired of installing guest additions after each and every new installation and keeping them updated after a new version of VirtualBox is released? Mounting an ISO, installing the required dependencies, running the installer… You don’t have to worry about those things anymore! The vagrant-vbguest plugin takes care of this for you. Install it with: vagrant plugin install vagrant-vbguest And add to your Vagrantfile a line like: config.vbguest.auto_update = true This installs the correct version of the guest additions and also installs dependencies if required to for example build the module.
3: Install missing plugins If I want to share a Vagrantfile, When my Vagrantfile depends on plugins such as above, it won’t work if they are missing. Luckily installing missing plugins is easy to automate within your Vagrantfile like below: unless Vagrant.has_plugin?("vagrant-disksize") puts 'Installing vagrant-disksize Plugin...' system('vagrant plugin install vagrant-disksize') end unless Vagrant.has_plugin?("vagrant-vbguest") puts 'Installing vagrant-vbguest Plugin...' system('vagrant plugin install vagrant-vbguest') end unless Vagrant.has_plugin?("vagrant-reload") puts 'Installing vagrant-reload Plugin...' system('vagrant plugin install vagrant-reload') end
This way you don’t have to first install the plugins before you can use the Vagrantfile. Inspiration from the Oracle provided Vagrantfiles here.
4: Execute a command once after a reboot Suppose you want to have a specific command executed only once after a reboot. This can happen because a specific command could require certain files not to be in use or for example the vagrant user not to be logged in. You can do this with a pre-script (prepare), the reload plugin and a post script (cleanup). The below example should work for most Linux distributions: Inside your Vagrantfile: config.vm.provision :shell, path: "prescript.sh" config.vm.provision :reload config.vm.provision :shell, path: "postscript.sh" Pre-script: prescript.sh chmod +x /etc/rc.d/rc.local echo ‘COMMAND_YOU_WANT_TO_HAVE_EXECUTED’ >> /etc/rc.d/rc.local Post-script: postscript.sh chmod -x /etc/rc.d/rc.local sed -i ‘$ d’ /etc/rc.d/rc.local The pre-script adds a line to rc.local and makes it executable. The postscript removes the line again.
5: Installing docker and docker-compose For installing docker and docker-compose (and running containers) there are 3 main options. Using Vagrant plugins This is the easiest option and does not require specific provisioning file entries. The Docker provisioner is provided as part of Vagrant out of the box. Docker-compose requires the installation of a plugin. vagrant plugin install vagrant-docker-compose Inside your Vagrantfile config.vm.provision :docker config.vm.provision :docker_compose Using these plugins, you might have to look into how you can force it to use a specific version should you require it. Using a provisioning script and OS repositories
Eventually you'll reach a point where you need to run
multiple instances of an application or a service for high availability
or to manage increased load. That's what load balancer are for. There's generally two different types:
What
many people would call a "load balancer" is actually a server-side load
balancer. It can be implemented in hardware or software. The traffic is
sent to a dedicated service that decides where to send the traffic,
using an algorithm like round-robin, to one of the many instances.
Server-side load balancing
Client-side Load Balancing :
Instead of relying on another service to
distribute the load, the client itself, is responsible for deciding
where to send the traffic also using an algorithm like round-robin. It
can either discover the instances, via service discovery, or can be
configured with a predefined list. Netflix Ribbon is an example of a client-side load balancer.
Usage: git config –global user.name “[name]”
Usage: git config –global user.email “[email address]”
This command sets the author name and email address respectively to be used with your commits.
git init
Usage: git init [repository name]
This command is used to start a new repository.
git clone
Usage: git clone [url]
This command is used to obtain a repository from an existing URL.
git add
Usage: git add [file]
This command adds a file to the staging area.
Usage: git add *
This command adds one or more to the staging area.
git commit
Usage: git commit -m “[ Type in the commit message]”
This command records or snapshots the file permanently in the version history.
Usage: git commit -a
This command commits any files you’ve added with the git add command and also commits any files you’ve changed since then.
git diff
Usage: git diff
This command shows the file differences which are not yet staged. Usage: git diff –staged
This command shows the differences between the files in the staging area and the latest version present.
Usage: git diff [first branch] [second branch]
This command shows the differences between the two branches mentioned.
git reset
Usage: git reset [file]
This command unstages the file, but it preserves the file contents.
Usage: git reset [commit]
This command undoes all the commits after the specified commit and preserves the changes locally.
Usage: git reset –hard [commit] This command discards all history and goes back to the specified commit.
git status
Usage: git status
This command lists all the files that have to be committed.
git rm
Usage: git rm [file]
This command deletes the file from your working directory and stages the deletion.
git log
Usage: git log
This command is used to list the version history for the current branch.
Usage: git log –follow[file]
This command lists version history for a file, including the renaming of files also.
git show
Usage: git show [commit]
This command shows the metadata and content changes of the specified commit.
git tag
Usage: git tag [commitID]
This command is used to give tags to the specified commit.
git branch
Usage: git branch
This command lists all the local branches in the current repository.
Usage: git branch [branch name]
This command creates a new branch.
Usage: git branch -d [branch name]
This command deletes the feature branch.
git checkout
Usage: git checkout [branch name]
This command is used to switch from one branch to another.
Usage: git checkout -b [branch name]
This command creates a new branch and also switches to it.
git merge
Usage: git merge [branch name]
This command merges the specified branch’s history into the current branch.
git remote
Usage: git remote add [variable name] [Remote Server Link]
This command is used to connect your local repository to the remote server.
git push
Usage: git push [variable name] master
This command sends the committed changes of master branch to your remote repository.
Usage: git push [variable name] [branch]
This command sends the branch commits to your remote repository.
Usage: git push –all [variable name]
This command pushes all branches to your remote repository.
Usage: git push [variable name] :[branch name]
This command deletes a branch on your remote repository.
git pull
Usage: git pull [Repository Link]
This command fetches and merges changes on the remote server to your working directory.
git stash
Usage: git stash save
This command temporarily stores all the modified tracked files.
Usage: git stash pop
This command restores the most recently stashed files.
Usage: git stash list
This command lists all stashed changesets.
Usage: git stash drop
This command discards the most recently stashed changeset.
Want to learn more about git commands? Here is a Git Tutorial to get you started. Alternatively, you can take a top-down approach and start with this DevOps Tutorial.
dest: '/tmp' force: no # dont download if file already exists
untar tar.gz
USER AND GROUP MGMT
change user password for user Joe (user Fred running the cmd as sudo on the target box)
# 1 install passlib pip install passlib
#2 update the pw, using a hash ansible targethost -s -m user -a
"name=joe update_password=always password={{ 'MyNewPassword' |
password_hash('sha512') }}" -u fred --ask-sudo-pass
copy public ssh key to remote authorized_keys file
ansible-playbook # Run on all hosts defined
ansible-playbook -f 10 # Run 10 hosts parallel
ansible-playbook --verbose # Verbose on successful tasks
ansible-playbook -C # Test run
ansible-playbook -C -D # Dry run
ansible-playbook -l # Run on single host
ansible -m setup # All facts for one host
ansible -m setup -a 'filter=ansible_eth*' # Only ansible fact for one host
ansible all -m setup -a 'filter=facter_*' # Only facter facts but for all hosts
Sometimes
we want to do many things with single tasks like installing many
packages with the same tasks just by changing the arguments. This can be
achieved using the with_items clause.
By using the with_items, ansible creates a temporary variable called {{item}}
which consist the value for the current iteration. Let’s have some
example to understand this. We will install few packages with below
playbook.
The
above playbook will run 3 tasks each for installing individual package.
Rather than specifying three different tasks, we can use with_items and specify the list of packages that we need to install.
# Installing Packages with one Task ( Faster Process )- name: Installing Packages
apt:
name: "{{ item }}"
update_cache: yes
with_items:
- git
- nginx
- memcached
Here, while executing the task “Installing packages” Ansible will read the list from with_items and install packages one by one. You can also use with_items
with roles as well. So if you have any custom role defined and you want
to execute that role multiple times, rather than defining it multiple
times you can use with_items and just pass your elements.
2. Facts Gathering
In
Ansible, Facts are nothing but information that we derive from speaking
with the remote system. Ansible uses setup module to discover this
information automatically. Sometime this information is required in
playbook as this is dynamic information fetched from remote systems.
192.168.56.7 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"172.17.0.1",
"10.0.2.15",
"192.168.56.7"
],
( many more facts)...
It
becomes a time consuming process in Ansible as it has to gather
information from all the hosts listed in your inventory file. We can
avoid this situation and speed up our play execution by specifying gathering_facts to false in playbook.
---- hosts: web
gather_facts: False
We
can also filter the facts gathering to save some time.This case is
mainly useful when you want only hardware or network information that
you want to use in your playbook. So rather than asking for all facts,
we can minimize this by only asking network or hardware facts to save
some time. To do this, you have to keep gather_facts to True and also pass one more attribute named gather_subset to fetch specific remote information. Ansible supports network, hardware, virtual, facter, ohai as subset. To specify subset in your playbook you have to follow the below example.
- hosts: web
gather_facts: True
gather_subset: network
To specify multiple subsets , you can combine then using comma (ex. network, virtual)
- hosts: web
gather_facts: True
gather_subset: network,virtual
Sometimes there might be requirement for creating local custom facts on remote machines. This can be achieved by creating .fact file under /etc/ansible/facts.d/ location on remote machine. The .fact
file can have JSON, INI or executable file returning JSON. For example,
I have created a file called local.fact under
/etc/ansible/facts.d/local.fact and defined with following value.
[general]
sample_value=1
sample_fact=normal
By
default, you will get these facts whenever you gather fact on the
remote server you defined this. If you want to filter the facts, you can
use the below command.
Sometime
it is desired to abort the entire play on failure of any task on any
host. This can be helpful in a scenario where you are deploying any
service on group of hosts and if any failure occurred on any server
should fail the entire play because we don’t want the deployments to be
partial on any server.
---
- hosts: web
any_errors_fatal: true
The any_error_fatal option will mark all the hosts as failed if fails and immediately abort the playbook execution.
4. max_fail_percentage
Ansible
is designed in such a way that it will continue to execute the playbook
until and unless there are any hosts in the group that are not yet
failed. Sometimes it becomes issue while doing deployments because its
not maintaining consistency. Consider scenario’s where you have 100+
servers attached to load balancer and you are targeting for zero
downtime with rolling updates. As Ansible supports rolling updates and
you can define the batch size( Batch size is nothing but the number of
servers you want to target for deployment in rolling updates, you can
also provide %), you have to monitor these deployments for failure and
take decision when to call it off. max_fail_percentage allows you to abort the play if certain threshold of failures have been reached.
---
- hosts: web
max_fail_percentage: 30
serial: 30
If 30 of the servers to fail out of 100. Ansible will abort the rest of the play.
5. run_once
There
are condition where we have to write our playbook in such a way that
will run some tasks or perform some action only on single host from
group. If you are thinking of Handlers do the same thing. Think twice
because even though multiple tasks notify to perform some action,
handlers will only gets executed after all tasks completed in play but
on all hosts and not on single.
To achieve this, Ansible provided run_once
module, which will run only on single host from group of hosts. By
default, Ansible will select the first host from the group to execute.
This can also be used with delegate_to to run the task on specific server. When executed with serial, task marked as run_once gets executed on one host from each batch.
6. Ansible Vault
There
are scenarios where we have to keep sensitives information in playbook,
like database username and password. Keeping such sensitive information
open is not a good idea as we are going to keep our playbook in version
control system. To Keep such information, Ansible provided Vault to
store such information in encrypted format.
Ansible
Vault can be used to encrypt binary files, group_vars, host_vars,
include_vars and var_files. Ansible vault can be used with command line
tool named ansible-vault.You can create encrypted file using following command.
ansible-vault create encryptme.yml
If
you are running this command for first time, it will ask you for
setting vault password. Later you have to provide the same while running
ansible-playbook command using--ask-vault-pass.
To encrypt any file, you can use the following command
ansible-vault encrypt filename.yml
This will encrypt all your content and can only be decrypted using vault password.
Since Ansible 2.4
you can have multiple vault passwords. The reason for allowing multiple
passwords is because you cannot encrypt dev and prod passwords using
single vault password. The passwords for environments dev will be
different, than prod environment. Now, if anyone who has dev vault
password would not be able to decrypt prod password which makes it more
secure. The Vault credentials are encrypted through vault-id. Please follow below examples for creating multiple vault passwords.
The vault-id is used for decrypting the passwords. The vault-id dev is used to encrypt dev_config.yml whereas vault-id prod is used to encrypt prod_config.yml. To decrypt, we use the following command.
This command will ask vault password for vault-id prod.
7. No_logs
In
previous section, we covered how we can encrypt the data using Ansible
Vault and share it publicly. But this encrypted data is exposed when we
run the playbook in -v(verbose) mode. Anyone who has access to
controller machine or Ansible Tower jobs, they can easily identify the
encrypted data by running the playbook in verbose mode.
Playbook ran with verbose mode to show how encrypted data can be seen.
In
above screenshot, you can see that the encrypted data is exposed in
ansible_facts. To secure or censor such information, Ansible has provide
a keyword named no_log which you can set to true to keep any task’s information censored.
This
way you can keep verbose output but hide sensitive information from
others. This can also be applied to play but it becomes difficult for
debug and not recommended.
Note that when debugging Ansible with ANSIBLE_DEBUG, the no_logs cannot stop ansible from showing the information.
8. tags
Sometimes
while writing the playbook we never think about dividing the playbook
logically and we end up with a long playbook. But what if we can divide
the long playbook into logical units. We can achieve this with tags, which divides the playbook into logical sections.
Ansible Tags are supported by tasks and play. You can use tags
keyword and provide any tag to task or play. Tags are inherited down to
the dependency chain which means that if you applied the tags to a role
or play, all tasks associated under that will also get the same tag.
To run your playbook with specific tag, you have to provide command line attribute --tags and name of your tag.
ansible-playbook -i local site.yml --tags package
Above
command will run tasks which are tagged as package and skip all other
tasks. Sometimes you have to play complete playbook and skip some part.
This can be achieved with--skip-tag attribute.
ansible-playbook -i local site.yml --skip-tags package
The above command will run all tasks and skip tasks tagged with package.If you want to list all tags, that can be done with--list-tag attribute.
Ansible also provided some special tags as always, tagged, untagged and all.
ansible-playbook -i local site.yml --skip-tags always
By default , ansible runs with--tags all which will execute all tasks.
9. command module idempotent (optional)
As
we know that all modules are idempotent, which means if we are running a
module multiple times should have the same affect as running it just
once. To implement idempotency, you have to check module whether its
desired state has been achieved or not. If its already achieved then
just exit or else perform the action specified. Mostly all Ansible
modules are idempotent but there are few modules which are not. Command
and Shell modules of Ansible are not idempotent. But there are ways to
make them idempotent. Let’s see how we can make them idempotent.
Command module runs same command again and again. To make it idempotent we can use the attribute create or remove. When used with create
attribute, Ansible will only run the command task if the file specified
by the pattern does not exists. Alternatively you could use remove, which will only execute the task if the file specified exists.
tasks:- name: Running command if file not present
command: setup_db.sh
args:
creates: /opt/database
As
Ansible supports idempotent, make sure you use all such modules in your
playbook to make your play idempotent so that re-running should be
safe.
10. Debugging Playbook on Run
Debugging
an ansible playbook is one of the coolest feature that ansible has
introduced(in 2.1 version). While we develop any playbook sometimes we
see failures and to debug we usually run the playbook again, identify
the error that Ansible throws and modify the playbook and then rerun the
playbook. What if your playbook takes 30 minutes to run and your play
is failing for last few tasks and after debugging you will again run
your playbook for almost 30 minutes. I guess that’s ideal way to debug,
You can used the ansible debug strategy.
Ansible
provides a debug strategy which will help to enable the debugger when a
task fails. It will provide access to all features of the debugger in
the context of failed task. This way if you encounter a failed task, you
can set the values of the variables, update the module arguments and
re-run the failed task with new arguments and variables.
To use the debug strategy in your playbook, you have to define the strategy as debug.
---
- hosts: web
strategy: debug tasks: ...
With Debugger, it provides multiple commands to debug your failed tasks.
P task/host/result/vars ->Prints the value to executed a module
task.args[key] = value — upgrade the module arguments
vars[args]=value — set argument value
r(edo) — run the task again
c(continue) — Just continue
q(uit) — quit from debugger
Let’s run the following playbook to demonstrate this feature.