Update 2016-06-29-Episode-62-Console-Yourself-With-Cheap-Steam.adoc

= Episode 62: Console Yourself With Cheap Steam
:hp-tags: steam, console, UI, BackRoom
:hp-image: logo.png

It's a bit light on this week with pinball news.

In light of this, we look into how folks on other platforms could capitalise on Steam Sales for PC.
You might be surprised about how easy it is for a TPA Console player (PS3/PS4 or XBox) to get cheap tables and frequent updates.

In the aftermath of the New UI Premature birth on Android, we also give a PSA about how to talk to engineers about fixes or observations you have with an application.

There's a BlahCade BackRoom longer than the main show, with one of the most obnoxious wedding announcements you will have ever heard.
If you don't fancy hearing us talking about it, just take a look at the link and prepare to groan.

NOTE: There is a bit of an audio race condition at about 17 minutes in.
It sounds like Jared is talking right over Chris.
He wasn't.
It's a Blab thing...

== Links

http://shoutengine.com/BlahCadePodcast/#[Stream/Download/RSS]

https://itunes.apple.com/us/podcast/blahcade-podcast/id1039748922?mt=2[iTunes]

https://twitter.com/blahcade[@BlahCade on Twitter]

https://blab.im/BlahCade[BlahCade on Blab.im (Live Session Recordings)]

https://represent.com/blahcade-shirt[BlahCade T-shirts on represent.com]

== Timings

* Introduction - 0:30
* Beta for Indy 500 on PC - 1:10
* Pinball Arcade Tables Deeply Discounted - 3:20
* Zen Tables Deeply Discounted - 6:05
* Should Console Owners Switch to Steam? - 6:35
** What is the minimum recommended GPU spec? - 7:20
** Can a GTX-670 cope with TPA? - 9:15
** Chris, reporting from Blackwater 300 - 10:45
** How could I test it out on my PC? - 11:40
* http://www.samvandoorn.net/?/web/project-1/[_STYN The Machine_ by Sam Van Doorn] - 12:45
* New UI on Android Progress Report - 15:20
** _Constructive_ criticism sought - 17:50
** How to be constructive when providing feedback - 19:40
* TPA Android Users Guide 2.0 - 22:08
* Outtro (before BackRoom) - 24:14
* http://postgradproblems.com/this-hipster-marriage-announcement-from-the-new-york-times-is-the-most-insufferable-yet/[BackRoom: Hipster Wedding Announcement] - 25:55
* Hard Outtro - 43:25

= Episode 62: Console Yourself With Cheap Steam
:hp-tags: steam, console, New_UI, BackRoom
:hp-image: logo.png

It's a bit light on this week with pinball news.

In light of this, we look into how folks on other platforms could capitalise on Steam Sales for PC.
You might be surprised about how easy it is for a TPA Console player (PS3/PS4 or XBox) to get cheap tables and frequent updates.

In the aftermath of the New UI Premature birth on Android, we also give a PSA about how to talk to engineers about fixes or observations you have with an application.

There's a BlahCade BackRoom longer than the main show, with one of the most obnoxious wedding announcements you will have ever heard.
If you don't fancy hearing us talking about it, just take a look at the link and prepare to groan.

NOTE: There is a bit of an audio race condition at about 17 minutes in.
It sounds like Jared is talking right over Chris.
He wasn't.
It's a Blab thing...

== Links

http://shoutengine.com/BlahCadePodcast/#[Stream/Download/RSS]

https://itunes.apple.com/us/podcast/blahcade-podcast/id1039748922?mt=2[iTunes]

https://twitter.com/blahcade[@BlahCade on Twitter]

https://blab.im/BlahCade[BlahCade on Blab.im (Live Session Recordings)]

https://represent.com/blahcade-shirt[BlahCade T-shirts on represent.com]

== Timings

* Introduction - 0:30
* Beta for Indy 500 on PC - 1:10
* Pinball Arcade Tables Deeply Discounted - 3:20
* Zen Tables Deeply Discounted - 6:05
* Should Console Owners Switch to Steam? - 6:35
** What is the minimum recommended GPU spec? - 7:20
** Can a GTX-670 cope with TPA? - 9:15
** Chris, reporting from Blackwater 300 - 10:45
** How could I test it out on my PC? - 11:40
* http://www.samvandoorn.net/?/web/project-1/[_STYN The Machine_ by Sam Van Doorn] - 12:45
* New UI on Android Progress Report - 15:20
** _Constructive_ criticism sought - 17:50
** How to be constructive when providing feedback - 19:40
* TPA Android Users Guide 2.0 - 22:08
* Outtro (before BackRoom) - 24:14
* http://postgradproblems.com/this-hipster-marriage-announcement-from-the-new-york-times-is-the-most-insufferable-yet/[BackRoom: Hipster Wedding Announcement] - 25:55
* Hard Outtro - 43:25


Update 2016-01-13-how-to-install-python-on-linux.adoc

= როგორ დავაყენოთ პითონი ლინუქსზე
:hp-alt-title: how to install python on linux
:hp-image: https://raw.githubusercontent.com/Lh4cKg/Lh4cKg.github.io/master/images/python-pip.png

პითონის დაყენება შეიძლება ნებისმიერ ოპერაციულ სისტემაზე. როგორებიცაა მაგ. Windows, Unix და Linux ოპერაციულ სისტემებზე.
მარტივი გზა პითონის დასაყენებლად არის package manager ის გამოყენება, მაგ. apt-get, yum, pacman და ა.შ.

debian/ubuntu დისტრიბუტივებზე შეგვიძლია გავუშვათ ბრძანება
მაგ. თუ გვინდა 2.x ვერსიის დაყენება

 * sudo apt-get install python2.7

თუ გვინდა 3.x ვერსიის დაყენება

 * sudo apt-get install python3.3

ასევე შეგვიძლია დავაყენოთ ბოლო ვერსია კოდის წყაროდან ანუ იგივე(Source), კოდის წყაროს გადმოწერა შეგიძლიათ პითონის ოფიციალური გვერდიდან ან Ftp დან - https://www.python.org/ftp/python/[Python Source Code] ვირჩევთ ბოლო ვერსიას 3.5.1 და ვიწერთ *.tgz ფორმატის ფაილს Python-3.5.1.tgz შემდეგ ვხსნით ტერმინალს და ვუშვებთ ქვემოთ მოცემულ ბრძანებებს

 * wget http://python.org/ftp/python/3.5.1/Python-3.5.1.tgz
 * tar -xvf Python-3.5.1.tgz
 * cd Python-3.5.1
 * ./configure
 * make
 * make altinstall

პითონის დაყენების პროცესი წარმატებით დასრულდა.

ნახეთ სურათი
image:https://raw.githubusercontent.com/Lh4cKg/Lh4cKg.github.io/master/images/pythonge.png []

:hp-tags: title[პითონი],title[ლინუქსი]

= როგორ დავაყენოთ პითონი ლინუქსზე
:hp-alt-title: how to install python on linux
:hp-image: https://raw.githubusercontent.com/Lh4cKg/Lh4cKg.github.io/master/images/python-pip.png

პითონის დაყენება შეიძლება ნებისმიერ ოპერაციულ სისტემაზე. როგორებიცაა მაგ. Windows, Unix და Linux ოპერაციულ სისტემებზე.
მარტივი გზა პითონის დასაყენებლად არის package manager ის გამოყენება, მაგ. apt-get, yum, pacman და ა.შ.

debian/ubuntu დისტრიბუტივებზე შეგვიძლია გავუშვათ ბრძანება
მაგ. თუ გვინდა 2.x ვერსიის დაყენება

 * sudo apt-get install python2.7

თუ გვინდა 3.x ვერსიის დაყენება

 * sudo apt-get install python3.3

ასევე შეგვიძლია დავაყენოთ ბოლო ვერსია სორსიდან, სორსის გადმოწერა შეგიძლიათ პითონის ოფიციალური გვერდიდან ან Ftp დან - https://www.python.org/ftp/python/[Python Source Code] ვირჩევთ ბოლო ვერსიას 3.5.1 და ვიწერთ *.tgz ფორმატის ფაილს Python-3.5.1.tgz შემდეგ ვხსნით ტერმინალს და ვუშვებთ ქვემოთ მოცემულ ბრძანებებს

 * wget http://python.org/ftp/python/3.5.1/Python-3.5.1.tgz
 * tar -xvf Python-3.5.1.tgz
 * cd Python-3.5.1
 * ./configure
 * make
 * make altinstall

პითონის დაყენების პროცესი წარმატებით დასრულდა.

ნახეთ სურათი
image:https://raw.githubusercontent.com/Lh4cKg/Lh4cKg.github.io/master/images/pythonge.png []

:hp-tags: title[პითონი],title[ლინუქსი]


Update 2017-05-13-DNS-Whitelist-in-BIND-with-RPZ.adoc

= DNS Whitelist in BIND with RPZ
 :hp-image: /covers/cover.png
 :hp-tags: DNS, Filtering, Firewall, Security

I recently got a Samsung 'smart' TV which is very nice to look at.

Unfortunately there have been numerous privacy issues with smart TV's of all kinds, and Samsung in http://www.bbc.com/news/technology-31296188[particular].  So to be safe I initially decided to block the TV completely from connecting to the internet, by blocking it at my router.

