blog

Creating an Advisor to Check for SELinux and Meltdown/Spectre: Part Two

Paul Namuag

In part 1 of this blog, we showed you how to integrate a basic check with SELinux modes. In this part 2 blog, we’ll discuss and go over with Meltdown/Spectre integration to our Advisors, set an alarm, and then see how to debug the script.

Let’s have a quick review of the Meltdown/Spectre vulnerability first. Currently, there are 8 variants that this CVE is covering. These are,

Some of these vulnerabilities or the so-called L1 Terminal Fault (L1TF) which is a speculative execution side-channel attack were just recently discovered, in contrast to the other variants Meltdown/Spectre. So let’s go ahead and integrate this in our Advisor, and scan our servers to identify if any is affected or not, and trigger an Alarm if required.

ClusterControl Advisor Implementation and Shell Script Invocation

First, we’ll setup the shell script. I’m using this implementation from Stéphane Lesimple (a.k.a. speed47). In my MySQL nodes, I run the following bash commands below:

$ sudo wget https://meltdown.ovh -O /usr/bin/spectre-meltdown-checker.sh
$ sudo chmod +x /usr/bin/spectre-meltdown-checker.sh

Now, let’s create the new file as follows:

Then, let’s copy the code that I have in my own Github repository and paste it into Cluster > Manage > Developer Studio. Then open the file we have just created under the myadvisors/host/spectre-meltdown-checker.js as seen below, and paste the code there.

Before going through the code, let’s discuss first the logical flow that we want to achieve.

Now, let’s dig into the code and explain what we are going to achieve. In lines 16 – 25, we have just declared the myAlarm(, <message>, <recommendation>)</span> function. This function will just return an integer which does the <span>alarmId(<category>, <isHost>, <title>, <message>, <recommendation>)</span> function returns. The returned value can be used when creating an alarm.</p> <pre><code class="language-javascript">function myAlarm(title, message, recommendation) { return Alarm::alarmId( Node, true, title, message, recommendation ); }</code></pre> <p>Now let’s skip some lines and go to the important ones. In line 48 – 50, we’re calling</p> <pre><code class="language-javascript">var shell = "test -e /usr/bin/spectre-meltdown-checker.sh"; var retval = host.system(shell); var reply = retval["result"];</code></pre> <p>We’re checking if the <em>spectre-meltdown-checker.sh</em> has been setup and installed at <em>/usr/bin</em> path. Lines 56 – 72, this is a failback in case we don’t find the script, notify the user through Advisors page that this has to be installed and setup. If found that it has been setup properly, lines 75 – 85 will check if a report has been generated and it looks as follows:</p> <pre><code class="language-javascript">var dateTime = CmonDateTime::currentDateTime(); var dateToday = dateTime.toString(ShortDateFormat); dateToday = dateToday.replace("/", "-"); var todayLogFile = "/tmp/spectre-meltdown" + "_" + dateToday + ".log"; shell = "test -e " + todayLogFile; // if /tmp/spectre-metldown_m.yy.dd.log exist. retval = host.system(shell); shell = "wc -l " + todayLogFile + "|awk -F ' ' '{print $1}'|tr -d 'n'"; // check if the file has contents var retvalLogContents = host.system(shell); replyLogContents = retvalLogContents["result"];</code></pre> <p>If it has no generated result yet, then the lines 90 – 99 handles the generation of report by such calling the <em>spectre-meltdown-check.sh</em>. Let’s see below,</p> <pre><code class="language-javascript">// Let's generate result if command fails and log do not exist. shell = "sudo nohup /usr/bin/spectre-meltdown-checker.sh --batch json > " + todayLogFile; retval = host.system(shell); reply = retval["result"]; var jsonMetldownCheckerReply = JSON::parse(reply.toString()); var errTimeoutMsg = "ssh timeout: Execution timeout"; print(shell); print ("retval" + retval); print("jsonMetldownCheckerReply " + retval);</code></pre> <p>Now line 90 shows that we are calling a nohup (no hang up) for <span>/usr/bin/spectre-meltdown-checker.sh</span> and passing <span>–batch json</span> to format the output as a JSON formatted output. Why using nohup? Well, CCDSL has its own limitation and we’re setting a 5-second call for such host.system() command calls, thus the return message would be like</p> <pre><code class="language-bash">ssh timeout: Execution timeout 5 secs has reached (channel_closing).</code></pre> <p>We’re planning to make this a configurable value, but we have to live with it for now.</p> <p>Since we’re going to generate a report, the lines 115 – 128 will handle a notification in case the generated log file hasn’t yet been created and notify the user to come back after a minute. You can also manually run the advisor by clicking the <img width="218" height="48" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20218%2048'%3E%3C/svg%3E" data-lazy-src="https://severalnines.com/sites/default/files/blog/node_5397/image1.jpg"><noscript><img width="218" height="48" src="https://severalnines.com/sites/default/files/blog/node_5397/image1.jpg"></noscript> button for the spectre-meltdown-checker.js script we have in the Developer Studio.</p> <p>We’re almost done now with the script, let’s go further down. Lines 130 – 144,</p> <pre><code class="language-javascript">shell = "cat " + todayLogFile + " | tr -d 'n'"; retval = host.system(shell); reply = retval["result"]; jsonStr = '{"list":' + reply.toString() + '}'; mapSpectreMeltdownResult = JSON::parse(jsonStr); for (ndex=0; ndex < mapSpectreMeltdownResult["list"].size(); ndex++) { if (mapSpectreMeltdownResult["list"][ndex]["VULNERABLE"]) { msg += "<br />Host is affected by " + mapSpectreMeltdownResult["list"][ndex]["CVE"] + "/" + mapSpectreMeltdownResult["list"][ndex]["NAME"] + ". " + "Suggested action: "" + mapSpectreMeltdownResult["list"][ndex]["INFOS"] + """; } }</code></pre> <p>Let’s have a look at that. Line 130 – 131 does a shell invocation in which we just invoke the Linux command using <a href="http://man7.org/linux/man-pages/man1/cat.1.html" rel="nofollow noopener" target="_blank">cat</a> command. After fetching the result with <span>cat</span> command, we parse the result again as a JSON array format with keyname == “<em>list</em>”. One of CCDSL’s limitation as of this time is that it is not able to handle JSON formatted array when it starts and ends with squared brackets “[“ and “]”. However, there’s a work around, as enclosing with curly braces resolves the case here. Then lines 136 – 144 is doing a for loop in order to handle the multi-arrayed values of variable <span>mapSpectreMeltdownResult</span>. This is where we are storing the contents taken from the generated report while we parse it.</p> <h2>Setting up the Alarm</h2> <p>Now, since we’re almost in the end of the code. Go to lines 146 – 156,</p> <pre><code class="language-javascript">if (msg.length()) { var recommendation = "We advise to update your kernel to the latest version " "or check your Linux Distro and see the recent updates about this CVE."; advice.setSeverity(Warning); advice.setJustification(msg); advice.setAdvice(recommendation); myAlarmId = myAlarm("Metldown/Spectre Affected!", msg, recommendation); // Let's raise an alarm. host.raiseAlarm(myAlarmId, Warning); }</code></pre> <p>we check the message length if any (which means there’s a vulnerability detected on the host), then set the Advisor advice now which is found in 149 – 151. Now on 153 – 155, you’ll see that we have setup the Alarm. It’s pretty easy eh? The line 153 calls the function that we have defined above the code which was discussed earlier at lines 16 – 25. By just calling <span>host.raiseAlarm(<type>, <severity>, <[message]>)</span> method, we are able to raise an Alarm which would look like below:</p> <div class="image"> <div class="image_inner"><img width="474" height="524" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20474%20524'%3E%3C/svg%3E" data-lazy-src="https://severalnines.com/sites/default/files/blog/node_5397/image7.jpg"><noscript><img width="474" height="524" src="https://severalnines.com/sites/default/files/blog/node_5397/image7.jpg"></noscript></div> </div> <p>Once you click on the warning, it’ll show as follows:</p> <div class="image"> <div class="image_inner"><img width="1999" height="466" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201999%20466'%3E%3C/svg%3E" data-lazy-src="https://severalnines.com/sites/default/files/blog/node_5397/image5.jpg"><noscript><img width="1999" height="466" src="https://severalnines.com/sites/default/files/blog/node_5397/image5.jpg"></noscript></div> </div> <p>and clicking the “<em>Full Alarm Details</em>”, it’ll reveal all of the messages as follows:</p> <div class="image"> <div class="image_inner"><img width="1498" height="1308" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201498%201308'%3E%3C/svg%3E" data-lazy-src="https://severalnines.com/sites/default/files/blog/node_5397/image2.jpg"><noscript><img width="1498" height="1308" src="https://severalnines.com/sites/default/files/blog/node_5397/image2.jpg"></noscript></div> </div> <p>Since we have setup the alarm, once you have this script compiled and run under Developer Studio, schedule this Advisor. To quickly check the result and see it in action, you can try to schedule it, let say, every 5 minutes or 10 minutes since the script will run only once per-day as long as the generated report exists. This is how it looks like:</p> <div class="image"> <div class="image_inner"><img width="1999" height="1215" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201999%201215'%3E%3C/svg%3E" data-lazy-src="https://severalnines.com/sites/default/files/blog/node_5397/image3.jpg"><noscript><img width="1999" height="1215" src="https://severalnines.com/sites/default/files/blog/node_5397/image3.jpg"></noscript></div> </div> <p>Isn’t it nice? This is cool stuff, we’re able to integrate security checks like these Spectre/Meltdown vulnerabilities. It’s pretty easy though specially if you have Javascript background but regardless of the familiarity, it would be easy to handle this one as there are plenty of examples we have in our <a href="https://github.com/severalnines/s9s-advisor-bundle" rel="nofollow noopener" target="_blank">Github repository</a>.</p> <h2>Debugging the Advisor Script</h2> <p>The CCDSL is not that rich and sophisticated kind of language but it does provide the ways to debug your script or there’s a tool to achieve this.</p> <p>Let’s go back to lines 97 – 99,</p> <pre><code class="language-javascript">print(shell); print ("retval" + retval); print("jsonMetldownCheckerReply " + retval);</code></pre> <p>These allows us to print the value of the variables on what it holds and what it contains. It’s not pretty but it works and does what we need. For that example, it’ll show the following result in the Message tab of the Developer Studio:</p> <div class="image"> <div class="image_inner"><img width="1422" height="586" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201422%20586'%3E%3C/svg%3E" data-lazy-src="https://severalnines.com/sites/default/files/blog/node_5397/image6.jpg"><noscript><img width="1422" height="586" src="https://severalnines.com/sites/default/files/blog/node_5397/image6.jpg"></noscript></div> </div> <h2>Debugging with ClusterControl CLI tools</h2> <p>Aside from using “print()” function, we can actually use the <a href="https://severalnines.com/docs/components.html#clustercontrol-cli">CLI tools</a> to run the .js file. For example, let’s try and debug the JavaScript file.</p> <pre><code class="language-bash">[root@ccnode vagrant]# s9s script --execute --cluster-id=2 -u admin --password=b8be2b56-80f9-45c7-a248-65ee6744a12f --print-json spectre-meltdown-checker.js { "controller_id": "clustercontrol", "reply_received": "2018-09-28T23:39:40.084Z", "request_created": "2018-09-28T23:39:40.082Z", "request_id": 2, "request_processed": "2018-09-28T23:39:40.087Z", "request_status": "Ok", "request_user_id": 3, "results": { "exitStatus": "null", "fileName": "spectre-meltdown-checker.js", "messages": [ { "lineNumber": 16, "message": "spectre-meltdown-checker.js:16: syntax error.", "severity": "error" } ], "status": "ParseError" } }</code></pre> <p>Let me explain what we’re doing here.</p> <ol> <li>I uploaded the file named spectre-meltdown-checker.js to the ClusterControl monitor host</li> <li>Locate your username and password which you can find in /etc/s9s.conf. Take note that, you have to open or read the file with sudo privilege since it’s owned by root<br /> e.g. content of /etc/s9s.conf</p> <pre><code class="language-bash"># # Configuration file created by the Cmon Controller for the # s9s command line tool. Please feel free to edit or # remove this file # [global] controller = https://localhost:9501 cmon_user = "admin" cmon_password = "b8be2b56-80f9-45c7-a248-65ee6744a12f"</code></pre> </li> <li>Run the command as follows, <pre><code class="language-bash">$ s9s script --execute --cluster-id=<your-cluster-id> -u <your-admin-username> --password=<your-admin-password> --print-json spectre-meltdown-checker.js</code></pre> </li> </ol> <p>Based on the example I have, I intentionally make an error on the script to show you how it works. We can even play around and get with the JSON values and pipe with python.</p> <p>e.g.</p> <pre><code class="language-bash">// Let’s get the advice value [root@ccnode vagrant]# s9s script --execute --cluster-id=2 -u admin --password=b8be2b56-80f9-45c7-a248-65ee6744a12f --print-json spectre-meltdown-checker.js | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["results"]["exitStatus"]["0"]["advice"]'; We advise to update your kernel to the latest version or check your Linux Distro and see the recent updates about this CVE.</code></pre> <p>To get the contents of the message, you can even do like this,</p> <p>e.g.</p> <pre><code class="language-bash">[root@ccnode vagrant]# s9s script --execute --cluster-id=2 -u admin --password=b8be2b56-80f9-45c7-a248-65ee6744a12f --print-json spectre-meltdown-checker.js | python -c 'import json,sys;obj=json.load(sys.stdin);size=len(obj["results"]["messages"]); map(lambda i: sys.stdout.write(obj["results"]["messages"][i]["message"] + "n"), range(size))'; 192.168.70.10 ========================== Meltdown/Spectre Check We advise to update your kernel to the latest version or check your Linux Distro and see the recent updates about this CVE. <br />Host is affected by CVE-2017-5753/SPECTRE VARIANT 1. Suggested action: "Kernel source needs to be patched to mitigate the vulnerability"<br />Host is affected by CVE-2017-5715/SPECTRE VARIANT 2. Suggested action: "IBRS+IBPB or retpoline+IBPB is needed to mitigate the vulnerability"<br />Host is affected by CVE-2017-5754/MELTDOWN. Suggested action: "PTI is needed to mitigate the vulnerability"<br />Host is affected by CVE-2018-3640/VARIANT 3A. Suggested action: "an up-to-date CPU microcode is needed to mitigate this vulnerability"<br />Host is affected by CVE-2018-3639/VARIANT 4. Suggested action: "Neither your CPU nor your kernel support SSBD"<br />Host is affected by CVE-2018-3620/VARIANT 4. Suggested action: "Your kernel doesn't support PTE inversion, update it" 192.168.70.20 ========================== Meltdown/Spectre Check We advise to update your kernel to the latest version or check your Linux Distro and see the recent updates about this CVE. <br />Host is affected by CVE-2017-5753/SPECTRE VARIANT 1. Suggested action: "Kernel source needs to be patched to mitigate the vulnerability"<br />Host is affected by CVE-2017-5715/SPECTRE VARIANT 2. Suggested action: "IBRS+IBPB or retpoline+IBPB is needed to mitigate the vulnerability"<br />Host is affected by CVE-2017-5754/MELTDOWN. Suggested action: "PTI is needed to mitigate the vulnerability"<br />Host is affected by CVE-2018-3640/VARIANT 3A. Suggested action: "an up-to-date CPU microcode is needed to mitigate this vulnerability"<br />Host is affected by CVE-2018-3639/VARIANT 4. Suggested action: "Neither your CPU nor your kernel support SSBD"<br />Host is affected by CVE-2018-3620/VARIANT 4. Suggested action: "Your kernel doesn't support PTE inversion, update it" 192.168.70.30 ========================== Meltdown/Spectre Check Script Setup/Installation required! <br />Empty reply from the command. It looks like you have not setup the shell script yet. You can get the shell script from https://meltdown.ovh<br /> or run "sudo wget https://meltdown.ovh -O /usr/bin/spectre-meltdown-checker.sh; sudo chmod +x /usr/bin/spectre-meltdown-checker.sh"</code></pre> <h2>Conclusion</h2> <p>The scripts we have created for selinux-checker.js and spectre-meltdown-checker.js are simple implementations, it shows you how you can integrate these checks. For Spectre/Meltdown checks, we can even improve the implementation like to create an Advisor as well that will just remove the /tmp/spectre-meltdow*.log files in case the number of files goes high.</p> <p>The ClusterControl Domain Specific Language is simple but powerful. There are plenty of ways to incorporate your tools or scripts into the Advisors. We’d like to hear more of your feedback and experiences</p> </div> <aside class="sidebar col-12 col-md-5 col-bleed-x"> <div class="sidebar-content"> <h5>Related Products</h5> <ul class="related-products"> <li class="product"> <a href="https://severalnines.com/product/clustercontrol/""> <img width="202" height="32" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20202%2032'%3E%3C/svg%3E" alt="logo-clustercontrol" data-lazy-src="https://severalnines.com/wp-content/themes/severalnines/assets/img/acf/logo-clustercontrol.svg"><noscript><img width="202" height="32" src="https://severalnines.com/wp-content/themes/severalnines/assets/img/acf/logo-clustercontrol.svg" alt="logo-clustercontrol"></noscript> <p>Worry-free database automation</p> </a> </li> </ul> </div> </aside> </div> <section class="archive-block"> <div class="container"> <div class="grid"> <header class="col-12 block-header"> <h2 class="section-title">Related content</h2> </header> <div class="col-12 archive-list"> <div class="archive-wrapper"> <div class="box post"> <div class="box-content"> <div class="image-wrapper"> <a href="https://severalnines.com/blog/clustercontrol-adds-scale-out-for-redis-sql-server-and-elasticsearch-in-latest-release/" title="ClusterControl adds scale out for Redis, SQL Server, and Elasticsearch in latest release"> <picture><source data-lazy-srcset="https://severalnines.com/wp-content/webp-express/webp-images/uploads/2022/08/Several9s_post_3_image-600x340.png.webp" type="image/webp"><img width="600" height="340" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20340'%3E%3C/svg%3E" class="attachment-archive size-archive wp-post-image webpexpress-processed" alt="" loading="lazy" data-lazy-src="https://severalnines.com/wp-content/uploads/2022/08/Several9s_post_3_image-600x340.png"><noscript><img width="600" height="340" src="https://severalnines.com/wp-content/uploads/2022/08/Several9s_post_3_image-600x340.png" class="attachment-archive size-archive wp-post-image webpexpress-processed" alt="" loading="lazy"></noscript></picture> </a> </div> <div class="text-area"> <div class="taxonomy-meta"> <a class="related-product" href="https://severalnines.com/related-product/clustercontrol/"> <img width="40" height="40" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2040%2040'%3E%3C/svg%3E" alt="clustercontrol" data-lazy-src="https://severalnines.com/wp-content/themes/severalnines/assets/img/acf/clustercontrol.svg"><noscript><img width="40" height="40" src="https://severalnines.com/wp-content/themes/severalnines/assets/img/acf/clustercontrol.svg" alt="clustercontrol"></noscript> </a> </div> <div class="meta-content"> <span class="date">August 2, 2022</span> <span class="author">Sarah Morris</span> </div> <div class="content-wrapper"> <a href="https://severalnines.com/blog/clustercontrol-adds-scale-out-for-redis-sql-server-and-elasticsearch-in-latest-release/" title="ClusterControl adds scale out for Redis, SQL Server, and Elasticsearch in latest release"> <h3 class="archive-title"> ClusterControl adds scale out for Redis, SQL Server, and Elasticsearch in latest release </h3> </a> </div> </div> </div> </div> <div class="box post"> <div class="box-content"> <div class="image-wrapper"> <a href="https://severalnines.com/blog/private-cloud-and-on-prem-database-architectures-with-clustercontrol/" title="Private cloud and on-prem database architectures with ClusterControl"> <picture><source data-lazy-srcset="https://severalnines.com/wp-content/webp-express/webp-images/uploads/2022/05/thisisengineering-raeng-zBLtU0zbJcU-unsplash-600x340.png.webp" type="image/webp"><img width="600" height="340" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20340'%3E%3C/svg%3E" class="attachment-archive size-archive wp-post-image webpexpress-processed" alt="" loading="lazy" data-lazy-src="https://severalnines.com/wp-content/uploads/2022/05/thisisengineering-raeng-zBLtU0zbJcU-unsplash-600x340.png"><noscript><img width="600" height="340" src="https://severalnines.com/wp-content/uploads/2022/05/thisisengineering-raeng-zBLtU0zbJcU-unsplash-600x340.png" class="attachment-archive size-archive wp-post-image webpexpress-processed" alt="" loading="lazy"></noscript></picture> </a> </div> <div class="text-area"> <div class="taxonomy-meta"> <a class="related-product" href="https://severalnines.com/related-product/clustercontrol/"> <img width="40" height="40" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2040%2040'%3E%3C/svg%3E" alt="clustercontrol" data-lazy-src="https://severalnines.com/wp-content/themes/severalnines/assets/img/acf/clustercontrol.svg"><noscript><img width="40" height="40" src="https://severalnines.com/wp-content/themes/severalnines/assets/img/acf/clustercontrol.svg" alt="clustercontrol"></noscript> </a> </div> <div class="meta-content"> <span class="date">June 8, 2022</span> <span class="author">Kyle Buzzell</span> </div> <div class="content-wrapper"> <a href="https://severalnines.com/blog/private-cloud-and-on-prem-database-architectures-with-clustercontrol/" title="Private cloud and on-prem database architectures with ClusterControl"> <h3 class="archive-title"> Private cloud and on-prem database architectures with ClusterControl </h3> </a> </div> </div> </div> </div> <div class="box post"> <div class="box-content"> <div class="image-wrapper"> <a href="https://severalnines.com/blog/a-true-alternative-to-elastic-cloud-for-elasticsearch-ops-automation/" title="A true alternative to Elastic Cloud for Elasticsearch ops automation"> <picture><source data-lazy-srcset="https://severalnines.com/wp-content/webp-express/webp-images/uploads/2022/05/husna-miskandar-FC4z3l4sUYc-unsplash-600x340.png.webp" type="image/webp"><img width="600" height="340" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20340'%3E%3C/svg%3E" class="attachment-archive size-archive wp-post-image webpexpress-processed" alt="" loading="lazy" data-lazy-src="https://severalnines.com/wp-content/uploads/2022/05/husna-miskandar-FC4z3l4sUYc-unsplash-600x340.png"><noscript><img width="600" height="340" src="https://severalnines.com/wp-content/uploads/2022/05/husna-miskandar-FC4z3l4sUYc-unsplash-600x340.png" class="attachment-archive size-archive wp-post-image webpexpress-processed" alt="" loading="lazy"></noscript></picture> </a> </div> <div class="text-area"> <div class="taxonomy-meta"> <a class="related-product" href="https://severalnines.com/related-product/clustercontrol/"> <img width="40" height="40" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2040%2040'%3E%3C/svg%3E" alt="clustercontrol" data-lazy-src="https://severalnines.com/wp-content/themes/severalnines/assets/img/acf/clustercontrol.svg"><noscript><img width="40" height="40" src="https://severalnines.com/wp-content/themes/severalnines/assets/img/acf/clustercontrol.svg" alt="clustercontrol"></noscript> </a> </div> <div class="meta-content"> <span class="date">May 19, 2022</span> <span class="author">Sarah Morris</span> </div> <div class="content-wrapper"> <a href="https://severalnines.com/blog/a-true-alternative-to-elastic-cloud-for-elasticsearch-ops-automation/" title="A true alternative to Elastic Cloud for Elasticsearch ops automation"> <h3 class="archive-title"> A true alternative to Elastic Cloud for Elasticsearch ops automation </h3> </a> </div> </div> </div> </div> </div> </div> </div> </div> </section> <section class="cover-with-text-box subscribe"> <div data-bg="https://severalnines.com/wp-content/uploads/2021/09/ilya-pavlov-wbXdGS_D17U-unsplash.png" class="background rocket-lazyload" style=""> <div class="container"> <div class="text-box"> <h3>Subscribe to get our best and freshest content</h3> <script type="rocketlazyloadscript" data-rocket-type="text/javascript">var gform;gform||(document.addEventListener("gform_main_scripts_loaded",function(){gform.scriptsLoaded=!0}),window.addEventListener("DOMContentLoaded",function(){gform.domLoaded=!0}),gform={domLoaded:!1,scriptsLoaded:!1,initializeOnLoaded:function(o){gform.domLoaded&&gform.scriptsLoaded?o():!gform.domLoaded&&gform.scriptsLoaded?window.addEventListener("DOMContentLoaded",o):document.addEventListener("gform_main_scripts_loaded",o)},hooks:{action:{},filter:{}},addAction:function(o,n,r,t){gform.addHook("action",o,n,r,t)},addFilter:function(o,n,r,t){gform.addHook("filter",o,n,r,t)},doAction:function(o){gform.doHook("action",o,arguments)},applyFilters:function(o){return gform.doHook("filter",o,arguments)},removeAction:function(o,n){gform.removeHook("action",o,n)},removeFilter:function(o,n,r){gform.removeHook("filter",o,n,r)},addHook:function(o,n,r,t,i){null==gform.hooks[o][n]&&(gform.hooks[o][n]=[]);var e=gform.hooks[o][n];null==i&&(i=n+"_"+e.length),gform.hooks[o][n].push({tag:i,callable:r,priority:t=null==t?10:t})},doHook:function(n,o,r){var t;if(r=Array.prototype.slice.call(r,1),null!=gform.hooks[n][o]&&((o=gform.hooks[n][o]).sort(function(o,n){return o.priority-n.priority}),o.forEach(function(o){"function"!=typeof(t=o.callable)&&(t=window[t]),"action"==n?t.apply(null,r):r[0]=t.apply(null,r)})),"filter"==n)return r[0]},removeHook:function(o,n,t,i){var r;null!=gform.hooks[o][n]&&(r=(r=gform.hooks[o][n]).filter(function(o,n,r){return!!(null!=i&&i!=o.tag||null!=t&&t!=o.priority)}),gform.hooks[o][n]=r)}});</script> <div class='gf_browser_unknown gform_wrapper gravity-theme' id='gform_wrapper_10' > <div class='gform_heading'> <span class='gform_description'>Newsletter Subscription</span> </div><form method='post' enctype='multipart/form-data' id='gform_10' action='/blog/clustercontrol-devstudio-using-advisor-create-checks-selinux-meltdown-spectre-part-2/' > <div class='gform_body gform-body'><div id='gform_fields_10' class='gform_fields top_label form_sublabel_below description_below'><div id="field_10_1" class="gfield gfield--width-full field_sublabel_below field_description_below hidden_label gfield_visibility_visible" data-js-reload="field_10_1"><label class='gfield_label' for='input_10_1' >Email</label><div class='ginput_container ginput_container_email'> <input name='input_1' id='input_10_1' type='text' value='' class='large' placeholder='Email' aria-invalid="false" /> </div></div><div id="field_10_3" class="gfield gfield--width-full field_sublabel_below field_description_below gfield_visibility_hidden" data-js-reload="field_10_3"><div class='admin-hidden-markup'><i class='gform-icon gform-icon--hidden'></i><span>Hidden</span></div><label class='gfield_label' for='input_10_3' >State</label><div class='ginput_container ginput_container_text'><input name='input_3' id='input_10_3' type='text' value='' class='large' aria-invalid="false" /> </div></div><div id="field_10_2" class="gfield gfield--width-full gform_hidden field_sublabel_below field_description_below gfield_visibility_visible" data-js-reload="field_10_2"><div class='ginput_container ginput_container_text'><input name='input_2' id='input_10_2' type='hidden' class='gform_hidden' aria-invalid="false" value='' /></div></div><div id="field_10_4" class="gfield field_sublabel_below field_description_below hidden_label gfield_visibility_visible" data-js-reload="field_10_4"><label class='gfield_label' for='input_10_4' >CAPTCHA</label><div id='input_10_4' class='ginput_container ginput_recaptcha' data-sitekey='6LeVGEAUAAAAANOt9l9-3MmtL4uormHOIttoKf_O' data-theme='light' data-tabindex='0' data-badge=''></div></div></div></div> <div class='gform_footer top_label'> <input type='submit' id='gform_submit_button_10' class='gform_button button' value='Subscribe' onclick='if(window["gf_submitting_10"]){return false;} window["gf_submitting_10"]=true; ' onkeypress='if( event.keyCode == 13 ){ if(window["gf_submitting_10"]){return false;} window["gf_submitting_10"]=true; jQuery("#gform_10").trigger("submit",[true]); }' /> <input type='hidden' class='gform_hidden' name='is_submit_10' value='1' /> <input type='hidden' class='gform_hidden' name='gform_submit' value='10' /> <input type='hidden' class='gform_hidden' name='gform_unique_id' value='' /> <input type='hidden' class='gform_hidden' name='state_10' value='WyJbXSIsIjk1OWIxODI3MGFjMmFlNzNjMGFjYWQwNDE1NzBkOTczIl0=' /> <input type='hidden' class='gform_hidden' name='gform_target_page_number_10' id='gform_target_page_number_10' value='0' /> <input type='hidden' class='gform_hidden' name='gform_source_page_number_10' id='gform_source_page_number_10' value='1' /> <input type='hidden' name='gform_field_values' value='' /> </div> </form> </div> <p class="small-grey"></p> </div> </div> </div> </section> </div><!-- .entry-content --> </article><!-- #post-13173 --> </main><!-- #main --> <footer class="site-footer"> <div class="wrapper-mid"> <div class="wrapper"> <div class="site-footer__mid"> <div class="column logo socialmedia"> <a class="logo" href="https://severalnines.com"> <img width="112" height="24" class="lazyloaded" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20112%2024'%3E%3C/svg%3E" alt="severalnines white logo" data-lazy-src="https://severalnines.com/wp-content/themes/severalnines/assets/img/seve9-logo-white.svg"><noscript><img width="112" height="24" class="lazyloaded" src="https://severalnines.com/wp-content/themes/severalnines/assets/img/seve9-logo-white.svg" alt="severalnines white logo"></noscript> </a> <ul class="severalnines-socialmedia"> <li> <a target="_blank" class="icon-Twitter" href="https://twitter.com/severalnines/" target="_self" title="Twitter"> <span class="screen-reader-text">Twitter</span> </a> </li> <li> <a target="_blank" class="icon-Facebook" href="https://www.facebook.com/severalnines/" target="_self" title="Facebook"> <span class="screen-reader-text">Facebook</span> </a> </li> <li> <a target="_blank" class="icon-Linkedin" href="https://www.linkedin.com/company/severalnines/" target="_self" title="Linkedin"> <span class="screen-reader-text">Linkedin</span> </a> </li> <li> <a target="_blank" class="icon-Youtube" href="http://www.youtube.com/c/Severalnines/" target="_self" title="Youtube"> <span class="screen-reader-text">Youtube</span> </a> </li> <li> <a target="_blank" class="icon-Slideshare" href="https://www.slideshare.net/severalnines/" target="_self" title="Slideshare"> <span class="screen-reader-text">Slideshare</span> </a> </li> <li> <a target="_blank" class="icon-RSS" href="https://severalnines.com/feed" target="_self" title="RSS"> <span class="screen-reader-text">RSS</span> </a> </li> </ul> </div> <div class="column footer-menu"> <ul id="menu-footer" class="menu-footer"><li id="menu-item-1117" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-1117"><a>Products</a> <ul class="sub-menu"> <li id="menu-item-1112" class="menu-item menu-item-type-post_type menu-item-object-product menu-item-1112"><a href="https://severalnines.com/clustercontrol/">CC</a></li> <li id="menu-item-1115" class="menu-item menu-item-type-post_type menu-item-object-product menu-item-1115"><a href="https://severalnines.com/ccx/">CCX</a></li> <li id="menu-item-1452" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-1452"><a href="https://backup.ninja">Backup Ninja</a></li> </ul> </li> <li id="menu-item-24957" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-24957"><a>CC</a> <ul class="sub-menu"> <li id="menu-item-24923" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-24923"><a href="/clustercontrol/databases/mysql/">MySQL</a></li> <li id="menu-item-24924" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-24924"><a href="/clustercontrol/databases/mariadb/">MariaDB</a></li> <li id="menu-item-24925" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-24925"><a href="/clustercontrol/databases/mongodb/">MongoDB</a></li> <li id="menu-item-24926" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-24926"><a href="/clustercontrol/databases/postgresql/">PostgreSQL</a></li> <li id="menu-item-24927" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-24927"><a href="/clustercontrol/databases/mysql-ndb-cluster/">MySQL NDB</a></li> <li id="menu-item-24928" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-24928"><a href="/clustercontrol/databases/timescaledb/">TimescaleDB</a></li> <li id="menu-item-24929" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-24929"><a href="/clustercontrol/databases/mysql-galera-cluster/">MySQL Galera</a></li> </ul> </li> <li id="menu-item-24930" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-24930"><a>Solutions</a> <ul class="sub-menu"> <li id="menu-item-24931" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-24931"><a href="/clustercontrol/solutions/multi-cloud/">Multi cloud</a></li> <li id="menu-item-24932" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-24932"><a href="/clustercontrol/solutions/hybrid-cloud/">Hybrid cloud</a></li> <li id="menu-item-24933" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-24933"><a href="/clustercontrol/solutions/disaster-recovery/">Disaster recovery</a></li> </ul> </li> <li id="menu-item-1444" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-1444"><a>Developers</a> <ul class="sub-menu"> <li id="menu-item-1445" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-1445"><a href="https://docs.severalnines.com/">Docs</a></li> <li id="menu-item-1436" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-1436"><a href="https://severalnines.com/support/">Support</a></li> <li id="menu-item-1451" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-1451"><a href="https://join.slack.com/t/clustercontrol/shared_invite/zt-b15k9477-jLllD6qJOUm3bGnOWynVig">S9S slack</a></li> <li id="menu-item-1447" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-1447"><a href="/clustercontrol/training/">CC Training</a></li> <li id="menu-item-1449" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-1449"><a href="/clustercontrol/certification/">CC Certification</a></li> </ul> </li> <li id="menu-item-24934" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-24934"><a>Corporate</a> <ul class="sub-menu"> <li id="menu-item-23354" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-23354"><a href="https://severalnines.com/about-us/">About us</a></li> <li id="menu-item-23073" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-23073"><a href="https://severalnines.com/contact/">Contact</a></li> <li id="menu-item-24935" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-24935"><a href="https://severalnines.com/career/">Careers</a></li> <li id="menu-item-23835" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-23835"><a href="https://severalnines.com/partners/">Partners</a></li> </ul> </li> </ul> </div> <div class="column subscribe"> <h3>The Planet9s newsletter</h3> <p>Join for inspiration, news about database stuff, this, that and more.</p> <div class="iframe-wrapper"> <div class='gf_browser_unknown gform_wrapper gravity-theme' id='gform_wrapper_1' > <div class='gform_heading'> <span class='gform_description'>Newsletter Subscription</span> </div><form method='post' enctype='multipart/form-data' id='gform_1' action='/blog/clustercontrol-devstudio-using-advisor-create-checks-selinux-meltdown-spectre-part-2/' > <div class='gform_body gform-body'><div id='gform_fields_1' class='gform_fields top_label form_sublabel_below description_below'><div id="field_1_1" class="gfield gfield--width-full field_sublabel_below field_description_below hidden_label gfield_visibility_visible" data-js-reload="field_1_1"><label class='gfield_label' for='input_1_1' >Email</label><div class='ginput_container ginput_container_email'> <input name='input_1' id='input_1_1' type='text' value='' class='large' placeholder='Email' aria-invalid="false" /> </div></div><div id="field_1_3" class="gfield gfield--width-full field_sublabel_below field_description_below gfield_visibility_hidden" data-js-reload="field_1_3"><div class='admin-hidden-markup'><i class='gform-icon gform-icon--hidden'></i><span>Hidden</span></div><label class='gfield_label' for='input_1_3' >State</label><div class='ginput_container ginput_container_text'><input name='input_3' id='input_1_3' type='text' value='' class='large' aria-invalid="false" /> </div></div><div id="field_1_2" class="gfield gfield--width-full gform_hidden field_sublabel_below field_description_below gfield_visibility_visible" data-js-reload="field_1_2"><div class='ginput_container ginput_container_text'><input name='input_2' id='input_1_2' type='hidden' class='gform_hidden' aria-invalid="false" value='' /></div></div><div id="field_1_4" class="gfield field_sublabel_below field_description_below hidden_label gfield_visibility_visible" data-js-reload="field_1_4"><label class='gfield_label' for='input_1_4' >CAPTCHA</label><div id='input_1_4' class='ginput_container ginput_recaptcha' data-sitekey='6LeVGEAUAAAAANOt9l9-3MmtL4uormHOIttoKf_O' data-theme='light' data-tabindex='0' data-badge=''></div></div></div></div> <div class='gform_footer top_label'> <input type='submit' id='gform_submit_button_1' class='gform_button button' value='Subscribe' onclick='if(window["gf_submitting_1"]){return false;} window["gf_submitting_1"]=true; ' onkeypress='if( event.keyCode == 13 ){ if(window["gf_submitting_1"]){return false;} window["gf_submitting_1"]=true; jQuery("#gform_1").trigger("submit",[true]); }' /> <input type='hidden' class='gform_hidden' name='is_submit_1' value='1' /> <input type='hidden' class='gform_hidden' name='gform_submit' value='1' /> <input type='hidden' class='gform_hidden' name='gform_unique_id' value='' /> <input type='hidden' class='gform_hidden' name='state_1' value='WyJbXSIsIjk1OWIxODI3MGFjMmFlNzNjMGFjYWQwNDE1NzBkOTczIl0=' /> <input type='hidden' class='gform_hidden' name='gform_target_page_number_1' id='gform_target_page_number_1' value='0' /> <input type='hidden' class='gform_hidden' name='gform_source_page_number_1' id='gform_source_page_number_1' value='1' /> <input type='hidden' name='gform_field_values' value='' /> </div> </form> </div> </div> </div> </div> </div> </div> <div class="wrapper-bottom"> <div class="wrapper"> <div class="site-footer__bottom"> <ul class="severalnines-socialmedia"> <li> <a target="_blank" class="icon-Twitter" href="https://twitter.com/severalnines/" target="_self" title="Twitter"> <span class="screen-reader-text">Twitter</span> </a> </li> <li> <a target="_blank" class="icon-Facebook" href="https://www.facebook.com/severalnines/" target="_self" title="Facebook"> <span class="screen-reader-text">Facebook</span> </a> </li> <li> <a target="_blank" class="icon-Linkedin" href="https://www.linkedin.com/company/severalnines/" target="_self" title="Linkedin"> <span class="screen-reader-text">Linkedin</span> </a> </li> <li> <a target="_blank" class="icon-Youtube" href="http://www.youtube.com/c/Severalnines/" target="_self" title="Youtube"> <span class="screen-reader-text">Youtube</span> </a> </li> <li> <a target="_blank" class="icon-Slideshare" href="https://www.slideshare.net/severalnines/" target="_self" title="Slideshare"> <span class="screen-reader-text">Slideshare</span> </a> </li> <li> <a target="_blank" class="icon-RSS" href="https://severalnines.com/feed" target="_self" title="RSS"> <span class="screen-reader-text">RSS</span> </a> </li> </ul> <div class="site-footer__copyright bottom-left"> </div> <div class="site-footer__mandatory-links bottom-right"> <ul class="mandatory-links"> <li><a href="https://severalnines.com/privacy/" target="_self" title="Privacy Policy">Privacy Policy</a> </li> <li><a href="https://severalnines.com/ccx/terms/" target="_self" title="Terms and Conditions">Terms and Conditions</a> </li> </ul> </div> </div> </div> </div> </footer> </div> <!-- Zopim chat bot code --> <script type="rocketlazyloadscript" data-rocket-type="text/javascript"> window.$zopim||(function(d,s){var z=$zopim=function(c){z._.push(c)},$=z.s= d.createElement(s),e=d.getElementsByTagName(s)[0];z.set=function(o){z.set. _.push(o)};z._=[];z.set._=[];$.async=!0;$.setAttribute("charset","utf-8"); $.src="//v2.zopim.com/?3P2DzaW6KX6JrCYBbnEAaeOa2IVmBM5T";z.t=+new Date;$. type="text/javascript";e.parentNode.insertBefore($,e)})(document,"script"); </script> <!-- scrolling functionality for when hash clicked/ hash for another page form --> <script type="rocketlazyloadscript" data-rocket-type="text/javascript">window.addEventListener('DOMContentLoaded', function() { jQuery(document).ready(function(){ jQuery(".acf-button-block a").on('click', function(event) { if ((this.hash !== "" && this.hash == this.href) || this.hash == '#gform_wrapper_7') { event.preventDefault(); var hash = this.hash; jQuery('html, body').animate({ scrollTop: jQuery(hash).offset().top-200 }, 0, function(){ window.location.hash = hash; }); } }); setTimeout(() => { id = window.location.hash; if ( jQuery(id).length > 0 ) { jQuery('html, body').animate({ scrollTop: jQuery(id).offset().top-180 }, 0, function(){ window.location.hash = id; }); } }, 100); }); });</script> <script type="rocketlazyloadscript" id='rocket-browser-checker-js-after'> "use strict";var _createClass=function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||!1,descriptor.configurable=!0,"value"in descriptor&&(descriptor.writable=!0),Object.defineProperty(target,descriptor.key,descriptor)}}return function(Constructor,protoProps,staticProps){return protoProps&&defineProperties(Constructor.prototype,protoProps),staticProps&&defineProperties(Constructor,staticProps),Constructor}}();function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor))throw new TypeError("Cannot call a class as a function")}var RocketBrowserCompatibilityChecker=function(){function RocketBrowserCompatibilityChecker(options){_classCallCheck(this,RocketBrowserCompatibilityChecker),this.passiveSupported=!1,this._checkPassiveOption(this),this.options=!!this.passiveSupported&&options}return _createClass(RocketBrowserCompatibilityChecker,[{key:"_checkPassiveOption",value:function(self){try{var options={get passive(){return!(self.passiveSupported=!0)}};window.addEventListener("test",null,options),window.removeEventListener("test",null,options)}catch(err){self.passiveSupported=!1}}},{key:"initRequestIdleCallback",value:function(){!1 in window&&(window.requestIdleCallback=function(cb){var start=Date.now();return setTimeout(function(){cb({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-start))}})},1)}),!1 in window&&(window.cancelIdleCallback=function(id){return clearTimeout(id)})}},{key:"isDataSaverModeOn",value:function(){return"connection"in navigator&&!0===navigator.connection.saveData}},{key:"supportsLinkPrefetch",value:function(){var elem=document.createElement("link");return elem.relList&&elem.relList.supports&&elem.relList.supports("prefetch")&&window.IntersectionObserver&&"isIntersecting"in IntersectionObserverEntry.prototype}},{key:"isSlowConnection",value:function(){return"connection"in navigator&&"effectiveType"in navigator.connection&&("2g"===navigator.connection.effectiveType||"slow-2g"===navigator.connection.effectiveType)}}]),RocketBrowserCompatibilityChecker}(); </script> <script id='rocket-preload-links-js-extra'> var RocketPreloadLinksConfig = {"excludeUris":"\/(?:.+\/)?feed(?:\/(?:.+\/?)?)?$|\/(?:.+\/)?embed\/|\/(index\\.php\/)?wp\\-json(\/.*|$)|\/refer\/|\/go\/|\/recommend\/|\/recommends\/","usesTrailingSlash":"1","imageExt":"jpg|jpeg|gif|png|tiff|bmp|webp|avif|pdf|doc|docx|xls|xlsx|php","fileExt":"jpg|jpeg|gif|png|tiff|bmp|webp|avif|pdf|doc|docx|xls|xlsx|php|html|htm","siteUrl":"https:\/\/severalnines.com","onHoverDelay":"100","rateThrottle":"3"}; </script> <script type="rocketlazyloadscript" id='rocket-preload-links-js-after'> (function() { "use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e=function(){function i(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(e,t,n){return t&&i(e.prototype,t),n&&i(e,n),e}}();function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var t=function(){function n(e,t){i(this,n),this.browser=e,this.config=t,this.options=this.browser.options,this.prefetched=new Set,this.eventTime=null,this.threshold=1111,this.numOnHover=0}return e(n,[{key:"init",value:function(){!this.browser.supportsLinkPrefetch()||this.browser.isDataSaverModeOn()||this.browser.isSlowConnection()||(this.regex={excludeUris:RegExp(this.config.excludeUris,"i"),images:RegExp(".("+this.config.imageExt+")$","i"),fileExt:RegExp(".("+this.config.fileExt+")$","i")},this._initListeners(this))}},{key:"_initListeners",value:function(e){-1<this.config.onHoverDelay&&document.addEventListener("mouseover",e.listener.bind(e),e.listenerOptions),document.addEventListener("mousedown",e.listener.bind(e),e.listenerOptions),document.addEventListener("touchstart",e.listener.bind(e),e.listenerOptions)}},{key:"listener",value:function(e){var t=e.target.closest("a"),n=this._prepareUrl(t);if(null!==n)switch(e.type){case"mousedown":case"touchstart":this._addPrefetchLink(n);break;case"mouseover":this._earlyPrefetch(t,n,"mouseout")}}},{key:"_earlyPrefetch",value:function(t,e,n){var i=this,r=setTimeout(function(){if(r=null,0===i.numOnHover)setTimeout(function(){return i.numOnHover=0},1e3);else if(i.numOnHover>i.config.rateThrottle)return;i.numOnHover++,i._addPrefetchLink(e)},this.config.onHoverDelay);t.addEventListener(n,function e(){t.removeEventListener(n,e,{passive:!0}),null!==r&&(clearTimeout(r),r=null)},{passive:!0})}},{key:"_addPrefetchLink",value:function(i){return this.prefetched.add(i.href),new Promise(function(e,t){var n=document.createElement("link");n.rel="prefetch",n.href=i.href,n.onload=e,n.onerror=t,document.head.appendChild(n)}).catch(function(){})}},{key:"_prepareUrl",value:function(e){if(null===e||"object"!==(void 0===e?"undefined":r(e))||!1 in e||-1===["http:","https:"].indexOf(e.protocol))return null;var t=e.href.substring(0,this.config.siteUrl.length),n=this._getPathname(e.href,t),i={original:e.href,protocol:e.protocol,origin:t,pathname:n,href:t+n};return this._isLinkOk(i)?i:null}},{key:"_getPathname",value:function(e,t){var n=t?e.substring(this.config.siteUrl.length):e;return n.startsWith("/")||(n="/"+n),this._shouldAddTrailingSlash(n)?n+"/":n}},{key:"_shouldAddTrailingSlash",value:function(e){return this.config.usesTrailingSlash&&!e.endsWith("/")&&!this.regex.fileExt.test(e)}},{key:"_isLinkOk",value:function(e){return null!==e&&"object"===(void 0===e?"undefined":r(e))&&(!this.prefetched.has(e.href)&&e.origin===this.config.siteUrl&&-1===e.href.indexOf("?")&&-1===e.href.indexOf("#")&&!this.regex.excludeUris.test(e.href)&&!this.regex.images.test(e.href))}}],[{key:"run",value:function(){"undefined"!=typeof RocketPreloadLinksConfig&&new n(new RocketBrowserCompatibilityChecker({capture:!0,passive:!0}),RocketPreloadLinksConfig).init()}}]),n}();t.run(); }()); </script> <script type="rocketlazyloadscript" data-minify="1" src='https://severalnines.com/wp-content/cache/min/1/wp-content/themes/severalnines/assets/dist/frontend.js?ver=1660631399' id='cntrst-scripts-js' defer></script> <script type="rocketlazyloadscript" src='https://severalnines.com/wp-includes/js/dist/vendor/regenerator-runtime.min.js?ver=0.13.9' id='regenerator-runtime-js' defer></script> <script type="rocketlazyloadscript" src='https://severalnines.com/wp-includes/js/dist/vendor/wp-polyfill.min.js?ver=3.15.0' id='wp-polyfill-js'></script> <script type="rocketlazyloadscript" src='https://severalnines.com/wp-includes/js/dist/dom-ready.min.js?ver=d996b53411d1533a84951212ab6ac4ff' id='wp-dom-ready-js' defer></script> <script type="rocketlazyloadscript" src='https://severalnines.com/wp-includes/js/dist/hooks.min.js?ver=c6d64f2cb8f5c6bb49caca37f8828ce3' id='wp-hooks-js'></script> <script type="rocketlazyloadscript" src='https://severalnines.com/wp-includes/js/dist/i18n.min.js?ver=ebee46757c6a411e38fd079a7ac71d94' id='wp-i18n-js'></script> <script type="rocketlazyloadscript" id='wp-i18n-js-after'> wp.i18n.setLocaleData( { 'text direction\u0004ltr': [ 'ltr' ] } ); </script> <script type="rocketlazyloadscript" src='https://severalnines.com/wp-includes/js/dist/a11y.min.js?ver=a38319d7ba46c6e60f7f9d4c371222c5' id='wp-a11y-js' defer></script> <script type="rocketlazyloadscript" defer='defer' src='https://severalnines.com/wp-content/plugins/gravityforms/js/jquery.json.min.js?ver=2.6.4' id='gform_json-js'></script> <script id='gform_gravityforms-js-extra'> var gform_i18n = {"datepicker":{"days":{"monday":"Mon","tuesday":"Tue","wednesday":"Wed","thursday":"Thu","friday":"Fri","saturday":"Sat","sunday":"Sun"},"months":{"january":"January","february":"February","march":"March","april":"April","may":"May","june":"June","july":"July","august":"August","september":"September","october":"October","november":"November","december":"December"},"firstDay":1,"iconText":"Select date"}}; var gf_legacy_multi = []; var gform_gravityforms = {"strings":{"invalid_file_extension":"This type of file is not allowed. Must be one of the following:","delete_file":"Delete this file","in_progress":"in progress","file_exceeds_limit":"File exceeds size limit","illegal_extension":"This type of file is not allowed.","max_reached":"Maximum number of files reached","unknown_error":"There was a problem while saving the file on the server","currently_uploading":"Please wait for the uploading to complete","cancel":"Cancel","cancel_upload":"Cancel this upload","cancelled":"Cancelled"},"vars":{"images_url":"https:\/\/severalnines.com\/wp-content\/plugins\/gravityforms\/images"}}; var gf_global = {"gf_currency_config":{"name":"U.S. Dollar","symbol_left":"$","symbol_right":"","symbol_padding":"","thousand_separator":",","decimal_separator":".","decimals":2,"code":"USD"},"base_url":"https:\/\/severalnines.com\/wp-content\/plugins\/gravityforms","number_formats":[],"spinnerUrl":"https:\/\/severalnines.com\/wp-content\/plugins\/gravityforms\/images\/spinner.svg","strings":{"newRowAdded":"New row added.","rowRemoved":"Row removed","formSaved":"The form has been saved. The content contains the link to return and complete the form."}}; var gf_global = {"gf_currency_config":{"name":"U.S. Dollar","symbol_left":"$","symbol_right":"","symbol_padding":"","thousand_separator":",","decimal_separator":".","decimals":2,"code":"USD"},"base_url":"https:\/\/severalnines.com\/wp-content\/plugins\/gravityforms","number_formats":[],"spinnerUrl":"https:\/\/severalnines.com\/wp-content\/plugins\/gravityforms\/images\/spinner.svg","strings":{"newRowAdded":"New row added.","rowRemoved":"Row removed","formSaved":"The form has been saved. The content contains the link to return and complete the form."}}; </script> <script type="rocketlazyloadscript" defer='defer' src='https://severalnines.com/wp-content/plugins/gravityforms/js/gravityforms.min.js?ver=2.6.4' id='gform_gravityforms-js'></script> <script type="rocketlazyloadscript" defer='defer' src='https://www.google.com/recaptcha/api.js?hl=en&ver=6.0#038;render=explicit' id='gform_recaptcha-js'></script> <script type="rocketlazyloadscript" defer='defer' src='https://severalnines.com/wp-content/plugins/gravityforms/js/placeholders.jquery.min.js?ver=2.6.4' id='gform_placeholder-js'></script> <script type="rocketlazyloadscript">window.addEventListener('DOMContentLoaded', function() { gform.initializeOnLoaded( function() { jQuery(document).on('gform_post_render', function(event, formId, currentPage){if(formId == 10) {if(typeof Placeholders != 'undefined'){ Placeholders.enable(); }} } );jQuery(document).bind('gform_post_conditional_logic', function(event, formId, fields, isInit){} ) } ); });</script> <script type="rocketlazyloadscript">window.addEventListener('DOMContentLoaded', function() { gform.initializeOnLoaded( function() { jQuery(document).trigger('gform_post_render', [10, 1]) } ); });</script> <script type="rocketlazyloadscript">window.addEventListener('DOMContentLoaded', function() { gform.initializeOnLoaded( function() { jQuery(document).on('gform_post_render', function(event, formId, currentPage){if(formId == 1) {if(typeof Placeholders != 'undefined'){ Placeholders.enable(); }} } );jQuery(document).bind('gform_post_conditional_logic', function(event, formId, fields, isInit){} ) } ); });</script> <script type="rocketlazyloadscript">window.addEventListener('DOMContentLoaded', function() { gform.initializeOnLoaded( function() { jQuery(document).trigger('gform_post_render', [1, 1]) } ); });</script> <script>window.lazyLoadOptions=[{elements_selector:"img[data-lazy-src],.rocket-lazyload,iframe[data-lazy-src]",data_src:"lazy-src",data_srcset:"lazy-srcset",data_sizes:"lazy-sizes",class_loading:"lazyloading",class_loaded:"lazyloaded",threshold:300,callback_loaded:function(element){if(element.tagName==="IFRAME"&&element.dataset.rocketLazyload=="fitvidscompatible"){if(element.classList.contains("lazyloaded")){if(typeof window.jQuery!="undefined"){if(jQuery.fn.fitVids){jQuery(element).parent().fitVids()}}}}}},{elements_selector:".rocket-lazyload",data_src:"lazy-src",data_srcset:"lazy-srcset",data_sizes:"lazy-sizes",class_loading:"lazyloading",class_loaded:"lazyloaded",threshold:300,}];window.addEventListener('LazyLoad::Initialized',function(e){var lazyLoadInstance=e.detail.instance;if(window.MutationObserver){var observer=new MutationObserver(function(mutations){var image_count=0;var iframe_count=0;var rocketlazy_count=0;mutations.forEach(function(mutation){for(var i=0;i<mutation.addedNodes.length;i++){if(typeof mutation.addedNodes[i].getElementsByTagName!=='function'){continue} if(typeof mutation.addedNodes[i].getElementsByClassName!=='function'){continue} images=mutation.addedNodes[i].getElementsByTagName('img');is_image=mutation.addedNodes[i].tagName=="IMG";iframes=mutation.addedNodes[i].getElementsByTagName('iframe');is_iframe=mutation.addedNodes[i].tagName=="IFRAME";rocket_lazy=mutation.addedNodes[i].getElementsByClassName('rocket-lazyload');image_count+=images.length;iframe_count+=iframes.length;rocketlazy_count+=rocket_lazy.length;if(is_image){image_count+=1} if(is_iframe){iframe_count+=1}}});if(image_count>0||iframe_count>0||rocketlazy_count>0){lazyLoadInstance.update()}});var b=document.getElementsByTagName("body")[0];var config={childList:!0,subtree:!0};observer.observe(b,config)}},!1)</script><script data-no-minify="1" async src="https://severalnines.com/wp-content/plugins/wp-rocket/assets/js/lazyload/17.5/lazyload.min.js"></script><!-- The Modal --> <div id="s9s_modal" class="modal image_lightbox_popup"> <span id="s9s_modal-close" class="modal-close">×</span> <img id="s9s_modal-content" class="modal-content"> </div> </body> </html> <!-- This website is like a Rocket, isn't it? Performance optimized by WP Rocket. Learn more: https://wp-rocket.me -->