As it turns out however, the built-in Netflix app on the TV is the only way I can watch true UHD (10bit colour) 4k content on the TV (don't get me started!)

So I found myself in a situation where I needed to allow the TV to connect out to the internet, despite my misgivings.

But this got me thinking - could I somehow limit it's access to just Netflix?  I modified the router ACL to allow it talk to all the IPv4 prefixes announced by AS2906 [Netflix Streaming Services Inc.]  This unfortunately didn't work, without looking too deeply it seemed Akamai was involved in at least some of the traffic.  Either way the app didn't work, I could have continued to investigate and added more IP ranges to the ACL to make it work, but it seemed like a lot of trouble.

Ruling out cumbersome IP based blocking I began to wonder could I perhaps limit it's access by restricting the domain names it could resolve?

== Enter DNS RPZ

I am relatively familiar with Bind having used it down through the years, and one feature in particular suggested it might help - Response Policy Zones.

Basically RPZ can be used to create a DNS "firewall," limiting what domains can be resolved.  There is plenty of information online about how this can be set up, however I didn't find anything specifically explaining how to do what I needed (a total blacklist with only a very small whitelist of domains).

Turns out it's fairly easy to do.

== Bind Configuration

The first step is to get a basic Bind resolver up and running.  I did this with a Ubuntu 16.04 system.

I then defined two RPZ 'zones' in the 'options' section of my named.conf (on my particular system I did it in /etc/bind/named.conf.options).  The key thing here is that RPZ checks zones in the order they are listed - this is key to creating a whitelist as opposed to a blacklist.  A single line is required:

 response-policy { zone "rpz.whitelist"; zone "rpz"; };

All queries will then be filtered based on the response policy zones listed.  If a match is found in the first (rpz.whitelist) then that will be used, otherwise the second one (rpz) will be checked.

The Bind server needs to be configured as authorititive master for these zones, similar to a standard zone, although with "allow-query" set to none.  Again this is in named.conf (in my case /etc/bind/named.conf.default-zones):

 zone "rpz.whitelist" {
    type master;
    file "/etc/bind/db.rpz.whitelist";
    allow-query { none; };
 };

 zone "rpz" {
    type master;
    file "/etc/bind/db.rpz";
    allow-query { none; };
 };

As can be seen the zone definitions reference the location of the zone file for each.  The files are created as follows, using the RPZ syntax.  The first zone, rpz.whitelist, lists the domains I had worked out Netflix used:

_/etc/bind/db.rpz.whitelist_:
....
$TTL 60
@            IN    SOA  localhost. root.localhost.  (
                      4   ; serial
                      3H  ; refresh
                      1H  ; retry
                      1W  ; expiry
                      1H) ; minimum
              IN    NS    localhost.

 netflix.com                 CNAME   rpz-passthru.
 *.netflix.com               CNAME   rpz-passthru.

 nflximg.com                 CNAME   rpz-passthru.
 *.nflximg.com               CNAME   rpz-passthru.

 nflximg.net                 CNAME   rpz-passthru.
 *.nflximg.net               CNAME   rpz-passthru.
....

Note that for each domain I have included the 'apex' record, and also a wildcard to catch all sub-domains.  In each case they are listed as CNAME records pointing to rpz-passthru, which is the RPZ syntax to tell Bind to allow queries for them.

The second RPZ zone file is created as follows.  This is configured for all sub-domains of the root zone, with a CNAME pointing to "." (which tells RPZ to return NXDOMAIN for such a lookup).  As the trailing dot (root zone) is left out of entries in RPZ zones, an asterix on it's own is all that is needed to represent subdomains of the DNS root:

_/etc/bind/db.rpz_:
....
$TTL 60
@            IN    SOA  localhost. root.localhost.  (
                     4   ; serial
                     3H  ; refresh
                     1H  ; retry
                     1W  ; expiry
                     1H) ; minimum
             IN    NS    localhost.

* CNAME   .
....

With the config in place I was able to reload Bind and check if it was working.

== Results

So does it work.  If I try to resolve a random domain I get an NXDOMAIN response:

....
topranks@dnsvm:~$ dig A www.samsung.com @localhost

; <<>> DiG 9.10.3-P4-Ubuntu <<>> A www.samsung.com @localhost
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 14003
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.samsung.com.		IN	A
....

And if I try for a sub-domain of netflix.com I get a valid response:

....
topranks@dnsvm:~$ dig A www.netflix.com @localhost

; <<>> DiG 9.10.3-P4-Ubuntu <<>> A www.netflix.com @localhost
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59390
;; flags: qr rd ra; QUERY: 1, ANSWER: 10, AUTHORITY: 4, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.netflix.com.		IN	A

;; ANSWER SECTION:
www.netflix.com.	1800	IN	CNAME	www.geo.netflix.com.
www.geo.netflix.com.	1800	IN	CNAME	www.eu-west-1.prodaa.netflix.com.
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.209.165.126
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.19.164.15
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.178.51
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.209.156.83
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.202.184
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.15.72
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.81.52
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.174.58
....

== Additions for my Smart TV case

In addition to the above I changed the ACL on for traffic coming from the TV to only allow TCP on ports 80 and 443, which is enough for Netflix, but importantly blocks the TV from using any external DNS (even in normal circumstances it looks like the TV will use 8.8.8.8 in addition to any configured DNS server entered on it).

Finally on the TV I changed the DNS server and sure enough the TV thinks something is wrong with DNS:

image::https://cloud.githubusercontent.com/assets/4465905/26027929/bd59e8b2-380e-11e7-81b1-b8b2b8fd2ffe.JPG[Samsung Error Message]

So far so good, and yes the Netflix app still works fine.  Looking closely at my Bind logs I can see what's happening:

....
Apr 20 17:42:27 dnsvm named[7369]: 13-May-2017 17:42:27.003 queries: info: client 192.168.240.42#40665 (art-0.nflximg.net): query: art-0.nflximg.net IN A + (192.168.240.32)
Apr 20 17:42:27 dnsvm named[7369]: 13-May-2017 17:42:27.003 rpz: info: client 192.168.240.42#40665 (art-0.nflximg.net): rpz QNAME PASSTHRU rewrite art-0.nflximg.net via art-0.nflximg.net.rpz.netflix
Apr 20 17:42:27 dnsvm named[7369]: 13-May-2017 17:42:27.766 queries: info: client 192.168.240.42#34179 (ns11.whois.co.kr): query: ns11.whois.co.kr IN A + (192.168.240.32)
Apr 20 17:42:27 dnsvm named[7369]: 13-May-2017 17:42:27.766 rpz: info: client 192.168.240.42#34179 (ns11.whois.co.kr): rpz QNAME NXDOMAIN rewrite ns11.whois.co.kr via ns11.whois.co.kr.rpz
Apr 20 17:42:29 dnsvm named[7369]: 13-May-2017 17:42:29.031 queries: info: client 192.168.240.42#59989 (time.samsungcloudsolution.com): query: time.samsungcloudsolution.com IN A + (192.168.240.32)
Apr 20 17:42:29 dnsvm named[7369]: 13-May-2017 17:42:29.031 rpz: info: client 192.168.240.42#59989 (time.samsungcloudsolution.com): rpz QNAME NXDOMAIN rewrite time.samsungcloudsolution.com via time.samsungcloudsolution.com.rpz
Apr 20 17:42:29 dnsvm named[7369]: 13-May-2017 17:42:29.033 queries: info: client 192.168.240.42#36357 (time.samsungcloudsolution.com): query: time.samsungcloudsolution.com IN A + (192.168.240.32)
Apr 20 17:42:29 dnsvm named[7369]: 13-May-2017 17:42:29.033 rpz: info: client 192.168.240.42#36357 (time.samsungcloudsolution.com): rpz QNAME NXDOMAIN rewrite time.samsungcloudsolution.com via time.samsungcloudsolution.com.rpz
....

So yeah, probably not ideal as the TV can still get out to the internet, at least on 80 and 443 TCP, but without DNS I've hopefully limited how much it can do.

= DNS Whitelist in BIND with RPZ
 :hp-image: /covers/cover.png
 :hp-tags: DNS, Filtering, Firewall, Security

I recently got a Samsung 'smart' TV which is very nice to look at.

Unfortunately there have been numerous privacy issues with smart TV's of all kinds, and Samsung in http://www.bbc.com/news/technology-31296188[particular].  So to be safe I initially decided to block the TV completely from connecting to the internet, by blocking it at my router.

As it turns out however, the built-in Netflix app on the TV is the only way I can watch true UHD (10bit colour) 4k content on the TV (don't get me started!)

So I found myself in a situation where I needed to allow the TV to connect out to the internet, despite my misgivings.

But this got me thinking - could I somehow limit it's access to just Netflix?  I modified the router ACL to allow it talk to all the IPv4 prefixes announced by AS2906 [Netflix Streaming Services Inc.]  This unfortunately didn't work, without looking too deeply it seemed Akamai was involved in at least some of the traffic.  Either way the app didn't work, I could have continued to investigate and added more IP ranges to the ACL to make it work, but it seemed like a lot of trouble.

Ruling out cumbersome IP based blocking I began to wonder could I perhaps limit it's access by restricting the domain names it could resolve?

== Enter DNS RPZ

I am relatively familiar with Bind having used it down through the years, and one feature in particular suggested it might help - Response Policy Zones.

Basically RPZ can be used to create a DNS "firewall," limiting what domains can be resolved.  There is plenty of information online about how this can be set up, however I didn't find anything specifically explaining how to do what I needed (a total blacklist with only a very small whitelist of domains).

Turns out it's fairly easy to do.

== Bind Configuration

The first step is to get a basic Bind resolver up and running.  I did this with a Ubuntu 16.04 system.

I then defined two RPZ 'zones' in the 'options' section of my named.conf (on my particular system I did it in /etc/bind/named.conf.options).  The key thing here is that RPZ checks zones in the order they are listed - this is key to creating a whitelist as opposed to a blacklist.  A single line is required:

 response-policy { zone "rpz.whitelist"; zone "rpz"; };

All queries will then be filtered based on the response policy zones listed.  If a match is found in the first (rpz.whitelist) then that will be used, otherwise the second one (rpz) will be checked.

The Bind server needs to be configured as authorititive master for these zones, similar to a standard zone, although with "allow-query" set to none.  Again this is in named.conf (in my case /etc/bind/named.conf.default-zones):

 zone "rpz.whitelist" {
    type master;
    file "/etc/bind/db.rpz.whitelist";
    allow-query { none; };
 };

 zone "rpz" {
    type master;
    file "/etc/bind/db.rpz";
    allow-query { none; };
 };

As can be seen the zone definitions reference the location of the zone file for each.  The files are created as follows, using the RPZ syntax.  The first zone, rpz.whitelist, lists the domains I had worked out Netflix used:

_/etc/bind/db.rpz.whitelist_:
....
$TTL 60
@            IN    SOA  localhost. root.localhost.  (
                      4   ; serial
                      3H  ; refresh
                      1H  ; retry
                      1W  ; expiry
                      1H) ; minimum
              IN    NS    localhost.

 netflix.com                 CNAME   rpz-passthru.
 *.netflix.com               CNAME   rpz-passthru.

 nflximg.com                 CNAME   rpz-passthru.
 *.nflximg.com               CNAME   rpz-passthru.

 nflximg.net                 CNAME   rpz-passthru.
 *.nflximg.net               CNAME   rpz-passthru.
....

Note that for each domain I have included the 'apex' record, and also a wildcard to catch all sub-domains.  In each case they are listed as CNAME records pointing to rpz-passthru, which is the RPZ syntax to tell Bind to allow queries for them.

The second RPZ zone file is created as follows.  This is configured for all sub-domains of the root zone, with a CNAME pointing to "." (which tells RPZ to return NXDOMAIN for such a lookup).  As the trailing dot (root zone) is left out of entries in RPZ zones, an asterix on it's own is all that is needed to represent subdomains of the DNS root:

_/etc/bind/db.rpz_:
....
$TTL 60
@            IN    SOA  localhost. root.localhost.  (
                     4   ; serial
                     3H  ; refresh
                     1H  ; retry
                     1W  ; expiry
                     1H) ; minimum
             IN    NS    localhost.

* CNAME   .
....

With the config in place I was able to reload Bind and check if it was working.

== Results

So does it work.  If I try to resolve a random domain I get an NXDOMAIN response:

....
topranks@dnsvm:~$ dig A www.samsung.com @localhost

; <<>> DiG 9.10.3-P4-Ubuntu <<>> A www.samsung.com @localhost
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 14003
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.samsung.com.		IN	A
....

And if I try for a sub-domain of netflix.com I get a valid response:

....
topranks@dnsvm:~$ dig A www.netflix.com @localhost

; <<>> DiG 9.10.3-P4-Ubuntu <<>> A www.netflix.com @localhost
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59390
;; flags: qr rd ra; QUERY: 1, ANSWER: 10, AUTHORITY: 4, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.netflix.com.		IN	A

;; ANSWER SECTION:
www.netflix.com.	1800	IN	CNAME	www.geo.netflix.com.
www.geo.netflix.com.	1800	IN	CNAME	www.eu-west-1.prodaa.netflix.com.
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.209.165.126
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.19.164.15
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.178.51
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.209.156.83
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.202.184
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.15.72
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.81.52
www.eu-west-1.prodaa.netflix.com. 60 IN	A	52.208.174.58
....

== Additions for my Smart TV case

In addition to the above I changed the ACL on for traffic coming from the TV to only allow TCP on ports 80 and 443, which is enough for Netflix, but importantly blocks the TV from using any external DNS (even in normal circumstances it looks like the TV will use 8.8.8.8 in addition to any configured DNS server entered on it).

Finally on the TV I changed the DNS server and sure enough the TV thinks something is wrong:


Final changes on build your own CA with Ansible

= Build your own CA with Ansible
:page-tags: [ansible]
:page-image: /images/logos/ansible.png
:source_dir: ../sources/2020-11-28-Build-your-own-CA-with-Ansible
:image_dir: ../images/2020-11-28-Build-your-own-CA-with-Ansible
:published_at: 2020-11-28
:page-layout: post
:page-description: "How to generate certificates with Ansible."

Securing your Kafka, Elasticsearch, Cassandra, or whatever distributed software requires configuring using SSL (also known as TLS) to encrypt communications:

* Node to node communication
* Client to node communication

Setting up SSL means providing SSL  certificates for each node.
But generating SSL certificates is a cumbersome task:

* The https://kafka.apache.org/documentation/#security_ssl[Kafka documentation] describes extensively the process.
* Elasticsearch brings its own https://www.elastic.co/guide/en/elasticsearch/reference/master/configuring-tls.html#node-certificates[elasticsearch-certutil] tool.
* Datastax also https://docs.datastax.com/en/cassandra-oss/3.x/cassandra/configuration/secureSSLCertWithCA.html[documents] a similar process for Cassandra

I will describe here how to generate an SSL certificate for each node using Ansible.
It makes sense as I am also deploying Kafka, Elasticsearch and the like with Ansible.

There are several important rules to know when generating certificates:

* The name present in the certificate must match the public name of the host.
    We can not share the same certificate on all nodes unless using star certificates.
    Any TLS client connecting to a node will check that certificate name and hostname matches unless disabling hostname verification.
* The name present in the certificate, should match the reverse DNS name corresponding to the IP of the host.
    Java clients connecting to a node, will do a reverse DNS lookup to get the public name of the host they are connecting to.

These two rules are meant to prevent *Man in the middle* attacks.
A TLS certificate allows checking you're talking to the wanted target,
not something in between which could spy and steal information.

When a machine has multiple names (think about DNS aliases, virtual hosts), a certificate can contain multiple names.
The main name is called CN (Common Name),
while other names are called SAN (Subject Alt Names).

== The certificate authority

As Kafka or Elasticsearch clusters should never be publicly exposed,
using a public certificate authority (Thawte, Verisign and the like) is not necessary.
A self-signed certificate authority local to the cluster or the environment (Dev, Q/A) should be enough.

So the first step is to create a certificate authority that will be used to sign the certificates of all hosts belonging to our cluster.
As this step will be done only once, I won't automate it.

[source,shell]
----
$ mkdir ownca
$ openssl req -new -x509 \
    -days 1825 \ <1>
    -extensions v3_ca \ <2>
    -keyout ownca/root.key -out ownca/root.crt <3>

Generating a RSA private key
......+++++
....+++++
writing new private key to 'ownca/root.key'
Enter PEM pass phrase: <4>
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:FR <5>
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:.
Organization Name (eg, company) [Internet Widgits Pty Ltd]:eNova Conseil
Organizational Unit Name (eg, section) []:.
Common Name (e.g. server FQDN or YOUR name) []:Root
Email Address []:rootca@enova-conseil.com
----
<1> The CA root certificate will last 5 years
<2> This certificate will be used as a CA
<3> Generate both key and self-signed certificate
<4> The key is protected with a password
<5> Information describing the Root certificate

For safety reasons, the generated key should be kept secret and stored in a secure place:

* It must not be transfered to target Kafka servers
* It must not be kept in source control (Git) unless hidden in Ansible Vault password file

== The nodes certificates

This is where Ansible comes in.
As your cluster might have many nodes, automating certificate generation makes sense.
For each target host, I will repeat the same process:

image::{image_dir}/process.svg[Process]

. On the target host, generate a key `target.key` and a CSR  (Certificate signing request) `target.csr`
. Pull the CSR on the control host.
. Sign the CSR with the CA key.
  This will generate a certificate `target.crt`.
. Push the generated certificate `target.crt` on the target host.
  The CA certificate `root.crt` is also pushed.

As the TLS keys `.key` are sensitive, they do not travel, they stay where they were generated.
On the contrary, certificates `.crt` and CSRs `.csr` only contain public information.

[source,yaml]
----
include::{source_dir}/openssl/tasks/main.yml[tags=main]
----

Once you have the key, the certificate and CA certificate chain on the target host, you can start using them:

[source,yaml]
----
include::{source_dir}/openssl/tasks/main.yml[tags=after]
----

The produced PKCS12 file can be used as a Java Keystore. The `java_keystore` Ansible module can be used to create a JKS file instead.

The attentive reader has noticed I am using a bunch of `openssl_xxx` Ansible modules (namely `openssl_privatekey`, `openssl_csr`, `openssl_certificate` and `openssl_pkcs12`).
These modules require to have openssl and PyOpenSSL installed on each host.

[source,yaml]
----
include::{source_dir}/openssl/tasks/main.yml[tags=before]
----

= Build your own CA with Ansible
:page-tags: [ansible]
:page-image: /images/logos/ansible.png
:source_dir: ../sources/2020-11-28-Build-your-own-CA-with-Ansible
:image_dir: ../images/2020-11-28-Build-your-own-CA-with-Ansible
:published_at: 2020-11-28
:page-layout: post
:page-description: "How to generate certificates with Ansible."

Securing your Kafka, Elasticsearch, Cassandra, or whatever distributed software means using SSL (also known as TLS) to encrypt communications:

* Node to node communication
* Client to node communication

Setting up SSL means providing SSL  certificates for each node.
Generating SSL certificates is a cumbersome task:

* The https://kafka.apache.org/documentation/#security_ssl[Kafka documentation] describes extensively the process.
* Elasticsearch brings its own https://www.elastic.co/guide/en/elasticsearch/reference/master/configuring-tls.html#node-certificates[elasticsearch-certutil] tool.
* Datastax also https://docs.datastax.com/en/cassandra-oss/3.x/cassandra/configuration/secureSSLCertWithCA.html[documents] a similar process for Cassandra

I will describe here how to generate an SSL certificate for each node using Ansible,
because I am also deploying Kafka, Elasticsearch and the like with Ansible.

There are several important rules to know when generating certificates:

* The name present in the certificate must match the public name of the host.
    We can not share the same certificate on all nodes unless using star certificates.
    Any TLS client connecting to a node will check that certificate name and hostname matches unless disabling hostname verification.
* The name present in the certificate, should match the reverse DNS name corresponding to the IP of the host.
    Java clients connecting to a node, will do a reverse DNS lookup to get the public name of the host they are connecting to.

These two rules are meant to prevent *Man in the middle* attacks.
A TLS certificate allows checking you're talking to the wanted target,
not something in between which could spy and steal information.

When a machine has multiple names (think about DNS aliases, virtual hosts), a certificate can contain multiple names.
The main name is called CN (Common Name),
while other names are called SAN (Subject Alt Names).

== The certificate authority

As Kafka or Elasticsearch clusters should never be publicly exposed,
using a public certificate authority (Thawte, Verisign and the like) is not necessary.
A self-signed certificate authority local to the cluster or the environment (Dev, Q/A) should be enough.

So the first step is to create a certificate authority that will be used to sign the certificates of all hosts belonging to our cluster.
As this step will be done only once, I won't automate it.

[source,shell]
----
$ mkdir ownca
$ openssl req -new -x509 \
    -days 1825 \ <1>
    -extensions v3_ca \ <2>
    -keyout ownca/root.key -out ownca/root.crt <3>

Generating a RSA private key
......+++++
....+++++
writing new private key to 'ownca/root.key'
Enter PEM pass phrase: <4>
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:FR <5>
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:.
Organization Name (eg, company) [Internet Widgits Pty Ltd]:eNova Conseil
Organizational Unit Name (eg, section) []:.
Common Name (e.g. server FQDN or YOUR name) []:Root
Email Address []:rootca@enova-conseil.com
----
<1> The CA root certificate will last 5 years
<2> This certificate will be used as a CA
<3> Generate both key and self-signed certificate
<4> The key is protected with a password
<5> Information describing the Root certificate

For safety reasons, the generated key should be kept secret and stored in a secure place:

* It must not be transfered to target Kafka servers
* It must not be kept in source control (Git) unless hidden in Ansible Vault password file

== The nodes certificates

This is where Ansible comes in.
As your cluster might have many nodes, automating certificate generation makes sense.
For each target host, I will repeat the same process:

image::{image_dir}/process.svg[Process]

. On the target host, generate a key `target.key` and a CSR  (Certificate signing request) `target.csr`
. Pull the CSR on the control host.
. Sign the CSR with the CA key.
  This will generate a certificate `target.crt`.
. Push the generated certificate `target.crt` on the target host.
  The CA certificate `root.crt` is also pushed.

As the TLS keys `.key` are sensitive, they do not travel, they stay where they were generated.
On the contrary, certificates `.crt` and CSRs `.csr` only contain public information.

[source,yaml]
----
include::{source_dir}/openssl/tasks/main.yml[tags=main]
----

Once you have the key, the certificate and CA certificate chain on the target host, you can start using them:

[source,yaml]
----
include::{source_dir}/openssl/tasks/main.yml[tags=after]
----

The produced PKCS12 file can be used as a Java Keystore. The `java_keystore` Ansible module can be used to create a JKS file instead.

The attentive reader has noticed I am using a bunch of `openssl_xxx` Ansible modules (namely `openssl_privatekey`, `openssl_csr`, `openssl_certificate` and `openssl_pkcs12`).
These modules require to have openssl and PyOpenSSL installed on each host.

[source,yaml]
----
include::{source_dir}/openssl/tasks/main.yml[tags=before]
----


Add unique anchors for Config GCE sections

= Configuring for GCE
{product-author}
{product-version}
:data-uri:
:icons:
:experimental:
:toc: macro
:toc-title:

toc::[]

== Overview
OpenShift can be configured to access an
link:https://cloud.google.com/compute/docs/disks/[GCE infrastructure], including
link:../install_config/persistent_storage/persistent_storage_gce.html[using GCE
volumes as persistent storage] for application data. After GCE is configured
properly, some additional configurations will need to be completed on the
OpenShift hosts.

[[gce-configuring-masters]]
== Configuring Masters

Edit or
link:../install_config/master_node_configuration.html#creating-new-configuration-files[create] the
master configuration file on all masters
(*_/etc/origin/master/master-config.yaml_* by default) and update the
contents of the `*apiServerArguments*` and `*controllerArguments*` sections:

====
[source,yaml]
----
kubernetesMasterConfig:
  ...
  apiServerArguments:
    cloud-provider:
      - "gce"
  controllerArguments:
    cloud-provider:
      - "gce"

----
====

[[gce-configuring-nodes]]
== Configuring Nodes

Edit or
link:../install_config/master_node_configuration.html#creating-new-configuration-files[create]
the node configuration file on all nodes (*_/etc/origin/node/node-config.yaml_*
by default) and update the contents of the `*kubeletArguments*` section:

====
[source,yaml]
----
kubeletArguments:
  cloud-provider:
    - "gce"

----
====

Start or restart the OpenShift services on the master and all nodes.

= Configuring for GCE
{product-author}
{product-version}
:data-uri:
:icons:
:experimental:
:toc: macro
:toc-title:

toc::[]

== Overview
OpenShift can be configured to access an
link:https://cloud.google.com/compute/docs/disks/[GCE infrastructure], including
link:../install_config/persistent_storage/persistent_storage_gce.html[using GCE
volumes as persistent storage] for application data. After GCE is configured
properly, some additional configurations will need to be completed on the
OpenShift hosts.

== Configuring Masters

Edit or
link:../install_config/master_node_configuration.html#creating-new-configuration-files[create] the
master configuration file on all masters
(*_/etc/origin/master/master-config.yaml_* by default) and update the
contents of the `*apiServerArguments*` and `*controllerArguments*` sections:

====
[source,yaml]
----
kubernetesMasterConfig:
  ...
  apiServerArguments:
    cloud-provider:
      - "gce"
  controllerArguments:
    cloud-provider:
      - "gce"

----
====

== Configuring Nodes

Edit or
link:../install_config/master_node_configuration.html#creating-new-configuration-files[create]
the node configuration file on all nodes (*_/etc/origin/node/node-config.yaml_*
by default) and update the contents of the `*kubeletArguments*` section:

====
[source,yaml]
----
kubeletArguments:
  cloud-provider:
    - "gce"

----
====

Start or restart the OpenShift services on the master and all nodes.


updating the infinispan documentation

updating the infinispan documentation

[[infinispan-component]]
= Infinispan Component

*Available as of Camel version 2.13*

This component allows you to interact with
http://infinispan.org/[Infinispan] distributed data grid / cache.
Infinispan is an extremely scalable, highly available key/value data
store and data grid platform written in Java.

Infinispan requires at least Java 8.

The `camel-infinispan` component includes the following features:

* *Local Camel Consumer* - Receives cache change notifications and sends them to be processed.
This can be done synchronously or asynchronously, and is also supported with a replicated or distributed cache.

* *Local Camel Producer* - A producer creates and sends messages to an endpoint.
The `camel-infinispan` producer uses ``GET``, ``PUT``, ``REMOVE``, and `CLEAR` operations.
The local producer is also supported with a replicated or distributed cache.

* *Remote Camel Producer* - In Remote Client-Server mode, the Camel producer can send messages using Hot Rod.

* *Remote Camel Consumer* - In Client-Server mode, receives cache change notifications and sends them to be processed.
The events are processed asynchronously.

If you use Maven, you must add the following dependency to your `pom.xml`:

[source,xml]
------------------------------------------------------------
<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-infinispan</artifactId>
    <version>x.x.x</version>
    <!-- use the same version as your Camel core version -->
</dependency>
------------------------------------------------------------

== URI format

[source,java]
-------------------------------
infinispan://cacheName?[options]
-------------------------------

== URI Options

The producer allows sending messages to a local infinispan cache
configured in the registry, or to a remote cache using the HotRod
protocol. The consumer allows listening for events from local infinispan cache
accessible from the registry.

// component options: START
The Infinispan component supports 4 options, which are listed below.

[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| *configuration* (common) | The default configuration shared among endpoints. |  | InfinispanConfiguration
| *cacheContainer* (common) | The default cache container. |  | BasicCacheContainer
| *resolveProperty Placeholders* (advanced) | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | boolean
| *basicPropertyBinding* (advanced) | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
|===
// component options: END

// endpoint options: START
The Infinispan endpoint is configured using URI syntax:

----
infinispan:cacheName
----

with the following path and query parameters:

=== Path Parameters (1 parameters):

[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| *cacheName* | *Required* The cache to use |  | String
|===

=== Query Parameters (21 parameters):

[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| *hosts* (common) | Specifies the host of the cache on Infinispan instance |  | String
| *queryBuilder* (common) | Specifies the query builder. |  | InfinispanQueryBuilder
| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
| *clusteredListener* (consumer) | If true, the listener will be installed for the entire cluster | false | boolean
| *command* (consumer) | *Deprecated* The operation to perform. | PUT | String
| *customListener* (consumer) | Returns the custom listener in use, if provided |  | InfinispanCustom Listener
| *eventTypes* (consumer) | Specifies the set of event types to register by the consumer. Multiple event can be separated by comma. The possible event types are: CACHE_ENTRY_ACTIVATED, CACHE_ENTRY_PASSIVATED, CACHE_ENTRY_VISITED, CACHE_ENTRY_LOADED, CACHE_ENTRY_EVICTED, CACHE_ENTRY_CREATED, CACHE_ENTRY_REMOVED, CACHE_ENTRY_MODIFIED, TRANSACTION_COMPLETED, TRANSACTION_REGISTERED, CACHE_ENTRY_INVALIDATED, DATA_REHASHED, TOPOLOGY_CHANGED, PARTITION_STATUS_CHANGED |  | String
| *sync* (consumer) | If true, the consumer will receive notifications synchronously | true | boolean
| *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
| *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
| *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing. | false | boolean
| *operation* (producer) | The operation to perform. | PUT | InfinispanOperation
| *basicPropertyBinding* (advanced) | Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
| *cacheContainer* (advanced) | Specifies the cache Container to connect |  | BasicCacheContainer
| *cacheContainerConfiguration* (advanced) | The CacheContainer configuration. Uses if the cacheContainer is not defined. Must be the following types: org.infinispan.client.hotrod.configuration.Configuration - for remote cache interaction configuration; org.infinispan.configuration.cache.Configuration - for embedded cache interaction configuration; |  | Object
| *configurationProperties* (advanced) | Implementation specific properties for the CacheManager |  | Map
| *configurationUri* (advanced) | An implementation specific URI for the CacheManager |  | String
| *flags* (advanced) | A comma separated list of Flag to be applied by default on each cache invocation, not applicable to remote caches. |  | String
| *remappingFunction* (advanced) | Set a specific remappingFunction to use in a compute operation |  | BiFunction
| *resultHeader* (advanced) | Store the operation result in a header instead of the message body. By default, resultHeader == null and the query result is stored in the message body, any existing content in the message body is discarded. If resultHeader is set, the value is used as the name of the header to store the query result and the original message body is preserved. This value can be overridden by an in message header named: CamelInfinispanOperationResultHeader |  | Object
| *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
|===
// endpoint options: END
// spring-boot-auto-configure options: START
== Spring Boot Auto-Configuration

When using Spring Boot make sure to use the following Maven dependency to have support for auto configuration:

[source,xml]
----
<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-infinispan-starter</artifactId>
  <version>x.x.x</version>
  <!-- use the same version as your Camel core version -->
</dependency>
----

The component supports 23 options, which are listed below.

[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| *camel.component.infinispan.basic-property-binding* | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | Boolean
| *camel.component.infinispan.cache-container* | The default cache container. The option is a org.infinispan.commons.api.BasicCacheContainer type. |  | String
| *camel.component.infinispan.configuration.cache-container* | Specifies the cache Container to connect |  | BasicCacheContainer
| *camel.component.infinispan.configuration.cache-container-configuration* | The CacheContainer configuration. Uses if the cacheContainer is not defined. Must be the following types: org.infinispan.client.hotrod.configuration.Configuration - for remote cache interaction configuration; org.infinispan.configuration.cache.Configuration - for embedded cache interaction configuration; |  | Object
| *camel.component.infinispan.configuration.clustered-listener* | If true, the listener will be installed for the entire cluster | false | Boolean
| *camel.component.infinispan.configuration.configuration-properties* | Implementation specific properties for the CacheManager |  | Map
| *camel.component.infinispan.configuration.configuration-uri* | An implementation specific URI for the CacheManager |  | String
| *camel.component.infinispan.configuration.custom-listener* | Returns the custom listener in use, if provided |  | InfinispanCustom Listener
| *camel.component.infinispan.configuration.event-types* | Specifies the set of event types to register by the consumer. Multiple event can be separated by comma. <p/> The possible event types are: CACHE_ENTRY_ACTIVATED, CACHE_ENTRY_PASSIVATED, CACHE_ENTRY_VISITED, CACHE_ENTRY_LOADED, CACHE_ENTRY_EVICTED, CACHE_ENTRY_CREATED, CACHE_ENTRY_REMOVED, CACHE_ENTRY_MODIFIED, TRANSACTION_COMPLETED, TRANSACTION_REGISTERED, CACHE_ENTRY_INVALIDATED, DATA_REHASHED, TOPOLOGY_CHANGED, PARTITION_STATUS_CHANGED |  | Set
| *camel.component.infinispan.configuration.flags* | A comma separated list of Flag to be applied by default on each cache invocation, not applicable to remote caches. |  | Flag[]
| *camel.component.infinispan.configuration.hosts* | Specifies the host of the cache on Infinispan instance |  | String
| *camel.component.infinispan.configuration.operation* | The operation to perform. |  | InfinispanOperation
| *camel.component.infinispan.configuration.query-builder* | Specifies the query builder. |  | InfinispanQueryBuilder
| *camel.component.infinispan.configuration.remapping-function* | Set a specific remappingFunction to use in a compute operation |  | BiFunction
| *camel.component.infinispan.configuration.result-header* | Store the operation result in a header instead of the message body. By default, resultHeader == null and the query result is stored in the message body, any existing content in the message body is discarded. If resultHeader is set, the value is used as the name of the header to store the query result and the original message body is preserved. This value can be overridden by an in message header named: CamelInfinispanOperationResultHeader |  | Object
| *camel.component.infinispan.configuration.sync* | If true, the consumer will receive notifications synchronously | true | Boolean
| *camel.component.infinispan.customizer.embedded-cache-manager.enabled* | Enable or disable the cache-manager customizer. | true | Boolean
| *camel.component.infinispan.customizer.embedded-cache-manager.override* | Configure if the cache manager eventually set on the component should be overridden by the customizer. | false | Boolean
| *camel.component.infinispan.customizer.remote-cache-manager.enabled* | Enable or disable the cache-manager customizer. | true | Boolean
| *camel.component.infinispan.customizer.remote-cache-manager.override* | Configure if the cache manager eventually set on the component should be overridden by the customizer. | false | Boolean
| *camel.component.infinispan.enabled* | Enable infinispan component | true | Boolean
| *camel.component.infinispan.resolve-property-placeholders* | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | Boolean
| *camel.component.infinispan.configuration.command* | *Deprecated* The operation to perform. | PUT | String
|===
// spring-boot-auto-configure options: END

== Camel Operations
This section lists all available operations, along with their header information.

.Put Operations
[cols="40%,60%", frame="all", options="header"]
|===
| Operation Name
| Description

| InfinispanOperation.PUT
| *Context*: Embedded / Remote

*Description*: Puts a key/value pair in the cache, optionally with expiration

*Required Headers*: CamelInfinispanKey, CamelInfinispanValue

*Optional Headers*: CamelInfinispanLifespanTime, CamelInfinispanLifespanTimeUnit, CamelInfinispanMaxIdleTime, CamelInfinispanMaxIdleTimeUnit, CamelInfinispanIgnoreReturnValues

*Result Header*: CamelInfinispanOperationResult

| InfinispanOperation.PUTASYNC
| *Description*: Asynchronously puts a key/value pair in the cache, optionally with expiration

| InfinispanOperation.PUTIFABSENT
| *Description*: Puts a key/value pair in the cache if it did not exist, optionally with expiration

| InfinispanOperation.PUTIFABSENTASYNC
| *Description*: Asynchronously puts a key/value pair in the cache if it did not exist, optionally with expiration

|===

.Put All Operations
[cols="40%,60%", options="header"]
|===
| Operation Name
| Description

| InfinispanOperation.PUTALL
| *Context*: Embedded / Remote

*Description*: Adds multiple entries to a cache, optionally with expiration

*Required Headers*: CamelInfinispanMap

*Optional Headers*: CamelInfinispanLifespanTime, CamelInfinispanLifespanTimeUnit, CamelInfinispanMaxIdleTime, CamelInfinispanMaxIdleTimeUnit

*Result Header*: None

| CamelInfinispanOperation.PUTALLASYNC
| *Description*: Asynchronously adds multiple entries to a cache, optionally with expiration

|===

.Get Operations
[cols="40%,60%", frame="all", options="header"]
|===
|Operation Name
|Description

| InfinispanOperation.GET
| *Context*: Embedded / Remote

*Description*: Retrieves the value associated with a specific key from the cache

*Required Headers*: CamelInfinispanKey

*Optional Headers*: None

*Result Header*: None

| InfinispanOperation.GETORDEFAULT
| *Context*: Embedded / Remote

*Description*: Retrieves the value, or default value, associated with a specific key from the cache

*Required Headers*: CamelInfinispanKey

*Optional Headers*: None

*Result Header*: None
|===

.Contains Key Operation
[cols="40%,60%", options="header"]
|===
| Operation Name
| Description

| InfinispanOperation.CONTAINSKEY
| *Context*: Embedded / Remote

*Description*: Determines whether a cache contains a specific key

*Required Headers*: CamelInfinispanKey

*Optional Headers*: None

*Result Header*: CamelInfinispanOperationResult
|===

.Contains Value Operation
[cols="40%,60%", options="header"]
|===
| Operation Name
| Description

| InfinispanOperation.CONTAINSVALUE
| *Context*: Embedded / Remote

*Description*: Determines whether a cache contains a specific value

*Required Headers*: CamelInfinispanKey

*Optional Headers*: None

*Result Headers*: None
|===

.Remove Operations
[cols="40%,60%", options="header"]
|===
| Operation Name
| Description

| InfinispanOperation.REMOVE
| *Context*: Embedded / Remote

*Description*: Removes an entry from a cache, optionally only if the value matches a given one

*Required Headers*: CamelInfinispanKey

*Optional Headers*: CamelInfinispanValue

*Result Header*: CamelInfinispanOperationResult

| InfinispanOperation.REMOVEASYNC
| *Description*: Asynchronously removes an entry from a cache, optionally only if the value matches a given one

|===

.Replace Operations
[cols="40%,60%", options="header"]
|===
| Operation Name
| Description

| InfinispanOperation.REPLACE
| *Context*: Embedded / Remote

*Description*: Conditionally replaces an entry in the cache, optionally with expiration

*Required Headers*: CamelInfinispanKey, CamelInfinispanValue, CamelInfinispanOldValue

*Optional Headers*: CamelInfinispanLifespanTime, CamelInfinispanLifespanTimeUnit, CamelInfinispanMaxIdleTime, CamelInfinispanMaxIdleTimeUnit, CamelInfinispanIgnoreReturnValues

*Result Header*: CamelInfinispanOperationResult

| InfinispanOperation.REPLACEASYNC
| *Description*: Asynchronously conditionally replaces an entry in the cache, optionally with expiration

|===

.Clear Operations
[cols="40%,60%", options="header"]
|===
| Operation Name
| Description

| InfinispanOperation.CLEAR
| *Context*: Embedded / Remote

*Description*: Clears the cache

*Required Headers*: None

*Optional Headers*: None

*Result Header*: None

| InfinispanOperation.CLEARASYNC
| *Context*: Embedded / Remote

*Description*: Asynchronously clears the cache

*Required Headers*: None

*Optional Headers*: None

*Result Header*: None
|===

.Size Operation
[cols="40%,60%", options="header"]
|===
| Operation Name
| Description

| InfinispanOperation.SIZE
| *Context*: Embedded / Remote

*Description*: Returns the number of entries in the cache

*Required Headers*: None

*Optional Headers*: None

*Result Header*: CamelInfinispanOperationResult
|===

.Stats Operation
[cols="40%,60%", options="header"]
|===
| Operation Name
| Description

| InfinispanOperation.STATS
| *Context*: Embedded / Remote

*Description*: Returns statistics about the cache

*Required Headers*: None

*Optional Headers*: None

*Result Header*: CamelInfinispanOperationResult
|===

.Query Operation
[cols="40%,60%", options="header"]
|===
| Operation Name
| Description

| InfinispanOperation.QUERY
| *Context*: Remote

*Description*: Executes a query on the cache

*Required Headers*: CamelInfinispanQueryBuilder

*Optional Headers*: None

*Result Header*: CamelInfinispanOperationResult
|===

[NOTE]
====
Any operations that take `CamelInfinispanIgnoreReturnValues` will receive a null result.
====

== Message Headers

[width="100%",cols="10%,10%,10%,10%,60%",options="header",]
|=======================================================================
|Name |Default Value |Type |Context |Description
|CamelInfinispanCacheName |`null` |String |Shared |The cache participating in the operation or event.
|CamelInfinispanOperation |`PUT` |InfinispanOperation |Producer |The operation to perform.
|CamelInfinispanMap |`null` |Map |Producer |A Map to use in case of CamelInfinispanOperationPutAll operation
|CamelInfinispanKey |`null` |Object |Shared |The key to perform the operation to or the key generating the event.
|CamelInfinispanValue |`null` |Object |Producer |The value to use for the operation.
|CamelInfinispanEventType |`null` |String |Consumer |The type of the received event. Possible values defined here org.infinispan.notifications.cachelistener.event.Event.Type
|CamelInfinispanIsPre |`null` |Boolean |Consumer |Infinispan fires two events for each operation: one before and one after the operation.
|CamelInfinispanLifespanTime |`null` |long |Producer |The Lifespan time of a value inside the cache. Negative values are interpreted as infinity.
|CamelInfinispanTimeUnit |`null` |String |Producer |The Time Unit of an entry Lifespan Time.
|CamelInfinispanMaxIdleTime |`null` |long |Producer |The maximum amount of time an entry is allowed to be idle for before it is considered as expired.
|CamelInfinispanMaxIdleTimeUnit |`null` |String |Producer |The Time Unit of an entry Max Idle Time.
|CamelInfinispanQueryBuilder |null |InfinispanQueryBuilder |Producer |The QueryBuilde to use for QUERY command, if not present the command defaults to InifinispanConfiguration's one
|CamelInfinispanIgnoreReturnValues |null |Boolean |Producer |If this header is set, the return value for cache operation returning something is ignored by the client application
|CamelInfinispanOperationResultHeader |null |String |Producer |Store the operation result in a header instead of the message body
|=======================================================================

== Examples

* Retrieve a specific key from the default cache using a custom cache container:

[source,java]
----
from("direct:start")
    .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.GET)
    .setHeader(InfinispanConstants.KEY).constant("123")
    .to("infinispan?cacheContainer=#cacheContainer");
----

* Retrieve a specific key from a named cache:
+
[source,java]
----
from("direct:start")
    .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.PUT)
    .setHeader(InfinispanConstants.KEY).constant("123")
    .to("infinispan:myCacheName");
----

* Put a value with lifespan

[source,java]
----
from("direct:start")
    .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.GET)
    .setHeader(InfinispanConstants.KEY).constant("123")
    .setHeader(InfinispanConstants.LIFESPAN_TIME).constant(100L)
    .setHeader(InfinispanConstants.LIFESPAN_TIME_UNIT.constant(TimeUnit.MILLISECONDS.toString())
    .to("infinispan:myCacheName");
----

* Compute operation through a remapping function on the default cache using a custom cache container:

[source,java]
----
@BindToRegistry("mappingFunction")
BiFunction<String, String, String> comp = (k, v) -> v + "replay";

from("direct:start")
    .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.COMPUTE)
    .setHeader(InfinispanConstants.KEY).constant("123")
    .to("infinispan?cacheContainer=#cacheContainer&remappingFunction=#mappingFunction");
----

This will return oldValue + "replay".

This can be done also as async operation, with the `InfinispanOperation.COMPUTEASYNC` operation

* Retrieve a specific key from the remote cache using a cache container configuration with additional parameters (host, port and protocol version):

[source,java]
----
org.infinispan.client.hotrod.configuration.Configuration cacheContainerConfiguration = new org.infinispan.client.hotrod.configuration.ConfigurationBuilder()
    .addServer()
        .host("localhost")
        .port(9999)
        .version(org.infinispan.client.hotrod.ProtocolVersion.PROTOCOL_VERSION_25)
    .build();
...

from("direct:start")
    .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.GET)
    .setHeader(InfinispanConstants.KEY).constant("123")
    .to("infinispan?cacheContainerConfiguration=#cacheContainerConfiguration");
----

=== XML examples

Routing can also be performed using XML configuration.
The following example demonstrates `camel-infinispan` `local-camel-producer`, a camel route that sends data to an embedded cache created by the `local-cache` module.

[source,java,options="nowrap"]
----
<camelContext id="local-producer" xmlns="http://camel.apache.org/schema/blueprint">
    <route>
        <from uri="timer://local?fixedRate=true&period=5000"/>
        <setHeader headerName="CamelInfinispanKey">
            <constant>CamelTimerCounter</constant>
        </setHeader>
        <setHeader headerName="CamelInfinispanValue">
            <constant>CamelTimerCounter</constant>
        </setHeader>
        <to uri="infinispan://foo?cacheContainer=#cacheManager"/>
        <to uri="log:local-put?showAll=true"/>
    </route>
</camelContext>
----

The provided example requires you to instantiate the [class]``cacheManager``.

You can instantiate the [class]``cacheManager`` bean for Spring XML as follows:

[source,xml,options="nowrap"]
----
<bean id="cacheManager" class="org.infinispan.manager.DefaultCacheManager" init-method="start" destroy-method="stop">
    <constructor-arg type="java.lang.String" value="infinispan.xml"/>
</bean>
----

The following demonstrates how to instantiate the [class]``cacheManager`` bean using Blueprint XML.

[source,xml,options="nowrap"]
----
<bean id="cacheManager" class="org.infinispan.manager.DefaultCacheManager" init-method="start" destroy-method="stop">
    <argument value="infinispan.xml" />
</bean>
----

[NOTE]
====
Both the Spring XML and Blueprint XML examples use the configuration file [path]_infinispan.xml_
 for configuration of the cache. This file must be present on the classpath.
====

== Remote Query

When executing remote queries the cacheManager must be an instance of ``RemoteCacheManager``, and an example configuration utilizing a `RemoteCacheManager` is found below for both Java and blueprint.xml:

.Using only Java
====
[source,java,options="nowrap"]
----
from("direct:start")
    .setHeader(InfinispanConstants.OPERATION, InfinispanConstants.QUERY)
    .setHeader(InfinispanConstants.QUERY_BUILDER,
      new InfinispanQueryBuilder() {
        public Query build(QueryFactory<Query> queryFactory) {
          return queryFactory.from(User.class).having("name").like("%abc%")
                      .build();
        }
      })
    .to("infinispan://localhost?cacheContainer=#cacheManager&cacheName=remote_query_cache") ;
----
====

.Using Blueprint and Java
====
.Java [class]``RemoteCacheManagerFactory`` class:
[source,java,options="nowrap"]
----
public class RemoteCacheManagerFactory {
    ConfigurationBuilder clientBuilder;
    public RemoteCacheManagerFactory(String hostname, int port) {
        clientBuilder = new ConfigurationBuilder();
        clientBuilder.addServer()
            .host(hostname).port(port);
    }
    public RemoteCacheManager newRemoteCacheManager() {
        return new RemoteCacheManager(clientBuilder.build());
    }
}
----
.Java [class]``InfinispanQueryExample`` class:
[source,java,options="nowrap"]
----
public class InfinispanQueryExample {
    public InfinispanQueryBuilder getBuilder() {
        return new InfinispanQueryBuilder() {
            public Query build(QueryFactory<Query> queryFactory) {
                return queryFactory.from(User.class)
                         .having("name")
                         .like("%abc%")
                         .build();
            }
        }
    }
}
----
.blueprint.xml:
[source,xml,options="nowrap"]
----
<bean id=”remoteCacheManagerFactory” class=“com.datagrid.RemoteCacheManagerFactory”>
    <argument value=”localhost”/>
    <argument value="11222”/>
</bean>

<bean id=”cacheManager”
    factory-ref=”remoteCacheManagerFactory”
    factory-method=“newRemoteCacheManager”>
</bean>

<bean id="queryBuilder" class="org.example.com.InfinispanQueryExample"/>

<camelContext id="route" xmlns="http://camel.apache.org/schema/blueprint">
    <route>
        <from uri="direct:start"/>
            <setHeader headerName="CamelInfinispanOperation">
                <constant>CamelInfinispanOperationQuery</constant>
            </setHeader>
            <setHeader headerName="CamelInfinispanQueryBuilder">
                <method ref="queryBuilder" method="getBuilder"/>
            </setHeader>
        <to uri="infinispan://localhost?cacheContainer=#cacheManager&cacheName=remote_query_cache"/>
    </route>
</camelContext>
----
====

The `remote_query_cache` is an arbitrary name for a cache that holds the data, and the results of the query will be a list of domain objects stored as a `CamelInfinispanOperationResult` header.

In addition, there are the following requirements:

* The [class]``RemoteCacheManager`` must be configured to use [class]``ProtoStreamMarshaller``.
* The [class]``ProtoStreamMarshaller`` must be registered with the [class]``RemoteCacheManager``'s serialization context.
* The .proto descriptors for domain objects must be registered with the remote Data Grid server.

== Custom Listeners for Embedded Cache

Custom Listeners for an embedded cache can be registered through the [parameter]``customListener`` parameter as shown below:

.Using Java

[source,java,options="nowrap"]
----
from("infinispan://?cacheContainer=#myCustomContainer&cacheName=customCacheName&customListener=#myCustomListener")
  .to("mock:result");
----

.Using Blueprint

[source,xml,options="nowrap"]
----
<bean id="myCustomContainer" org.infinispan.manager.DefaultCacheManager"
      init-method="start" destroy-method="stop">
      <argument value="infinispan.xml" />
</bean>

<bean id="myCustomListener" class="org.example.com.CustomListener"/>

<camelContext id="route" xmlns="http://camel.apache.org/schema/blueprint">
    <route>
        <from uri="infinispan://?cacheContainer=#myCustomContainer&cacheName=customCacheName&customListener=#myCustomListener"/>
        <to uri="mock:result"/>
    </route>
</camelContext>
----

The instance of [class]``myCustomListener`` must exist.
Users are encouraged to extend the [class]``org.apache.camel.component.infinispan.embedded.InfinispanEmbeddedCustomListener`` and annotate the resulting class with the `@Listener` annotation from [package]#org.infinispan.notifications#
.

[NOTE]
====
Custom filters and converters for embedded caches are currently not supported.
====

== Custom Listeners for Remote Cache

Custom listeners for a remote cache can be registered in the same way as an embedded cache, with the exception that [parameter]``sync=false`` must be present.
For instance:

.Using only Java
====
[source,java,options="nowrap"]
----
from(infinispan://?cacheContainer=#cacheManager&sync=false&customListener=#myCustomListener")
  .to(mock:result);
----
====

.Using Blueprint and Java
====
.Java class:
[source,java,options="nowrap"]
----

public class RemoteCacheManagerFactory {
    ConfigurationBuilder clientBuilder;
    public RemoteCacheManagerFactory(String hostname, int port) {
        clientBuilder = new ConfigurationBuilder();
        clientBuilder.addServer()
            .host(hostname).port(port);
    }
    public RemoteCacheManager newRemoteCacheManager() {
        return new RemoteCacheManager(clientBuilder.build());
    }
}
----
.blueprint.xml:
[source,xml,options="nowrap"]
----
<bean id=”remoteCacheManagerFactory” class=“com.datagrid.RemoteCacheManagerFactory”>
    <argument value=”localhost”/>
    <argument value="11222”/>
</bean>

<bean id=”cacheManager”
    factory-ref=”remoteCacheManagerFactory”
    factory-method=“newRemoteCacheManager”>
</bean>

<bean id="myCustomListener" class="org.example.com.CustomListener"/>

<camelContext id="route" xmlns="http://camel.apache.org/schema/blueprint">
    <route>
        <from uri="infinispan://?cacheContainer=#cacheManager&sync=false&customListener=#myCustomListener"/>
        <to uri="mock:result"/>
    </route>
</camelContext>
----
====

The instance of [class]``myCustomListener`` must exist.
Users are encouraged to extend the [class]``org.apache.camel.component.infinispan.remote.InfinispanRemoteCustomListener`` class and annotate the resulting class with ``@ClientListener``; this annotation is found in [package]#org.infinispan.client.hotrod.annotation#
.

Remote listeners may also be associated with custom filters and converters as shown below:
[source,java,options="nowrap"]
----
@ClientListener(includeCurrentState=true, filterFactoryName = "static-filter-factory", converterFactoryName = "static-converter-factory")
  private static class MyCustomListener extends InfinispanRemoteCustomListener {
}
----

In order to use custom filters or converters classes annotated with `@NamedFactory` must be implemented.
A skeleton that implements the necessary methods is shown below:
[source,java,options="nowrap"]
----
import org.infinispan.notifications.cachelistener.filter;

@NamedFactory(name = "static-converter-factory")
public static class StaticConverterFactory implements CacheEventConverterFactory {
  @Override
  public CacheEventConverter<Integer, String, CustomEvent> getConverter(Object[] params) {
    ...
  }

  static class StaticConverter implements CacheEventConverter<Integer, String, CustomEvent>, Serializable {
    @Override
    public CustomEvent convert(Integer key, String previousValue, Metadata previousMetadata,
                               String value, Metadata metadata, EventType eventType) {
      ...
    }
  }
}

@NamedFactory(name = "static-filter-factory")
public static class StaticCacheEventFilterFactory implements CacheEventFilterFactory {
  @Override
  public CacheEventFilter<Integer, String> getFilter(final Object[] params) {
    ...
  }

  static class StaticCacheEventFilter implements CacheEventFilter<Integer, String>, Serializable {
    @Override
    public boolean accept(Integer key, String previousValue, Metadata previousMetadata,
                          String value, Metadata metadata, EventType eventType) {
      ...
    }
  }
}
----

Custom filters and converters must be registered with the server.
.

[NOTE]
====
In order to listen for remote HotRod events the cacheManager must be of type [class]``RemoteCacheManager`` and instantiated.
====

== Using the Infinispan based idempotent repository

In this section we will use the Infinispan based idempotent repository.

First, we need to create a cacheManager and then configure our

[source,java]
----
org.apache.camel.component.infinispan.processor.idempotent.InfinispanIdempotentRepository:
----

[source,xml]
----
<!-- set up the cache manager -->
<bean id="cacheManager"
      class="org.infinispan.manager.DefaultCacheManager"
      init-method="start"
      destroy-method="stop"/>

<!-- set up the repository -->
<bean id="infinispanRepo"
      class="org.apache.camel.component.infinispan.processor.idempotent.InfinispanIdempotentRepository"
      factory-method="infinispanIdempotentRepository">
    <argument ref="cacheManager"/>
    <argument value="idempotent"/>
</bean>
----

Then we can create our Infinispan idempotent repository in the spring
XML file as well:

[source,xml]
----
<camelContext xmlns="http://camel.apache.org/schema/spring">
    <route id="JpaMessageIdRepositoryTest">
        <from uri="direct:start" />
        <idempotentConsumer messageIdRepositoryRef="infinispanStore">
            <header>messageId</header>
            <to uri="mock:result" />
        </idempotentConsumer>
    </route>
</camelContext>
----

== See Also

* Configuring Camel
* Component
* Endpoint
* Getting Started

[[infinispan-component]]
= Infinispan Component

*Available as of Camel version 2.13*

This component allows you to interact with
http://infinispan.org/[Infinispan] distributed data grid / cache.
Infinispan is an extremely scalable, highly available key/value data
store and data grid platform written in Java.

Infinispan requires at least Java 8.

Maven users will need to add the following dependency to their `pom.xml`
for this component:

[source,xml]
------------------------------------------------------------
<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-infinispan</artifactId>
    <version>x.x.x</version>
    <!-- use the same version as your Camel core version -->
</dependency>
------------------------------------------------------------

== URI format

[source,java]
-------------------------------
infinispan://cacheName?[options]
-------------------------------

== URI Options

The producer allows sending messages to a local infinispan cache
configured in the registry, or to a remote cache using the HotRod
protocol. The consumer allows listening for events from local infinispan cache
accessible from the registry.

// component options: START
The Infinispan component supports 4 options, which are listed below.

[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| *configuration* (common) | The default configuration shared among endpoints. |  | InfinispanConfiguration
| *cacheContainer* (common) | The default cache container. |  | BasicCacheContainer
| *resolveProperty Placeholders* (advanced) | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | boolean
| *basicPropertyBinding* (advanced) | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
|===
// component options: END

// endpoint options: START
The Infinispan endpoint is configured using URI syntax:

----
infinispan:cacheName
----

with the following path and query parameters:

=== Path Parameters (1 parameters):

[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| *cacheName* | *Required* The cache to use |  | String
|===

=== Query Parameters (21 parameters):

[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| *hosts* (common) | Specifies the host of the cache on Infinispan instance |  | String
| *queryBuilder* (common) | Specifies the query builder. |  | InfinispanQueryBuilder
| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
| *clusteredListener* (consumer) | If true, the listener will be installed for the entire cluster | false | boolean
| *command* (consumer) | *Deprecated* The operation to perform. | PUT | String
| *customListener* (consumer) | Returns the custom listener in use, if provided |  | InfinispanCustom Listener
| *eventTypes* (consumer) | Specifies the set of event types to register by the consumer. Multiple event can be separated by comma. The possible event types are: CACHE_ENTRY_ACTIVATED, CACHE_ENTRY_PASSIVATED, CACHE_ENTRY_VISITED, CACHE_ENTRY_LOADED, CACHE_ENTRY_EVICTED, CACHE_ENTRY_CREATED, CACHE_ENTRY_REMOVED, CACHE_ENTRY_MODIFIED, TRANSACTION_COMPLETED, TRANSACTION_REGISTERED, CACHE_ENTRY_INVALIDATED, DATA_REHASHED, TOPOLOGY_CHANGED, PARTITION_STATUS_CHANGED |  | String
| *sync* (consumer) | If true, the consumer will receive notifications synchronously | true | boolean
| *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
| *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
| *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing. | false | boolean
| *operation* (producer) | The operation to perform. | PUT | InfinispanOperation
| *basicPropertyBinding* (advanced) | Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean
| *cacheContainer* (advanced) | Specifies the cache Container to connect |  | BasicCacheContainer
| *cacheContainerConfiguration* (advanced) | The CacheContainer configuration. Uses if the cacheContainer is not defined. Must be the following types: org.infinispan.client.hotrod.configuration.Configuration - for remote cache interaction configuration; org.infinispan.configuration.cache.Configuration - for embedded cache interaction configuration; |  | Object
| *configurationProperties* (advanced) | Implementation specific properties for the CacheManager |  | Map
| *configurationUri* (advanced) | An implementation specific URI for the CacheManager |  | String
| *flags* (advanced) | A comma separated list of Flag to be applied by default on each cache invocation, not applicable to remote caches. |  | String
| *remappingFunction* (advanced) | Set a specific remappingFunction to use in a compute operation |  | BiFunction
| *resultHeader* (advanced) | Store the operation result in a header instead of the message body. By default, resultHeader == null and the query result is stored in the message body, any existing content in the message body is discarded. If resultHeader is set, the value is used as the name of the header to store the query result and the original message body is preserved. This value can be overridden by an in message header named: CamelInfinispanOperationResultHeader |  | Object
| *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
|===
// endpoint options: END
// spring-boot-auto-configure options: START
== Spring Boot Auto-Configuration

When using Spring Boot make sure to use the following Maven dependency to have support for auto configuration:

[source,xml]
----
<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-infinispan-starter</artifactId>
  <version>x.x.x</version>
  <!-- use the same version as your Camel core version -->
</dependency>
----

The component supports 23 options, which are listed below.

[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| *camel.component.infinispan.basic-property-binding* | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | Boolean
| *camel.component.infinispan.cache-container* | The default cache container. The option is a org.infinispan.commons.api.BasicCacheContainer type. |  | String
| *camel.component.infinispan.configuration.cache-container* | Specifies the cache Container to connect |  | BasicCacheContainer
| *camel.component.infinispan.configuration.cache-container-configuration* | The CacheContainer configuration. Uses if the cacheContainer is not defined. Must be the following types: org.infinispan.client.hotrod.configuration.Configuration - for remote cache interaction configuration; org.infinispan.configuration.cache.Configuration - for embedded cache interaction configuration; |  | Object
| *camel.component.infinispan.configuration.clustered-listener* | If true, the listener will be installed for the entire cluster | false | Boolean
| *camel.component.infinispan.configuration.configuration-properties* | Implementation specific properties for the CacheManager |  | Map
| *camel.component.infinispan.configuration.configuration-uri* | An implementation specific URI for the CacheManager |  | String
| *camel.component.infinispan.configuration.custom-listener* | Returns the custom listener in use, if provided |  | InfinispanCustom Listener
| *camel.component.infinispan.configuration.event-types* | Specifies the set of event types to register by the consumer. Multiple event can be separated by comma. <p/> The possible event types are: CACHE_ENTRY_ACTIVATED, CACHE_ENTRY_PASSIVATED, CACHE_ENTRY_VISITED, CACHE_ENTRY_LOADED, CACHE_ENTRY_EVICTED, CACHE_ENTRY_CREATED, CACHE_ENTRY_REMOVED, CACHE_ENTRY_MODIFIED, TRANSACTION_COMPLETED, TRANSACTION_REGISTERED, CACHE_ENTRY_INVALIDATED, DATA_REHASHED, TOPOLOGY_CHANGED, PARTITION_STATUS_CHANGED |  | Set
| *camel.component.infinispan.configuration.flags* | A comma separated list of Flag to be applied by default on each cache invocation, not applicable to remote caches. |  | Flag[]
| *camel.component.infinispan.configuration.hosts* | Specifies the host of the cache on Infinispan instance |  | String
| *camel.component.infinispan.configuration.operation* | The operation to perform. |  | InfinispanOperation
| *camel.component.infinispan.configuration.query-builder* | Specifies the query builder. |  | InfinispanQueryBuilder
| *camel.component.infinispan.configuration.remapping-function* | Set a specific remappingFunction to use in a compute operation |  | BiFunction
| *camel.component.infinispan.configuration.result-header* | Store the operation result in a header instead of the message body. By default, resultHeader == null and the query result is stored in the message body, any existing content in the message body is discarded. If resultHeader is set, the value is used as the name of the header to store the query result and the original message body is preserved. This value can be overridden by an in message header named: CamelInfinispanOperationResultHeader |  | Object
| *camel.component.infinispan.configuration.sync* | If true, the consumer will receive notifications synchronously | true | Boolean
| *camel.component.infinispan.customizer.embedded-cache-manager.enabled* | Enable or disable the cache-manager customizer. | true | Boolean
| *camel.component.infinispan.customizer.embedded-cache-manager.override* | Configure if the cache manager eventually set on the component should be overridden by the customizer. | false | Boolean
| *camel.component.infinispan.customizer.remote-cache-manager.enabled* | Enable or disable the cache-manager customizer. | true | Boolean
| *camel.component.infinispan.customizer.remote-cache-manager.override* | Configure if the cache manager eventually set on the component should be overridden by the customizer. | false | Boolean
| *camel.component.infinispan.enabled* | Enable infinispan component | true | Boolean
| *camel.component.infinispan.resolve-property-placeholders* | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | Boolean
| *camel.component.infinispan.configuration.command* | *Deprecated* The operation to perform. | PUT | String
|===
// spring-boot-auto-configure options: END

== Message Headers

[width="100%",cols="10%,10%,10%,10%,60%",options="header",]
|=======================================================================
|Name |Default Value |Type |Context |Description
|CamelInfinispanCacheName |`null` |String |Shared |The cache participating in the operation or event.
|CamelInfinispanOperation |`PUT` |InfinispanOperation |Producer |The operation to perform.
|CamelInfinispanMap |`null` |Map |Producer |A Map to use in case of CamelInfinispanOperationPutAll operation
|CamelInfinispanKey |`null` |Object |Shared |The key to perform the operation to or the key generating the event.
|CamelInfinispanValue |`null` |Object |Producer |The value to use for the operation.
|CamelInfinispanEventType |`null` |String |Consumer |The type of the received event. Possible values defined here org.infinispan.notifications.cachelistener.event.Event.Type
|CamelInfinispanIsPre |`null` |Boolean |Consumer |Infinispan fires two events for each operation: one before and one after the operation.
|CamelInfinispanLifespanTime |`null` |long |Producer |The Lifespan time of a value inside the cache. Negative values are interpreted as infinity.
|CamelInfinispanTimeUnit |`null` |String |Producer |The Time Unit of an entry Lifespan Time.
|CamelInfinispanMaxIdleTime |`null` |long |Producer |The maximum amount of time an entry is allowed to be idle for before it is considered as expired.
|CamelInfinispanMaxIdleTimeUnit |`null` |String |Producer |The Time Unit of an entry Max Idle Time.
|CamelInfinispanQueryBuilder |null |InfinispanQueryBuilder |Producer |The QueryBuilde to use for QUERY command, if not present the command defaults to InifinispanConfiguration's one
|CamelInfinispanIgnoreReturnValues |null |Boolean |Producer |If this header is set, the return value for cache operation returning something is ignored by the client application
|CamelInfinispanOperationResultHeader |null |String |Producer |Store the operation result in a header instead of the message body
|=======================================================================

== Examples

* Retrieve a specific key from the default cache using a custom cache container:

[source,java]
----
from("direct:start")
    .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.GET)
    .setHeader(InfinispanConstants.KEY).constant("123")
    .to("infinispan?cacheContainer=#cacheContainer");
----

* Retrieve a specific key from a named cache:
+
[source,java]
----
from("direct:start")
    .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.PUT)
    .setHeader(InfinispanConstants.KEY).constant("123")
    .to("infinispan:myCacheName");
----

* Put a value with lifespan

[source,java]
----
from("direct:start")
    .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.GET)
    .setHeader(InfinispanConstants.KEY).constant("123")
    .setHeader(InfinispanConstants.LIFESPAN_TIME).constant(100L)
    .setHeader(InfinispanConstants.LIFESPAN_TIME_UNIT.constant(TimeUnit.MILLISECONDS.toString())
    .to("infinispan:myCacheName");
----

* Compute operation through a remapping function on the default cache using a custom cache container:

[source,java]
----
@BindToRegistry("mappingFunction")
BiFunction<String, String, String> comp = (k, v) -> v + "replay";

from("direct:start")
    .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.COMPUTE)
    .setHeader(InfinispanConstants.KEY).constant("123")
    .to("infinispan?cacheContainer=#cacheContainer&remappingFunction=#mappingFunction");
----

This will return oldValue + "replay".

This can be done also as async operation, with the `InfinispanOperation.COMPUTEASYNC` operation

* Retrieve a specific key from the remote cache using a cache container configuration with additional parameters (host, port and protocol version):

[source,java]
----
org.infinispan.client.hotrod.configuration.Configuration cacheContainerConfiguration = new org.infinispan.client.hotrod.configuration.ConfigurationBuilder()
    .addServer()
        .host("localhost")
        .port(9999)
        .version(org.infinispan.client.hotrod.ProtocolVersion.PROTOCOL_VERSION_25)
    .build();
...

from("direct:start")
    .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.GET)
    .setHeader(InfinispanConstants.KEY).constant("123")
    .to("infinispan?cacheContainerConfiguration=#cacheContainerConfiguration");
----

== Using the Infinispan based idempotent repository

In this section we will use the Infinispan based idempotent repository.

First, we need to create a cacheManager and then configure our

[source,java]
----
org.apache.camel.component.infinispan.processor.idempotent.InfinispanIdempotentRepository:
----

[source,xml]
----
<!-- set up the cache manager -->
<bean id="cacheManager"
      class="org.infinispan.manager.DefaultCacheManager"
      init-method="start"
      destroy-method="stop"/>

<!-- set up the repository -->
<bean id="infinispanRepo"
      class="org.apache.camel.component.infinispan.processor.idempotent.InfinispanIdempotentRepository"
      factory-method="infinispanIdempotentRepository">
    <argument ref="cacheManager"/>
    <argument value="idempotent"/>
</bean>
----

Then we can create our Infinispan idempotent repository in the spring
XML file as well:

[source,xml]
----
<camelContext xmlns="http://camel.apache.org/schema/spring">
    <route id="JpaMessageIdRepositoryTest">
        <from uri="direct:start" />
        <idempotentConsumer messageIdRepositoryRef="infinispanStore">
            <header>messageId</header>
            <to uri="mock:result" />
        </idempotentConsumer>
    </route>
</camelContext>
----

== Using the Infinispan based route policy

== See Also

* Configuring Camel
* Component
* Endpoint
* Getting Started