Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7019 Articles
article-image-trunks-using-3cx-part-2
Packt
12 Feb 2010
7 min read
Save for later

Trunks using 3CX: Part 2

Packt
12 Feb 2010
7 min read
The next wizard screen is for Outbound Call Rules. Let's go over it enough so that you can setup a simple rule. We start off with a name. This can be anything you like but I prefer something meaningful. For our example I want to dial 9 to use the analog line, and only allow extensions 100-102 to use this line. I also only want to be able to dial certain phone numbers. Then I have to delete the 9 before it goes out to the phone carrier. Let's have a look at each section of this screen: Calls to numbers starting with (Prefix) This is where you specify what you want someone to dial before the line is used. You could enter a string of numbers here to use as a "password" to dial out. You don't just let anyone call an international phone number, so set this to a string of numbers to use as your international password. Give the password only to those who need it. Just make sure you change it occasionally in case it slips out. Calls from extension(s) Now, you can specify who (by extension number) can use this gateway. Just enter the extension number(s) you want to allow either in a range (100-110), individually (100, 101, 104), or as a mix (100-103, 110). Usually, you will leave this open for everyone to use; otherwise, you will restrict extensions that were allowed to use the gateway, which will have repercussions of forwarding rules to external numbers. Calls to numbers with a length of This setting can be left blank if you want all calls to be able to go out on this gateway. In the next screenshot, I specified 3, 7, 10, and 11. This covers calls to 911, 411, 555-1234, 800-555-1234, and 1-800-555-1234, respectively. You can control what phone numbers go out based on the number of digits that are dialed. Route and strip options Since this is our only gateway right now, we will have it route the calls to the Patton gateway. The Strip Digits option needs to be set to 1. This will strip out the "9" that we specified above to dial out with. We can leave the Prepend section blank for now. Now, go ahead and click Finish: Once you click Finish, you will see a gateway wizard summary, as shown in the next screenshot. This shows you that the gateway is created, and it also gives an overview of the settings. Your next step is to get those settings configured on your gateway. There is a list of links for various supported gateways on the bottom of the summary page with up-to-date instructions. Feel free to visit those links. These links will take you to the 3CX website and explain how to configure that particular gateway. With Patton this is easy; click the Generate config file button. The only other information you need for the configuration file is the Subnet mask for the Patton gateway. Enter your network subnet mask in the box. Here, I entered a standard Class C subnet mask. This matches my 192.168.X.X network. Click OK when you are done: Once you click OK, your browser will prompt you to save the file, as shown in the following screenshot. Click Save: The following screenshot shows a familiar Save As Windows screen. I like to put this file in an easy-to-remember location on my hard drive. As I already have a 3CX folder created, I'm going to save the file there. You can change the name of the file if you wish. Click Save: Now that your file is saved, let's take a look at modifying those settings. Open the administration web interface and, on the left-hand side, click PSTN Devices. Go ahead and expand this by clicking the + sign next to it. Now, you will see our newly created Patton SN4114A gateway listed. Click the + sign again and expand that gateway. Next, click the Patton SN4114A name, and you will see the right-hand side window pane fill up with five separate tabs. The first tab is General. This is where you can change the gateway IP address, SIP port, and all the account details. If you change anything, you will need a new configuration file. So click the Generate config file button at the bottom of the screen. If you forgot to save the file previously, here's your chance to generate and save it again: On the Advanced tab, we have some Provider Capabilities. Leave these settings alone for now: We will leave the rest of the tabs for now. Go ahead and click the 10000 line information in the navigation pane on the left. These are the settings for that particular phone port (10000). The first group of settings that we can change is the authentication username and password. Remember, this is to register the line with 3CX and not to use the phone line. The next two sections are about what to do with an inbound call during Office Hours and Outside Office Hours. I didn't change anything from the gateway wizard but, on this screen, you can see that we selected Ring group 800 MainRingGroup. This is the Ring group that we configured previously. We also see similar drop-down boxes for Outside Office Hours. As no one will be in the office to answer the phone, I've selected a Digital Receptionist 801 DR1. In the section Other Options, the Outbound Caller ID box is used to enter what you would like to have presented to the outside world as caller ID information. If your phone carrier supports this, you can enter a phone number or a name. If the carrier does not support this, just leave it blank and talk to your carrier as to what you would require to have it assigned as your caller ID. The Allow outbound calls on this line and Allow incoming calls on this line checkboxes are used to limit calls in or out. Depending on your environment, you might want to leave one line selected as no outbound calls. This will always leave an incoming line for customers to call. Otherwise, unless you have other lines that they can call on, they will get a busy signal. Maximum simultaneous calls cannot be changed here as analog lines only support one call at a time. If you changed anything, click Apply and then go back and generate a new configuration file: For the most up-to-date information on configuring your gateway, visit the 3CX site: http://www.3cx.com/voip-gateways/index.html We will go over a summary of it here: Since nothing was changed, it is now time to configure the Patton device with the config file that we generated from the 3CX template. If you know the IP address of the device, go ahead and open a browser and navigate to that IP address. Mine would be http://192.168.2.10. If you do not know the IP address of your device, you will need the SmartNode discovery tool. The easiest place to get this tool is the CD that came with the device. You can also download it from http://www.3cx.com/downloads/misc/sndiscovery.zip, or search the Patton website for it. Go ahead and install the SmartNode discovery tool and run it. You will get a screen that tells you all the SmartNodes on your network with their IP address, MAC address, and firmware version. Double-click on the SmartNode to open the web interface in a browser. The default username is administrator, and the password field is left blank. Click Import/Export on the left and Import Configuration on the right. Click Browse to find the configuration file that we generated. Click Import and then Reload to restart the gateway with the new configuration. That's it . We can now get incoming calls and make an outbound call.
Read more
  • 0
  • 0
  • 2986

article-image-xen-virtualization-work-mysql-server-ruby-rails-and-subversion
Packt
22 Oct 2009
7 min read
Save for later

Xen Virtualization: Work with MySQL Server, Ruby on Rails, and Subversion

Packt
22 Oct 2009
7 min read
Base Appliance Image We will use an Ubuntu Feisty domain image as the base image for creating these appliances. This image should be made as sparse and small as possible, and free of any cruft. A completely stripped down version of Linux with only the bare necessities would be a great start. In this case, we will not need any graphical desktop environments, so we can completely eliminate software packages like the X11 and any window manager like Gnome or KDE. Once we have a base image, we can back it up and then start using it for creating Xen appliances. In this article we will use an Ubuntu Feisty domain as the base image. Once this domain image is ready we are going to update it and clean it up a little bit so it can be our base. Edit the sources list for apt and add in other repositories that we will need to get software packages we will need when creating these appliances. Update your list of software. This will connect to the apt repositories and get the latest list of packages. We will do the actual update in the next step. Upgrade the distribution to ensure that you have the latest versions of all the packages. Automatically clean the image so all unused packages are removed. This will ensure that the image stays free of cruft.   Now we have the base appliance image ready, we will use it to create some Xen appliances. You can make a backup of the original base image and every time you create an appliance you can use a copy as the starting point or template. The images are nothing but domU images, which are customized for running only specific applications. You start them up and run them like ay other Xen guest domains. MySQL Database Server MySQL is one of the most popular open-source databases in the world. It is a key component of the LAMP architecture – (Linux Apache MySQL and PHP). It is also very easy to get started with MySQL and is one of the key factors driving its adoption across the enterprise. In this section we will create a Xen appliance that will run a MySQL database server and also provide the ability to automatically backup the database on a given schedule. Time for Action – Create our first Xen appliance We will use our base Ubuntu Feisty domain image, and add MySQL and other needed software to it. Please ensure that you have updated your base image to the latest versions of the repositories and software packages before creating this appliance. Install mysql-server using apt. Once it is installed, Ubuntu will automatically start the database server. So before we make our other changes, stop MySQL. Edit the /etc/mysql/my.cnf and comment out the line for the bind-address parameter. This will ensure that MySQL will accept connections from external machines and not just the localhost. Start a mysql console session to test that everything is installed and working correctly. Next we will install the utility for doing the automated backups. In order to do that we will first need to install the wget utility for transferring files. This is not a part of the base Ubuntu Feisty installation. Download the automysqlbackup script from the website. Copy this script to wherever you like, maybe /opt. Create a link to this location so it’s easy to do future updates. # cp automysqlbackup.sh.2.5 /opt# ln -s automysqlbackup.sh.2.5 automysqlbackup.sh Edit the script and modify the parameters at the top of the script to match your environment. Here are the changes to be made in our case. # Username to access the MySQL server e.g. dbuserUSERNAME=pchaganti# Username to access the MySQL server e.g. passwordPASSWORD=password# Host name (or IP address) of MySQL server e.g localhostDBHOST=localhost# List of DBNAMES for Daily/Weekly Backup e.g. "DB1 DB2 DB3"DBNAMES="all"# Backup directory location e.g /backupsBACKUPDIR="/var/backup/mysql"# Mail setupMAILCONTENT="quiet" Schedule this backup script to be run daily by creating a crontab entry for it, in the following format. 45 5 * * * root  /opt/automysqlbackup.sh >/dev/null 2>&1 Now we have a MySQL database server with automatic daily backups as a nice reusable Xen appliance. What just happened? We created our first Xen appliance! It is running the open-source MySQL database server along with an automated backup of the database as per the given schedule. This image is essentially a domU image and it can be uploaded along with its configuration file to a repository somewhere, and can be used by anyone in the enterprise or elsewhere with their Xen server. You can either start up the domain manually as and when you need it or set it up to boot automatically when your xend server starts. Ruby on Rails Appliance Ruby on Rails is one of the hottest web development frameworks around. It is simple to use and you can use all the expressive power of the Ruby language. It provides a great feature set and has really put the Ruby language on the map. Ruby on Rails is gaining rapid adoption across the IT landscape and for a wide variety of web applications. In this section, we are going to create a Rails appliance that contains Ruby, Rails, and the Mongrel cluster for serving the Rails application and nginx web server for the static content. This appliance gives you a great starting point for your explorations into the world of Ruby on Rails and can be an excellent learning resource. Time for Action – Rails on Xen We will use our base Ubuntu Feisty domain image and add Rails and other needed software to it. Please ensure that you have updated your base image to the latest versions of the repositories and software packages before creating this appliance. Install the packages required for compiling software on an Ubuntu system. This is required as we will be compiling some native extensions. Once the image is done, you can always remove this package if you want to save space. Install Ruby and other packages that are needed for it. Download the RubyGems package from RubyForge. We will use this to install any Ruby libraries or packages that we will need, including Rails. Now install Rails. The first time when you run this command on a clean Ubuntu Feisty system, you will get the following error. Ignore this error and just run the command once again and it will work fine. This will install Rails and all of its dependencies. Create a new Rails application. This will create everything needed in a directory named xenbook. $ rails xenbook  Change into the directory of the application that we created in the previous step and start the server up. This will start Ruby’s built-in web server, webrick by default. Launch a web browser and navigate to the web page for our xenbook application. We have everything working for a simple Rails install. However, we are using webrick, which is a bit slow. So let’s install the Mongrel server and use it with Rails. We will actually install mongrel_cluster that will let us use a cluster of Mongrel processes for serving up our Rails application.
Read more
  • 0
  • 0
  • 2985

article-image-using-jquery-and-jqueryui-widget-factory-plugins-requirejs
Packt
18 Jun 2013
5 min read
Save for later

Using jQuery and jQueryUI Widget Factory plugins with RequireJS

Packt
18 Jun 2013
5 min read
(For more resources related to this topic, see here.) How to do it... We must declare the jquery alias name within our Require.js configuration file. require.config({// 3rd party script alias namespaths: {// Core Libraries// --------------// jQuery"jquery": "libs/jquery",// Plugins// -------"somePlugin": "libs/plugins/somePlugin"}}); If a jQuery plugin does not register itself as AMD compatible, we must also create a Require.js shim configuration to make sure Require.js loads jQuery before the jQuery plugin. shim: {// Twitter Bootstrap plugins depend on jQuery"bootstrap": ["jquery"]} We will now be able to dynamically load a jQuery plugin with the require() method. // Dynamically loads a jQuery plugin using the require() methodrequire(["somePlugin"], function() {// The callback function is executed after the pluginis loaded}); We will also be able to list a jQuery plugin as a dependency to another module. // Sample file// -----------// The define method is passed a dependency array and a callbackfunctiondefine(["jquery", "somePlugin"], function ($) {// Wraps all logic inside of a jQuery.ready event$(function() {});}); When using a jQueryUI Widget Factory plugin, we create Require.js path names for both the jQueryUI Widget Factory and the jQueryUI Widget Factory plugin: "jqueryui": "libs/jqueryui","selectBoxIt": "libs/plugins/selectBoxIt" Next, create a shim configuration property: // The jQueryUI Widget Factory depends on jQuery"jqueryui": ["jquery"],// The selectBoxIt plugin depends on both jQuery and the jQueryUIWidget Factory"selectBoxIt": ["jqueryui"] We will now be able to dynamically load the jQueryUI Widget Factory plugin with the require() method: // Dynamically loads the jQueryUI Widget Factory plugin, selectBoxIt,using the Require() methodrequire(["selectBoxIt"], function() {// The callback function is executed after selectBoxIt.js(and all of its dependencies) have been loaded}); We will also be able to list the jQueryUI Widget Factory plugin as a dependency to another module: // Sample file// -----------// The define method is passed a dependency array and a callbackfunctiondefine(["jquery", "selectBoxIt"], function ($) {// Wraps all logic inside of a jQuery.ready event$(function() {});}); How it works... Luckily for us, jQuery adheres to the AMD specification and registers itself as a named AMD module. If you are confused about how/why they are doing that, let's take a look at the jQuery source: // Expose jQuery as an AMD moduleif ( typeof define === "function" && define.amd && define.amd.jQuery ){define( "jquery", [], function () { return jQuery; } );} jQuery first checks to make sure there is a global define() function available on the page. Next, jQuery checks if the define function has an amd property, which all AMD loaders that adhere to the AMD API should have. Remember that in JavaScript, functions are first class objects, and can contain properties. Finally, jQuery checks to see if the amd property contains a jQuery property, which should only be there for AMD loaders that understand the issues with loading multiple versions of jQuery in a page that all might call the define() function. Essentially, jQuery is checking that an AMD script loader is on the page, and then registering itself as a named AMD module (jquery). Since jQuery exports itself as the named AMD module, jquery, you must use this exact name when setting the path configuration to your own version of jQuery, or Require.js will throw an error. If a jQuery plugin registers itself as an anonymous AMD module and jQuery is also listed with the proper lowercased jquery alias name within your Require.js configuration file, using the plugin with the require() and define() methods will work as you expect. Unfortunately, most jQuery plugins are not AMD compatible, and do not wrap themselves in an optional define() method and list jquery as a dependency. To get around this issue, we can use the Require.js shim object configuration like we have seen before to tell Require. js that a file depends on jQuery. The shim configuration is a great solution for jQuery plugins that do not register themselves as AMD modules. Unfortunately, unlike jQuery, the jQueryUI does not currently register itself as a named AMD module, which means that plugin authors that use the jQueryUI Widget Factory cannot provide AMD compatibility. Since the jQueryUI Widget Factory is not AMD compatible, we must use a workaround involving the paths and shim configuration objects to properly define the plugin as an AMD module. There's more... You will most likely always register your own files as anonymous AMD modules, but jQuery is a special case. Registering itself as a named AMD module allows other third-party libraries that depend on jQuery, such as jQuery plugins, to become AMD compatible by calling the define() method themselves and using the community agreed upon module name, jquery, to list jQuery as a dependency. Summary This article demonstrates how to use jQuery and jQueryUI Widget Factory plugins with Require.js. Resources for Article : Further resources on this subject: So, what is KineticJS? [Article] HTML5 Presentations - creating our initial presentation [Article] Tips & Tricks for Ext JS 3.x [Article]
Read more
  • 0
  • 0
  • 2982

article-image-r-and-its-diverse-possibilities
Packt
16 Dec 2016
11 min read
Save for later

R and its Diverse Possibilities

Packt
16 Dec 2016
11 min read
In this article by Jen Stirrup, the author of the book Advanced Analytics with R and Tableau, We will cover, with examples, the core essentials of R programming such as variables and data structures in R such as matrices, factors, vectors, and data frames. We will also focus on control mechanisms in R ( relational operators, logical operators, conditional statements, loops, functions, and apply) and how to execute these commands in R to get grips before proceeding to article that heavily rely on these concepts for scripting complex analytical operations. (For more resources related to this topic, see here.) Core essentials of R programming One of the reasons for R’s success is its use of variables. Variables are used in all aspects of R programming. For example, variables can hold data, strings to access a database, whole models, queries, and test results. Variables are a key part of the modeling process, and their selection has a fundamental impact on the usefulness of the models. Therefore, variables are an important place to start since they are at the heart of R programming. Variables In the following section we will deal with the variables—how to create variables and working with variables. Creating variables It is very simple to create variables in R, and to save values in them. To create a variable, you simply need to give the variable a name, and assign a value to it. In many other languages, such as SQL, it’s necessary to specify the type of value that the variable will hold. So, for example, if the variable is designed to hold an integer or a string, then this is specified at the point at which the variable is created. Unlike other programming languages, such as SQL, R does not require that you specify the type of the variable before it is created. Instead, R works out the type for itself, by looking at the data that is assigned to the variable. In R, we assign variables using an assignment variable, which is a less than sign (<) followed by a hyphen (-). Put together, the assignment variable looks like so: Working with variables It is important to understand what is contained in the variables. It is easy to check the content of the variables using the lscommand. If you need more details of the variables, then the ls.strcommand will provide you with more information. If you need to remove variables, then you can use the rm function. Data structures in R The power of R resides in its ability to analyze data, and this ability is largely derived from its powerful data types. Fundamentally, R is a vectorized programming language. Data structures in R are constructed from vectors that are foundational. This means that R’s operations are optimized to work with vectors. Vector The vector is a core component of R. It is a fundamental data type. Essentially, a vector is a data structure that contains an array where all of the values are the same type. For example, they could all be strings, or numbers. However, note that vectors cannot contain mixed data types. R uses the c() function to take a list of items and turns them into a vector. Lists R contains two types of lists: a basic list, and a named list. A basic list is created using the list() operator. In a named list, every item in the list has a name as well as a value. named lists are a good mapping structure to help map data between R and Tableau. In R, lists are mapped using the $ operator. Note, however, that the list label operators are case sensitive. Matrices Matrices are two-dimensional structures that have rows and columns. The matrices are lists of rows. It’s important to note that every cell in a matrix has the same type. Factors A factor is a list of all possible values of a variable in a string format. It is a special string type, which is chosen from a specified set of values known as levels. They are sometimes known as categorical variables. In dimensional modeling terminology, a factor is equivalent to a dimension, and the levels represent different attributes of the dimension. Note that factors are variables that can only contain a limited number of different values. Data frames The data frame is the main data structure in R. It’s possible to envisage the data frame as a table of data, with rows and columns. Unlike the list structure, the data frame can contain different types of data. In R, we use the data.frame() command in order to create a data frame. The data frame is extremely flexible for working with structured data, and it can ingest data from many different data types. Two main ways to ingest data into data frames involves the use of many data connectors, which connect to data sources such as databases, for example. There is also a command, read.table(), which takes in data. Data Frame Structure Here is an example, populated data frame. There are three columns, and two rows. The top of the data frame is the header. Each horizontal line afterwards holds a data row. This starts with the name of the row, and then followed by the data itself. Each data member of a row is called a cell. Here is an example data frame, populated with data: Example Data Frame Structure df = data.frame( Year=c(2013, 2013, 2013), Country=c("Arab World","Carribean States", "Central Europe"), LifeExpectancy=c(71, 72, 76)) As always, we should read out at least some of the data frame so we can double-check that it was set correctly. The data frame was set to the df variable, so we can read out the contents by simply typing in the variable name at the command prompt: To obtain the data held in a cell, we enter the row and column co-ordinates of the cell, and surround them by square brackets []. In this example, if we wanted to obtain the value of the second cell in the second row, then we would use the following: df[2, "Country"] We can also conduct summary statistics on our data frame. For example, if we use the following command: summary(df) Then we obtain the summary statistics of the data. The example output is as follows: You’ll notice that the summary command has summarized different values for each of the columns. It has identified Year as an integer, and produced the min, quartiles, mean, and max for year. The Country column has been listed, simply because it does not contain any numeric values. Life Expectancy is summarized correctly. We can change the Year column to a factor, using the following command: df$Year <- as.factor(df$Year) Then, we can rerun the summary command again: summary(df) On this occasion, the data frame now returns the correct results that we expect: As we proceed throughout this book, we will be building on more useful features that will help us to analyze data using data structures, and visualize the data in interesting ways using R. Control structures in R R has the appearance of a procedural programming language. However, it is built on another language, known as S. S leans towards functional programming. It also has some object-oriented characteristics. This means that there are many complexities in the way that R works. In this section, we will look at some of the fundamental building blocks that make up key control structures in R, and then we will move onto looping and vectorized operations. Logical operators Logical operators are binary operators that allow the comparison of values: Operator Description <  less than <= less than or equal to >  greater than >= greater than or equal to == exactly equal to != not equal to !x Not x x | y x OR y x & y x AND y isTRUE(x) test if X is TRUE For loops and vectorization in R Specifically, we will look at the constructs involved in loops. Note, however, that it is more efficient to use vectorized operations rather than loops, because R is vector-based. We investigate loops here, because they are a good first step in understanding how R works, and then we can optimize this understanding by focusing on vectorized alternatives that are more efficient. More information about control flows can be obtained by executing the command at the command line: Help?Control The control flow commands take decisions and make decisions between alternative actions. The main constructs are for, while, and repeat. For loops Let’s look at a for loop in more detail. For this exercise, we will use the Fisher iris dataset, which is installed along with R by default. We are going to produce summary statistics for each species of iris in the dataset. You can see some of the iris data by typing in the following command at the command prompt: head(iris) We can divide the iris dataset so that the data is split by species. To do this, we use the split command, and we assign it to the variable called IrisBySpecies: IrisBySpecies <- split(iris,iris$Species) Now, we can use a for loop in order to process the data in order to summarize it by species. Firstly, we will set up a variable called output, and set it to a list type. For each species held in the IrisBySpecies variable, we set it to calculate the minimum, maximum, mean, and total cases. It is then set to a data frame called output.df, which is printed out to the screen: output <- list() for(n in names(IrisBySpecies)){ ListData <- IrisBySpecies[[n]] output[[n]] <- data.frame(species=n, MinPetalLength=min(ListData$Petal.Length), MaxPetalLength=max(ListData$Petal.Length), MeanPetalLength=mean(ListData$Petal.Length), NumberofSamples=nrow(ListData)) output.df <- do.call(rbind,output) } print(output.df) The output is as follows: We used a for loop here, but they can be expensive in terms of processing. We can achieve the same end by using a function that uses a vector called Tapply. Tapply processes data in groups. Tapply has three parameters; the vector of data, the factor that defines the group, and a function. It works by extracting the group, and then applying the function to each of the groups. Then, it returns a vector with the results. We can see an example of tapply here, using the same dataset: output <- data.frame(MinPetalLength=tapply(iris$Petal.Length,iris$Species,min), MaxPetalLength=tapply(iris$Petal.Length,iris$Species,max), MeanPetalLength=tapply(iris$Petal.Length,iris$Species,mean), NumberofSamples=tapply(iris$Petal.Length,iris$Species,length)) print(output) This time, we get the same output as previously. The only difference is that by using a vectorized function, we have concise code that runs efficiently. To summarize, R is extremely flexible and it’s possible to achieve the same objective in a number of different ways. As we move forward through this book, we will make recommendations about the optimal method to select, and the reasons for the recommendation. Functions R has many functions that are included as part of the installation. In the first instance, let’s look to see how we can work smart by finding out what functions are available by default. In our last example, we used the split() function. To find out more about the split function, we can simply use the following command: ?split Or we can use: help(split) It’s possible to get an overview of the arguments required for a function. To do this, simply use the args command: args(split) Fortunately, it’s also possible to see examples of each function by using the following command: example(split) If you need more information than the documented help file about each function, you can use the following command. It will go and search through all the documentation for instances of the keyword: help.search("split") If you  want to search the R project site from within RStudio, you can use the RSiteSearch command. For example: RSiteSearch("split") Summary In this article, we have looked at various essential structures in working with R. We have looked at the data structures that are fundamental to using R optimally. We have also taken the view that structures such as for loops can often be done better as vectorized operations. Finally, we have looked at the ways in which R can be used to create functions in order to simply code. Resources for Article: Further resources on this subject: Getting Started with Tableau Public [article] Creating your first heat map in R [article] Data Modelling Challenges [article]
Read more
  • 0
  • 0
  • 2982

article-image-building-news-aggregating-site-joomla
Packt
26 May 2010
3 min read
Save for later

Building a News Aggregating Site in Joomla!

Packt
26 May 2010
3 min read
(For more resources on Joomla!, see here.) The completed news aggregation site will look similar to the example shown in the following screenshot: Build Weird Hap'nins Vaughan Pyre is a very ambitious webpreneur. What he really hopes for is a website that is completely self-maintaining, and on which he can place some Google AdSense blocks. Clicks from the visitors to his site will ensure that he makes lots of money. For this, he needs a site where the content updates regularly with fresh content so that visitors will keep coming back to click on some more Google ads. Vaughan's ultimate objective is to create several of these websites. Template The template chosen is Midnight by BuyHTTP, which is a template that fits the theme of this unique website. Extensions This is, surprisingly, a very simple site to build, and much of the requirements can be actually be achieved by using the native News Feeds component. However, the News Feeds component will only list the title links to the external feed items, whereas what Vaughan wants is that the feeds are pulled into the site as articles. Therefore, we will be using an automatic article generator component. There are several of such components on the Joomla! extensions site, but almost all of them are commercial. Vaughan is a skinflint and will not pay to buy any script, so what we are looking for is free component. That is why we have chosen the following: 4RSS—aggregates RSS feeds and creates articles from them JCron Scheduler—used for cron jobs management and scheduling to simulate cron jobs through the Joomla! frontend interface at preset intervals Indeed, were it not for the fact that Vaughan needs the content to automatically be updated, we needn't use any extension other than the 4RSS component. Other extensions The core module that will be used for this site is: Main Menu module—creates the primary navigation functionality for the site pages Sections and categories New sections and categories will need to be created so that incoming article feeds will be correctly routed according to their description. A new section will be created that we will call Feed. Under this section, we shall have three categories—Bad News, More Bad News, and Weird News. Create a new section We intend to create a section that will be named Feed. In order to do this, perform the following steps: Navigate to the Section Manager from the Control Panel, and then click on the New icon at the top right-hand side, in order to create a new section. On the next page, add the name of the section, and then save your changes. Create new categories To create a new category, perform the following steps: Navigate to the Category Manager page from the Control Panel. On the following page, create a new category in the same way as we created the new section. However, remember to set the Section to Feed.
Read more
  • 0
  • 0
  • 2981

article-image-getting-started-apache-solr
Packt
02 Dec 2011
8 min read
Save for later

Getting Started with Apache Solr

Packt
02 Dec 2011
8 min read
  (For more resources on Apache, see here.) We're going to get started by downloading Solr, examine its directory structure, and then finally run it. This sets you up for the next section, which tours a running Solr server. Get Solr: You can download Solr from its website: http://lucene.apache.org/ solr/. The last Solr release this article was written for is version 3.4. Solr has had several relatively minor point-releases since 3.1 and it will continue. In general I recommend using the latest release since Solr and Lucene's code are extensively tested. Lucid Imagination also provides a Solr distribution called "LucidWorks for Solr". As of this writing it is Solr 3.2 with some choice patches that came after to ensure its stability and performance. It's completely open source; previous LucidWorks releases were not as they included some extras with use limitations. LucidWorks for Solr is a good choice if maximum stability is your chief concern over newer features. Get Java: The only prerequisite software needed to run Solr is Java 5 (a.k.a. java version 1.5) or later—ideally Java 6. Typing java –version at a command line will tell you exactly which version of Java you are using, if any. Use latest version of Java! The initial release of Java 7 included some serious bugs that were discovered shortly before its release that affect Lucene and Solr. The release of Java 7u1 on October 19th, 2011 resolves these issues. These same bugs occurred with Java 6 under certain JVM switches, and Java 6u29 resolves them. Therefore, I advise you to use the latest Java release. Java is available on all major platforms including Windows, Solaris, Linux, and Apple. Visit http://www.java.com to download the distribution for your platform. Java always comes with the Java Runtime Environment (JRE) and that's all Solr requires. The Java Development Kit (JDK) includes the JRE plus the Java compiler and various diagnostic utility programs. One such useful program is jconsole, and so the JDK distribution is recommended. Solr is a Java-based web application, but you don't need to be particularly familiar with Java in order to use it. Solr's installation directory structure When you unzip Solr after downloading it, you should find a relatively straightforward directory structure: client: Convenient language-specific client APIs for talking to Solr. Ignore the client directory Most client libraries are maintained by other organizations, except for the Java client SolrJ which lies in the dist/ directory. client/ only contains solr-ruby , which has fallen out of favor compared to rsolr —both of which are Ruby Solr clients. contrib: Solr contrib modules. These are extensions to Solr. The final JAR file for each of these contrib modules is actually in dist/; so the actual files here are mainly the dependent JAR files. analysis-extras: A few text analysis components that have large dependencies. There are some "ICU" Unicode classes for multilingual support, a Chinese stemmer, and a Polish stemmer. clustering: A engine for clustering search results. dataimporthandler: The DataImportHandler (DIH) —a very popular contrib module that imports data into Solr from a database and some other sources. extraction: Integration with Apache Tika– a framework for extracting text from common file formats. This module is also called SolrCell and Tika is also used by the DIH's TikaEntityProcessor. uima: Integration with Apache UIMA—a framework for extracting metadata out of text. There are modules that identify proper names in text and identify the language, for example. To learn more, see Solr's wiki: http://wiki.apache.org/solr/SolrUIMA. velocity: Simple Search UI framework based on the Velocity templating language. dist: Solr's WAR and contrib JAR files. The Solr WAR file is the main artifact that embodies Solr as a standalone file deployable to a Java web server. The WAR does not include any contrib JARs. You'll also find the core of Solr as a JAR file, which you might use if you are embedding Solr within an application, and Solr's test framework as a JAR file, which is to assist in testing Solr extensions. You'll also see SolrJ's dependent JAR files here. docs: Documentation—the HTML files and related assets for the public Solr website, to be precise. It includes a good quick tutorial, and of course Solr's API. Even if you don't plan on extending the API, some parts of it are useful as a reference to certain pluggable Solr configuration elements—see the listing for the Java package org.apache.solr.analysis in particular. example: A complete Solr server, serving as an example. It includes the Jetty servlet engine (a Java web server), Solr, some sample data and sample Solr configurations. The interesting child directories are: example/etc: Jetty's configuration. Among other things, here you can change the web port used from the pre-supplied 8983 to 80 (HTTP default). exampledocs: Sample documents to be indexed into the default Solr configuration, along with the post.jar program for sending the documents to Solr. example/solr: The default, sample Solr configuration. This should serve as a good starting point for new Solr applications. It is used in Solr's tutorial. example/webapps: Where Jetty expects to deploy Solr from. A copy of Solr's WAR file is here, which contains Solr's compiled code. Solr's home directory and Solr cores When Solr starts, the very first thing it does is determine where the Solr home directory is. There are various ways to tell Solr where it is, but by default it's the directory named simply solr relative to the current working directory where Solr is started. You will usually see a solr.xml file in the home directory, which is optional but recommended. It mainly lists Solr cores. For simpler configurations like example/solr, there is just one Solr core, which uses Solr's home directory as its core instance directory . A Solr core holds one Lucene index and the supporting Solr configuration for that index. Nearly all interactions with Solr are targeted at a specific core. If you want to index different types of data separately or shard a large index into multiple ones then Solr can host multiple Solr cores on the same Java server. A Solr core's instance directory is laid out like this: conf: Configuration files. The two I mention below are very important, but it will also contain some other .txt and .xml files which are referenced by these two. conf/schema.xml: The schema for the index including field type definitions with associated analyzer chains. conf/solrconfig.xml: The primary Solr configuration file. conf/xslt: Various XSLT files that can be used to transform Solr's XML query responses into formats such as Atom and RSS. conf/velocity: HTML templates and related web assets for rapid UI prototyping using Solritas. The soon to be discussed "browse" UI is implemented with these templates. data: Where Lucene's index data lives. It's binary data, so you won't be doing anything with it except perhaps deleting it occasionally to start anew. lib: Where extra Java JAR files can be placed that Solr will load on startup. This is a good place to put contrib JAR files, and their dependencies. Running Solr Now we're going to start up Jetty and finally see Solr running albeit without any data to query yet. We're about to run Solr directly from the unzipped installation. This is great for exploring Solr and doing local development, but it's not what you would seriously do in a production scenario. In a production scenario you would have a script or other mechanism to start and stop the servlet engine with the operating system—Solr does not include this. And to keep your system organized, you should keep the example directly as exactly what its name implies—an example. So if you want to use the provided Jetty servlet engine in production, a fine choice then copy the example directory elsewhere and name it something else. First go to the example directory, and then run Jetty's start.jar file by typing the following command: >>cd example >>java -jar start.jar The > > notation is the command prompt. These commands will work across *nix and DOS shells. You'll see about a page of output, including references to Solr. When it is finished, you should see this output at the very end of the command prompt: 2008-08-07 14:10:50.516::INFO: Started SocketConnector @ 0.0.0.0:8983 The 0.0.0.0 means it's listening to connections from any host (not just localhost, notwithstanding potential firewalls) and 8983 is the port. If Jetty reports this, then it doesn't necessarily mean that Solr was deployed successfully. You might see an error such as a stack trace in the output if something went wrong. Even if it did go wrong, you should be able to access the web server: http://localhost:8983. Jetty will give you a 404 page but it will include a list of links to deployed web applications, which will just be Solr for this setup. Solr is accessible at: http://localhost:8983/solr, and if you browse to that page, then you should either see details about an error if Solr wasn't loaded correctly, or a simple page with a link to Solr's admin page, which should be http://localhost:8983/solr/admin/. You'll be visiting that link often. To quit Jetty (and many other command line programs for that matter), press Ctrl+C on the keyboard.
Read more
  • 0
  • 0
  • 2979
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-hands-tutorial-ejb-31-security
Packt
15 Jun 2011
9 min read
Save for later

Hands-on Tutorial on EJB 3.1 Security

Packt
15 Jun 2011
9 min read
EJB 3.1 Cookbook Security is an important aspect of many applications. Central to EJB security is the control of access to classes and methods. There are two approaches to controlling access to EJBs. The first, and the simplest, is through the use of declarative annotations to specify the types of access permitted. The second approach is to use code to control access to the business methods of an EJB. This second approach should not be used unless the declarative approach does not meet the needs of the application. For example, access to a method may be denied during certain times of the day or during certain maintenance periods. Declarative security is not able to handle these types of situations. In order to incorporate security into an application, it is necessary to understand the Java EE environment and its terminology. The administration of security for the underlying operating system is different from that provided by the EE server. The EE server is concerned with realms, users and groups. The application is largely concerned with roles. The roles need to be mapped to users and groups of a realm for the application to function properly. A realm is a domain for a server that incorporates security policies. It possesses a set of users and groups which are considered valid users of an application. A user typically corresponds to an individual while a group is a collection of individuals. Group members frequently share a common set of responsibilities. A Java EE server may manage multiple realms. An application is concerned with roles. Access to EJBs and their methods is determined by the role of a user. Roles are defined in such a manner as to provide a logical way of deciding which users/groups can access which methods. For example, a management type role may have the capability to approve a travel voucher whereas an employee role should not have that capability. By assigning certain users to a role and then specifying which roles can access which methods, we are able to control access to EJBs. The use of groups makes the process of assigning roles easier. Instead of having to map each individual to a role, the user is assigned to a group and the group is mapped to a role. The business code does not have to check every individual. The Java EE server manages the assignment of users to groups. The application needs only be concerned with controlling a group's access. A group is a server level concept. Roles are application level. One group can be associated with multiple applications. For example, a student group may use a student club and student registration application while a faculty group might also use the registration application but with more capability. A role is simply a name for a set of capabilities. For example, an auditor role may be to review and certify a set of accounts. This role would require read access to many, if not all, of the accounts. However, modification privileges may be restricted. Each application has its own set of roles which have been defined to meet the security needs of the application. The EE server manages realms consisting of users, groups, and resources. The server will authenticate users using Java's underlying security features. The user is then referred to as a principal and has a credential containing the user's security attributes. During the deployment of an application, users and groups are mapped to roles of the application using a deployment descriptor. The configuration of the deployment descriptor is normally the responsibility of the application deployer. During the execution of the application, the Java Authentication and Authorization Service (JAAS) API authenticates a user and creates a principal representing the user. The principal is then passed to an EJB. Security in a Java EE environment can be viewed from different perspectives. When information is passed between clients and servers, transport level security comes into play. Security at this level can include Secure HTTP (HTTPS) and Secure Sockets Layer (SSL). Messages can be sent across a network in the form of Simple Object Access Protocol (SOAP) messages. These messages can be encrypted. The EE container for EJBs provides application level security which is the focus of the chapter. Most servers provide unified security support between the web container and the EJB container. For example, calls from a servlet in a web container to an EJB are handled automatically resulting in a flexible security mechanism. Most of the recipes presented in this article are interrelated. If your intention is to try out the code examples, then make sure you cover the first two recipes as they provide the framework for the execution of the other recipes. In the first recipe, Creating the SecurityApplication, we create the foundation application for the remaining recipes. In the second recipe, Configuring the server to handle security, the basic steps needed to configure security for an application are presented. The use of declarative security is covered in the Controlling security using declarations recipe while programmatic security is discussed in the next article on Controlling security programmatically. The Understanding and declaring roles recipe examines roles in more detail and the Propagating identity recipe talks about how the identity of a user is managed in an application. Creating the SecurityApplication In this article, we will create a SecurityApplication built around a simple Voucher entity to persist travel information. This is a simplified version of an application that allows a user to submit a voucher and for a manager to approve or disapprove it. The voucher entity itself will hold only minimal information. Getting ready The illustration of security will be based on a series of classes: Voucher – An entity holding travel-related information VoucherFacade – A facade class for the entity AbstractFacade – The base class of the VoucherFacade VoucherManager – A class used to manage vouchers and where most of the security techniques will be demonstrated SecurityServlet – A servlet used to drive the demonstrations All of these classes will be members of the packt package in the EJB module except for the servlet which will be placed in the servlet package of the WAR module. How to do it... Create a Java EE application called SecurityApplication with an EJB and a WAR module. Add a packt package to the EJB module and an entity called Voucher to the package. Add five private instance variables to hold a minimal amount of travel information: name, destination, amount, approved, and an id. Also, add a default and a three argument constructor to the class to initialize the name, destination, and amount fields. The approved field is also set to false. The intent of this field is to indicate whether the voucher has been approved or not. Though not shown below, also add getter and setter methods for these fields. You may want to add other methods such as a toString method if desired. @Entity public class Voucher implements Serializable { private String name; private String destination; private BigDecimal amount; private boolean approved; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; public Voucher() { } public Voucher(String name, String destination, BigDecimal amount) { this.name = name; this.destination = destination; this.amount = amount; this.approved = false; } ... } Next, add an AbstractFacade class and a VoucherFacade class derived from it. The VoucherFacade class is shown below. As with other facade classes found in previous chapters, the class provides a way of accessing an entity manager and the base class methods of the AbstractFacade class. @Stateless public class VoucherFacade extends AbstractFacade<Voucher> { @PersistenceContext(unitName = "SecurityApplication-ejbPU") private EntityManager em; protected EntityManager getEntityManager() { return em; } public VoucherFacade() { super(Voucher.class); } } Next, add a stateful EJB called VoucherManager. Inject an instance of the VoucherFacade class using the @EJB annotation. Also add an instance variable for a Voucher. We need a createVoucher method that accepts a name, destination, and amount arguments, and then creates and subsequently persists the Voucher. Also, add get methods to return the name, destination, and amount of the voucher. @Stateful public class VoucherManager { @EJB VoucherFacade voucherFacade; Voucher voucher; public void createVoucher(String name, String destination, BigDecimal amount) { voucher = new Voucher(name, destination, amount); voucherFacade.create(voucher); } public String getName() { return voucher.getName(); } public String getDestination() { return voucher.getDestination(); } public BigDecimal getAmount() { return voucher.getAmount(); } ... } Next add three methods: submit – This method is intended to be used by an employee to submit a voucher for approval by a manager. To help explain the example, display a message showing when the method has been submitted. approve – This method is used by a manager to approve a voucher. It should set the approved field to true and return true. reject – This method is used by a manager to reject a voucher. It should set the approved field to false and return false. @Stateful public class VoucherManager { ... public void submit() { System.out.println("Voucher submitted"); } public boolean approve() { voucher.setApproved(true); return true; } public boolean reject() { voucher.setApproved(false); return false; } } To complete the application framework, add a package called servlet to the WAR module and a servlet called SecurityServlet to the package. Use the @EJB annotation to inject a VoucherManager instance field into the servlet. In the try block of the processRequest method, add code to create a new voucher and then use the submit method to submit it. Next, display a message indicating the submission of the voucher. public class SecurityServlet extends HttpServlet { @EJB VoucherManager voucherManager; protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { voucherManager.createVoucher("Susan Billings", "SanFrancisco", BigDecimal.valueOf(2150.75)); voucherManager.submit(); out.println("<html>"); out.println("<head>"); out.println("<title>Servlet SecurityServlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h3>Voucher was submitted</h3>"); out.println("</body>"); out.println("</html>"); } finally { out.close(); } } ... } Execute the SecurityServlet. Its output should appear as shown in the following screenshot: How it works... In the Voucher entity, notice the use of BigDecimal for the amount field. This java.math package class is a better choice for currency data than float or double. Its use avoids problems which can occur with rounding. The @GeneratedValue annotation, used with the id field, is for creating an entity facade. In the VoucherManager class, notice the injection of the stateless VoucherFacade session EJB into a stateful VoucherManager EJB. Each invocation of a VoucherFacade method may result in the method being executed against a different instance of VoucherManager. This is the correct use of a stateless session EJB. The injection of a stateful EJB into a stateless EJB is not recommended.  
Read more
  • 0
  • 0
  • 2977

Packt
22 Aug 2013
7 min read
Save for later

Pentaho – Using Formulas in Our Reports

Packt
22 Aug 2013
7 min read
(For more resources related to this topic, see here.) At the end of the article, we propose that you make some modifications to the report created in this article. Starting practice In this article, we will create a copy of the report, then we will do the necessary changes in its layout; the final result is as follows: As we can observe in the previous screenshot, the rectangle that is to the left of each title changes color. We'll see how to do this, and much more, shortly. Time for action – making a copy of the previous report In this article, we will use an already created report. To do so, we will open it and save it with the name 09_Using_Formulas.prpt. Then we will modify its layout to fit this article. Finally, we will establish default values for our parameters. The steps for making a copy of the previous report are as follows: We open the report 07_Adding_Parameters.prpt that we created. Next, we create a copy by going to File | Save As... and saving it with the name 09_Using_Formulas.prpt. We will modify our report so that it looks like the following screenshot: As you can see, we have just added a rectangle in the Details section, a label (Total) in the Details Header section, and we have modified the name of the label found in the Report Header section. To easily differentiate this report from the one used previously, we have also modified its colors to grayscale. Later in this article, we will make the color of the rectangle vary according to the formula, so itis important that the rest of the report does not have too many colors so the result are easy for the end user to see. We will establish default values in our parameters so we can preview the report without delays caused by having to choose the values for ratings, year, and month. We go to the Data tab, select the SelectRating parameter, right-click on it, and choose the Edit Parameter... option: In Default Value, we type the value [G]: Next, we click on OK to continue. We should do something similar for SelectYear and SelectMonth: For SelectYear, the Default Value will be 2005. For SelectMonth, the Default Value will be 5. Remember that the selector shows the names of the months, but internally the months' numbers are used; so, 5 represents May. What just happened? We created a copy of the report 07_Adding_Parameters.prpt and saved it with the name 09_Using_Formulas.prpt. We changed the layout of the report, adding new objects and changing the colors. Then we established default values for the parameters SelectRating, SelectYear, and SelectMonth. Formulas To manage formulas, PRD implements the open standard OpenFormula. According to OpenFormula's specifications: "OpenFormula is an open format for exchanging recalculated formulas between office application implementations, particularly for spreadsheets. OpenFormula defines the types, syntax, and semantics for calculated formulas, including many predefined functions and operations, so that formulas can be exchanged between applications and produce substantively equal outputs when recalculated with equal inputs. Both closed and open source software can implement OpenFormula." For more information on OpenFormula, refer to the following links: Wikipedia: http://en.wikipedia.org/wiki/OpenFormula Specifications: https://www.oasis-open.org/committees/download.php/16826/openformula-spec-20060221.html Web: http ://www.openformula.org/ Pentaho wiki: http://wiki.pentaho.com/display/Reporting/Formula+Expressions Formulas are used for greatly varied purposes, and their use depends on the result one wants to obtain. Formulas let us carry out simple and complex calculations based on fixed and variable values and include predefined functions that let us work with text, databases, date and time, let us make calculations, and also include general information functions and user-defined functions. They also use logical operators (AND, OR, and so on) and comparative operators (>, <, and so on). Creating formulas There are two ways to create formulas: By creating a new function and by going to Common | Open Formula By pressing the button in a section's / an object's Style or Attributes tab, or to configure some feature In the report we are creating in this article, we will create formulas using both methods. Using the first method, general-use formulas can be created. That is, the result will be an object that can either be included directly in our report or used as a value in another function, style, or attribute. We can create objects that make calculations at a general level to be included in sections that include Report Header, Group Footer, and so on, or we can make calculations to be included in the Details section. In this last case, the formula will make its calculation row by row. With this last example, we can make an important differentiation with respect to aggregate functions as they usually can only calculate totals and subtotals. Using the second method, we create specific-use functions that affect the value of the style or attribute of an individual object. The way to use these functions is simple. Just choose the value you want to modify in the Style and Attributes tabs and click on the button that appears on their right. In this way, you can create formulas that dynamically assign values to an object's color, position, width, length, format, visibility, and so on. Using this technique, stoplights can be created by assigning different values to an object according to a calculation, progress bars can be created by changing an object's length, and dynamic images can be placed in the report using the result of a formula to calculate the image's path. As we have seen in the examples, using formulas in our reports gives us great flexibility in applying styles and attributes to objects and to the report itself, as well as the possibility of creating our own objects based on complex calculations. By using formulas correctly, you will be able to give life to your reports and adapt them to changing contexts. For example, depending on which user executes the report, a certain image can appear in the Report Header section, or graphics and subreports can be hidden if the user does not have sufficient permissions. The formula editor The formula editor has a very intuitive and easy-to-use UI that in addition to guiding us in creating formulas, tells us, whenever possible, the value that the formula will return. In the following screenshot, you can see the formula editor: We will explain its layout with an example. Let's suppose that we added a new label and we want to create a formula that returns the value of Attributes.Value. For this purpose, we do the following: Select the option to the right of Attributes.Value. This will open the formula editor. In the upper-left corner, there is a selector where we can specify the category of functions that we want to see. Below this, we find a list of the functions that we can use to create our own formulas. In the lower-left section, we can see more information about the selected function; that is, the type of value that it will return and a general description: We choose the CONCATENATE function by double-clicking on it, and in the lower-right section, we can see the formula (Formula:) that we will use. We type in =CONCATENATE(Any), and an assistant will open in the upper-right section that will guide us in entering the values we want to concatenate. We could complete the CONCATENATE function by adding some fixed values and some variables; take the following example: If there is an error in the text of the formula, text will appear to warn us. Otherwise, the formula editor will try to show us the result that our formula will return. When it is not possible to visualize the result that a formula will return, this is usually because the values used are calculated during the execution of the report. Formulas should always begin with the = sign. Initially, one tends to use the help that the formula editor provides, but later, with more practice, it will become evident that it is much faster to type the formula directly. Also, if you need to enter complex formulas or add various functions with logical operators, the formula editor will not be of use.
Read more
  • 0
  • 0
  • 2977

article-image-test-driving-uitableviews-cedar
Joe Masilotti
04 Mar 2015
8 min read
Save for later

Test Driving UITableViews with Cedar

Joe Masilotti
04 Mar 2015
8 min read
One of the first things a developer does when learning iOS development is to display a list of items to the user. In iOS we use UITableViews to show one-dimensional tables of information. In practice they look like a long list of data and should be used in that way. UITableViews get their information from a UITableViewDataSource, which responds to a few delegate methods for a number of cells and what information the cells contain. This post will follow a step-by-step guide to test driving UITableViews in iOS. All code samples will use the behavior-driven testing framework Cedar. Cedar can be installed as a Cocoapod by adding the following to your Podfile: target Specs do pod Cedar end Follow this guide for installation and configuration instructions if you are having trouble or want a crash course on the framework. Unit-Style Approach One way to test table views is to follow a unit-style approach on the data source. The goal there is to call single public methods and assert that the correct state was altered or the return value was configured correctly. The target for unit testing a UITableView is its UITableViewDataSource property. The tests for this are fairly straightforward as they call -tableView:cellForRowAtIndexPath: and -tableView:numberOfCellsInSection: directly. For example, let's say we want our controller to display a table with the current list of iPhones. Our mental assertions are that this table should show a single section with nine items, one for each of the iPhone, iPhone 3G, iPhone 3GS, iPhone 4, iPhone 4s, iPhone 5, iPhone 5s, iPhone 6, and iPhone 6 Plus. The unit tests will follow a very similar pattern. Since a table defaults to one section we don't need to write a test asserting the number of sections. We can just go about testing that there are nine cells and assuming that the first and last cells text is correct, everything is working. describe(@"ViewController", ^{ __block ViewController *subject; beforeEach(^{ subject = [[ViewController alloc] init]; }); describe(@"-tableView:numberOfRowsInSection:", ^{ it(@"should have nine cells", ^{ [subject tableView:subject.tableView numberOfRowsInSection:0] should equal(9); }); }); describe(@"-tableView:cellForRowAtIndexPath:", ^{ __block UITableViewCell *cell; context(@"the first cell", ^{ beforeEach(^{ NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; cell = [subject tableView:subject.tableView cellForRowAtIndexPath:indexPath]; }); it(@"should display 'iPhone'", ^{ cell.textLabel.text should equal(@"iPhone"); }); }); context(@"the last cell", ^{ beforeEach(^{ NSIndexPath *indexPath = [NSIndexPath indexPathForRow:8 inSection:0]; cell = [subject tableView:subject.tableView cellForRowAtIndexPath:indexPath]; }); it(@"should display 'iPhone 6 Plus'", ^{ cell.textLabel.text should equal(@"iPhone 6 Plus"); }); }); }); }); Now the good part about these tests is that they are easy to follow and straight to the point. When we ask how many items there are we expect the right amount. And when we want to ensure the first cell is set up correctly we test just that. Issues Unfortunately there are a few problems with this approach. The biggest issue is that we can get these tests to pass without actually displaying anything on the screen. A simple implementation of these two methods in our controller will make everything green but has no guarantee that a table view is on the screen (or that one even exists!). The first step in remedying this is to write a test asserting that the table view is a subview. Another, albeit minor, issue is we are breaking encapsulation; we are exposing that our controller conforms to the UITableViewDataSource protocol. Let's see what we can do about these two problems. Benefits Don't think that unit-style is bad, it just has different uses. If you have an app that uses multiple instances you will see benefits from this approach. This is because all you would need in your controller is to ensure the right type of data source was configured. You could take this one step farther by injecting the array of items to display and unit testing that. Then you have a repeatable unit of code that shows a list of data conforming to your app's specifications, which is quite powerful. Behavior-Driven Approach Let's take a more behavioral approach to our problem. Our goal is to display to the user the list of iPhones. If we care about what the user sees what is the closest way of replicating that? How about what cells are visible to the user? From Apple's documentation, -visibleCells on UITableView: Returns the table cells that are visible in the receiver. This sounds interesting. Let's restructure our tests to run assertions on the cells that the user sees, not some made up world of delegates and data sources. describe(@"when the view loads", ^{ beforeEach(^{ subject.view should_not be_nil; [subject.view layoutIfNeeded]; }); it(@"should display the first iPhone, first", ^{ UITableViewCell *firstCell = subject.tableView.visibleCells.firstObject; firstCell.textLabel.text should equal(@"iPhone"); }); it(@"display the iPhone 6 Plus, last", ^{ UITableViewCell *lastCell = subject.tableView.visibleCells.lastObject; lastCell.textLabel.text should equal(@"iPhone 6 Plus"); }); }); Note that in the beforeEach we assert that the view should exist. This is to kick off the controller's view lifecycle methods, namely -loadView and -viewDidLoad. We then tell its view to layout its subviews if need be. This ensures that anything we add as subviews have their layout constraints configured and applied. To get this to pass we have a few things to take care of. Create the backing array of iPhones Create the table view and add it as a subview Become the data source and respond to the calls The first one is easy so let's knock that out first. @interface ViewController () <UITableViewDataSource> @property (nonatomic) UITableView *tableView; @property (nonatomic, strong) NSArray *iPhones; @end @implementation ViewController - (instancetype)init { if (self = [super init]) { self.iPhones = @[ @"iPhone", @"iPhone 3G", @"iPhone 3GS", @"iPhone 4", @"iPhone 4s", @"iPhone 5", @"iPhone 5s", @"iPhone 6", @"iPhone 6 Plus" ]; } return self; } Note the opening up of the -tableView property in the interface extension. This allows us to keep it private in the header and the outside world while still being able to modify it internally. Next let's add the table view and its auto layout constraints. - (void)viewDidLoad { [super viewDidLoad]; self.tableView = [[UITableView alloc] init]; [self.view addSubview:self.tableView]; [self addTableViewConstraints]; } #pragma mark - Private - (void)addTableViewConstraints { self.tableView.translatesAutoresizingMaskIntoConstraints = NO; NSDictionary *views = @{ @"tableView": self.tableView }; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[tableView]|" options:kNilOptions metrics:nil views:views]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[tableView]|" options:kNilOptions metrics:nil views:views]]; } Since we aren't working with Storyboards or xibs/nibs we create the table view manually and add it as a subview. We also will need to add some simple auto layout constraints to have it fill the screen. Check out Apple's Auto Layout by Example guide if you would like a deeper explanation. Finally let's get to the meat of the issue and respond to the data source methods. #pragma mark - <UITableViewDataSource> - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.iPhones.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier forIndexPath:indexPath]; cell.textLabel.text = self.iPhones[indexPath.row]; return cell; } We also need to become the data source of the table so do that and register the cell in -viewDidLoad. [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kCellIdentifier]; self.tableView.dataSource = self; Finally add the constant to the top of the file. NSString * const kCellIdentifier = @"CellIdentifier"; What's interesting with this approach is that not until you have every line correct with the tests pass. This helps ensure that what is happening under spec is closer to the real experience of the app. For example, having a table view on the screen, responding to the delegate calls, but not assigning the delegate won't get you anywhere. In the unit approach you could have done just that but still seen your tests go green. Benefits of Behavior Testing When testing behavior you put yourself in a world that more closely represents the state when a user is interacting with it. It also enables you to test collaboration between objects without having to single very simple piece of the architecture out. This means it can be easy to get carried away and start writing full integration tests from controllers. If you keep to only testing one or two layers of abstraction, in this case the table view through the delegate, your code and specs remain easy to read and understand. A side effect of this approach enabled us to hide some implementation details in the production code. This means we are more freely to do a green-to-green refactor without having to change our specs. For example, we could extract the UITableViewDataSource into its own object and know that it works correctly when all of the existing tests still pass. If we wanted to then reuse that collaborator we could then extract the specs and have it stand on its own. Or if our backing array turned into an NSDictionary and found everything by key nothing in our tests would have to change. There are many styles of testing and even more ways to test Objective-C code and the Cocoa Touch framework. Behavior testing is just one approach that has proved to be the most flexible and easy to understand for me. What other techniques and methods have you implemented to ensure code coverage on your own iOS apps? About the author Joe Masilotti is a test-driven iOS developer living in Brooklyn, NY. He contributes to open-source testing tools on GitHub and talks about development, cooking, and craft beer on Twitter.
Read more
  • 0
  • 0
  • 2975

article-image-getting-started-apache-mesos
Packt
28 Feb 2018
7 min read
Save for later

Getting Started with Apache Mesos

Packt
28 Feb 2018
7 min read
1 Getting Started with Apache Mesos In this article by David Blomquist author of the book Apache Mesos Cookbook, we will In this chapter, we will provide an overview of the Mesos architecture and recipes for installing Mesos on Linux and Mac. The following are the recipes coverbeed covering in this chapter following topics: Installing Mesos on Ubuntu 16.04 from packages Installing Mesos on Ubuntu 14.04 from packages Installing Mesos on CentOS 7 and RHEL 7 from packages Introduction Apache Mesos is a cluster management software that can distribute the combined resources of many individual servers to applications through frameworks. Mesos is an open source software that is free to download and use in accordance with the Apache License 2.0. This book article will provide the reader with recipes for deploying and developing Apache Mesos and the Mesos frameworks. Mesos can run on Linux, Mac, and Windows. However, we recommend running Mesos on Linux for production deployments and on Mac and Windows for development purposes only. Mesos can be installed from TAR files, Git, source code, or from packages downloaded from repositories. We have chosen to cover only a few installation methods on select operating system versions in this bookarticle. The reasons for covering these specific operating systems and installation methods are as follows: The operating systems natively include a kernel that supports full resource isolation The operating systems are current as of this writing with long term support The operating systems and installation methods do not require workarounds or an excessive number of external repositories The installation methods use the latest stable version of Mesos, whether it is from packages or source code Mesosphere, founded by one of the original developers of Mesos, is a company that provides free open source packages as well as commercial support for Mesos. Mesosphere packages are well maintained and provide an easy way to install and run Mesos. You can run a production Mesos cluster using these packages if you do not require any customization of the build or install process. However, installing from source will allow you to customize the build and install process and enable and disable features. If you want a completely open source and customizable production cluster, we recommend you to install Mesos from source on Ubuntu 16.04 or Ubuntu 14.04. If you want a development environment on a Mac, building from source on OS X is the only way to go. The installation methods that we cover will all provide you with a good base for building out a Mesos development or production environment. We will guide you through the installations in the following sections, but first, you will need to plan for your Mesos deployment. For a Mesos development environment, you only need one host or node. The node can be a physical computer, a virtual machine, or a cloud instance. For a production cluster, we recommend at least three master nodes and as many slave nodes as you will need to support your application frameworks. You can think of the slave nodes as a pool of CPU, RAM, and storage that can be increased by simply adding more slave nodes. Mesos makes it very easy to add slave nodes to an existing cluster as your application requirements increase. At this point, you should know whether you will be building a Mesos development environment or a production cluster and you should have an idea of how many master and slave nodes you will need. The next sections will provide recipes for installing Mesos in the environment of your choice Installing Mesos on Ubuntu 16.04 from Packages In this recipe, we will be installing Mesos .deb packages from the Mesosphere repositories using apt. Getting ready You must be running a 64-bit version of the Ubuntu 16.04 operating system and it should be patched to the most current patch level using apt-get prior to installing the Mesos packages. How to do it… First, download and install the OpenPGP key for the Mesosphere packages: $ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv E56151BF Now install the Mesosphere repository:  $ DISTRO=$(lsb_release -is | tr '‘[:upper:]'’ '‘[:lower:]'’) $ CODENAME=$(lsb_release -cs) $ echo "“deb http://repos.mesosphere.io/${DISTRO} ${CODENAME} main"” | sudo tee /etc/apt/sources.list.d/mesosphere.list Update the apt-get package indexes:  $ sudo apt-get update And finally, install Mesos and the included ZooKeeper binaries:  $ sudo apt-get -y install mesos At this point, you can start Mesos to do some basic testing. To start the Mesos master and agent (slave) daemons, execute the following:  $ sudo service mesos-master start $ sudo service mesos-slave start To validate the Mesos installation, open a browser and point it to http://:5050. Replace with the actual address of the host with the new Mesos installation How it works… The Mesosphere packages provide the software required to run Mesos.. Next, you will configure ZooKeeper, which is covered in Chapter 2. See also If you prefer to build and install Mesos on Ubuntu from source code, we will cover that in an upcoming section in this chapter. Installing Mesos on Ubuntu 14.04 from Packages In this recipe, we will be installing Mesos .deb packages from the Mesosphere repositories using apt. Getting ready You must be running a 64-bit version of the Ubuntu 14.04 operating system and it should be patched to the most current patch level using apt-get prior to installing the Mesos packages. How to do it…… First, download and install the OpenPGP key for the Mesosphere packages:  $ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv E56151BF Now install the Mesosphere repository: $ DISTRO=$(lsb_release -is | tr '‘[:upper:]'’ '‘[:lower:]'’) $ CODENAME=$(lsb_release -cs) $ echo "“deb http://repos.mesosphere.io/${DISTRO} ${CODENAME} main"” | sudo tee /etc/apt/sources.list.d/mesosphere.list Update the apt-get package indexes:  $ sudo apt-get update And finally, install Mesos and the included ZooKeeper binaries: $ sudo apt-get -y install mesos At this point, you can either start Mesos to do some basic testing. To start the Mesos master and agent (slave) daemons, execute the following command:  $ sudo service mesos-master start $ sudo service mesos-slave start To validate the Mesos installation, open a browser and point it to http://:5050. Replace with the actual address of the host with the new Mesos installation How it works… The Mesosphere packages provide the software required to run Mesos. Next, you will configure ZooKeeper, which is covered in Chapter 2., See also If you prefer to build and install Mesos on Ubuntu from source code, we will cover that in an upcoming section in this chapter. Installing Mesos on CentOS 7 and RHEL 7 from Packages In this recipe, we will be installing Mesos .rpm packages from the Mesosphere repositories using yum. Getting ready Your CentOS 7 or RHEL 7 operating system should be patched to the most current patch level using yum prior to installing the Mesosphere packages. How to do it… First, add the Mesosphere repository: $ sudo rpm -Uvh http://repos.mesosphere.io/el/7/noarch/RPMS/mesosphere-el-repo-7-1.noarch.rpm And now, install Mesos and ZooKeeper: $ sudo yum -y install mesos mesosphere-zookeeper At this point, you can start Mesos to do some basic testing. To start the Mesos master and agent (slave) daemons, execute the following:  $ sudo service mesos-master start $ sudo service mesos-slave start To validate the Mesos installation, open a browser and point it to http://:5050. Replace with the actual address of the host with the new Mesos installation How it works… The Mesosphere packages provide the software required to run Mesos. Next, you will configure ZooKeeper, which is covered in Chapter 2. See also If you prefer to build and install Mesos from source code on RHEL 7 or CentOS 7, you can find installation instructions for CentOS 7 on the mesos.apache.org website. We do not cover installing Mesos source code on RHEL7 or CentOS 7 in this book article due to dependencies that require the installation of packages from multiple third-party repositories.  Summary In this article we have learned how to install Mesos on Ubuntu 16.04 from packages, how to install Mesos on Ubuntu 14.04 from packages and how to installing Mesos on CentOS 7 and RHEL 7 from packages. Resources for Article:   Further resources on this subject: Apache Mesos Cookbook Mastering Mesos
Read more
  • 0
  • 0
  • 2974
article-image-replication
Packt
24 Dec 2014
5 min read
Save for later

Cassandra High Availability: Replication

Packt
24 Dec 2014
5 min read
This article by Robbie Strickland, the author of Cassandra High Availability, describes the data replication architecture used in Cassandra. Replication is perhaps the most critical feature of a distributed data store, as it would otherwise be impossible to make any sort of availability guarantee in the face of a node failure. As you already know, Cassandra employs a sophisticated replication system that allows fine-grained control over replica placement and consistency guarantees. In this article, we'll explore Cassandra's replication mechanism in depth. Let's start with the basics: how Cassandra determines the number of replicas to be created and where to locate them in the cluster. We'll begin the discussion with a feature that you'll encounter the very first time you create a keyspace: the replication factor. (For more resources related to this topic, see here.) The replication factor On the surface, setting the replication factor seems to be a fundamentally straightforward idea. You configure Cassandra with the number of replicas you want to maintain (during keyspace creation), and the system dutifully performs the replication for you, thus protecting you when something goes wrong. So by defining a replication factor of three, you will end up with a total of three copies of the data. There are a number of variables in this equation. Let's start with the basic mechanics of setting the replication factor. Replication strategies One thing you'll quickly notice is that the semantics to set the replication factor depend on the replication strategy you choose. The replication strategy tells Cassandra exactly how you want replicas to be placed in the cluster. There are two strategies available: SimpleStrategy: This strategy is used for single data center deployments. It is fine to use this for testing, development, or simple clusters, but discouraged if you ever intend to expand to multiple data centers (including virtual data centers such as those used to separate analysis workloads). NetworkTopologyStrategy: This strategy is used when you have multiple data centers, or if you think you might have multiple data centers in the future. In other words, you should use this strategy for your production cluster. SimpleStrategy As a way of introducing this concept, we'll start with an example using SimpleStrategy. The following Cassandra Query Language (CQL) block will allow us to create a keyspace called AddressBook with three replicas: CREATE KEYSPACE AddressBookWITH REPLICATION = {   'class' : 'SimpleStrategy',   'replication_factor' : 3}; The data is assigned to a node via a hash algorithm, resulting in each node owning a range of data. Let's take another look at the placement of our example data on the cluster. Remember the keys are first names, and we determined the hash using the Murmur3 hash algorithm. The primary replica for each key is assigned to a node based on its hashed value. Each node is responsible for the region of the ring between itself (inclusive) and its predecessor (exclusive). While using SimpleStrategy, Cassandra will locate the first replica on the owner node (the one determined by the hash algorithm), then walk the ring in a clockwise direction to place each additional replica, as follows: Additional replicas are placed in adjacent nodes when using manually assigned tokens In the preceding diagram, the keys in bold represent the primary replicas (the ones placed on the owner nodes), with subsequent replicas placed in adjacent nodes, moving clockwise from the primary. Although each node owns a set of keys based on its token range(s), there is no concept of a master replica. In Cassandra, unlike make other database designs, every replica is equal. This means reads and writes can be made to any node that holds a replica of the requested key. If you have a small cluster where all nodes reside in a single rack inside one data center, SimpleStrategy will do the job. This makes it the right choice for local installations, development clusters, and other similar simple environments where expansion is unlikely because there is no need to configure a snitch (which will be covered later in this section). For production clusters, however, it is highly recommended that you use NetworkTopologyStrategy instead. This strategy provides a number of important features for more complex installations where availability and performance are paramount. NetworkTopologyStrategy When it's time to deploy your live cluster, NetworkTopologyStrategy offers two additional properties that make it more suitable for this purpose: Rack awareness: Unlike SimpleStrategy, which places replicas naively, this feature attempts to ensure that replicas are placed in different racks, thus preventing service interruption or data loss due to failures of switches, power, cooling, and other similar events that tend to affect single racks of machines. Configurable snitches: A snitch helps Cassandra to understand the topology of the cluster. There are a number of snitch options for any type of network configuration. Here's a basic example of a keyspace using NetworkTopologyStrategy: CREATE KEYSPACE AddressBookWITH REPLICATION = {   'class' : 'NetworkTopologyStrategy',   'dc1' : 3,   'dc2' : 2}; In this example, we're telling Cassandra to place three replicas in a data center called dc1 and two replicas in a second data center called dc2. Summary In this article, we introduced the foundational concepts of replication and consistency. In our discussion, we outlined the importance of the relationship between replication factor and consistency level, and their impact on performance, data consistency, and availability. By now, you should be able to make sound decisions specific to your use cases. This article might serve as a handy reference in the future as it can be challenging to keep all these details in mind. Resources for Article: Further resources on this subject: An overview of architecture and modeling in Cassandra [Article] Basic Concepts and Architecture of Cassandra [Article] About Cassandra [Article]
Read more
  • 0
  • 0
  • 2972

article-image-working-javascript-drupal-6-part-2
Packt
15 Oct 2009
11 min read
Save for later

Working with JavaScript in Drupal 6: Part 2

Packt
15 Oct 2009
11 min read
Creating a theme Drupal separates layout and styling information from processing code. HTML is usually stored in templates or theme functions. The CSS along with other styling information (including some images) are also stored separately from the functional code. A theme is a collection of resources, (usually template files, CSS, JavaScript, and images) that can be plugged into Drupal to provide layout and styling to a site. If we want to change the look and feel of a site, the best place to start is with a theme. We've already created a JavaScript file that provides additional printing functionality. In this section, we are going to create a new theme, and then incorporate our new script. Typically, a theme must provide the following things: HTML markup for common Drupal structures such as pages, blocks, comments, and nodes. This will include navigational elements. Any styles needed. This is typically done in the CSS files. Any necessary images or media elements that will play a substantial role in layout. Information about the theme, including a screenshot. In addition to these, many themes will also provide: JavaScript files that may be necessary for added functionality. Other sorts of media, such as Flash animations, may occasionally be needed. PHP code that performs complex layout tasks may sometimes be used. A theme must have at least one pre-defined file (the theme's .info file). Commonly though, full themes have eight or more files. Full themes and subthemes The first step in creating our theme is deciding whether we want to start from scratch or begin with an existing theme. If we were to start from scratch, we would create a full theme. But if we wanted to build on another theme, we could create another kind of theme called a subtheme. To create a full theme, we would need to implement all of the required features of a theme, and perhaps add on some other features as well. Typically, this would involve creating all of the necessary templates, a couple of CSS files, and a couple of helper files. Sometimes, it is more expedient to begin with an existing theme and just override the things we want to change. This is the capability that subthemes, a new addition in Drupal 6, provide. From a technical perspective, creating a full theme is not difficult, but it is time-consuming. In contrast, a subtheme can be created quickly. Since our focus is on JavaScript, and not theming, we will be creating a subtheme. That way, we can make the most of an existing project and keep our work to a minimum. As the name implies, a subtheme is derived from another theme. Therefore, we will need to pick a theme to start with. Drupal comes with six themes pre-installed, and these vary in method and complexity. For example, Garland is a complex theme with templates, JavaScript, CSS, and lots of special PHP. In contrast, Chameleon generates simpler HTML, but does all of this in pure PHP code, without reliance on template files. Since we want to focus our attention on JavaScript, it would be best to start with a simple theme. From there, we will selectively override only what we need. Our theme of choice will be the Bluemarine theme, which has a very basic PHPTemplate-based structure that is easy to customize. Looking for a good base theme to start with? Check out the Zen theme in the contributed themes at http://drupal.org/project/zen. It's built to enable subtheming. You will need to create some CSS content, but the HTML structure is all in place. We will with Bluemarine and create a new subtheme, borrowing as much as possible from the base theme. Creating a theme: first steps To create a theme, we will do the following: Create a directory for the theme. Create the theme's .info (dot-info) file. Add our first files. After we've finished these three short steps, we will add our JavaScript to the theme. A precaution for theme developersTo get build our theme correctly, we will need to be able to view it. But to view it, we will need to have it enabled. What if we make a mistake that prevents Drupal from rendering correctly? We could lock ourselves out of the administration page. To prevent this from happening, it is wise to set the administration theme to one of the default themes. This is done in Administer | Site configuration | Administration theme. Creating a theme directory Every theme should have its own directory. When you install Drupal, one of the directories created is called themes/. If you take a look inside that directory, you will see all of the top-level (non-subtheme) themes that Drupal provides. Do not put your themes in there. This directory is only for themes that come with Drupal's core. Themes, like modules, go inside the sites/ subtree. The sites/ area also appears inside the Drupal directory and is created when you install Drupal. Inside the sites/ directory, two folders are created by default: sites/all/ and sites/default/. To better understand these two directories, keep in mind that one installation of Drupal can serve multiple sites. For example, if I have a site called example.com and a site called anotherexample.com, I can use one installation of Drupal to serve both. The first site I install will be installed in sites/default/. The next site I install will need to go in its own folder (for example, sites/anotherexample.com/). Content that only belongs to a single site should go in that site's directory. For example, if I want to install a special theme for anotherexample.com, I should put the theme in sites/anotherexample.com/themes/. In other cases, I may want to share a theme or module across all sites. In these cases, files would go in sites/all/. In this article, we will be putting all of our themes and modules in sites/all/themes/ and sites/all/modules/. If in doubt, put files in sites/all/. This makes it easier to share your work between sites. With that background material behind us, let's create our theme directory. The name we give to this directory will be the name of our theme. Theme and module names should always be in a lower case, and may be composed only of letters, numbers, and underscores. In the .info file, we will be able to attach a human-readable name to the theme. That may use spaces, capital letters, and other special characters. Our first theme will be in sites/all/themes/frobnitz/ as seen in the following screehshot:. If this is the first theme you create, you may also need to create the sites/all/themes/ directory. Once the directory is created, we need to add a special file to tell Drupal about the theme. Creating the .info file Inside sites/all/themes/frobnitz/, we need to create a file to provide important information about our theme. The file will always be named after the theme, and end with the extension .info. Because of the extension, it is usually called the theme's dot-info file. We will create frobnitz.info, and add the following contents to the file: ; $Id$name = Frobnitzdescription = Table-based multi-column theme with JavaScriptenhancements.version = 1.0core = 6.xbase theme = bluemarine The .info file contains a handful of lines with the form name = value. These entries provide basic information about the theme. Some of this information is displayed to the user (for example, name and description). Some information is used by Drupal to make sure that this theme will work with the installed version of Drupal. The core parameter is used for that. Later in this article, we will see some other entries that contain information directly related to the display of the theme. With those parameters, we can change the way the theme looks and behaves just by altering the values. The name, description, version, and core fields are required for all themes. The name field is used to give our theme a human-friendly name. You can use capital letters and spaces in this field. The description parameter is used to provide a one-sentence explanation of what the theme does. The version field should indicate which version number of this theme is. As with most software, you typically start with 1.0. Finally, the core field should indicate what version of Drupal this theme works with. For us, it will always be 6.x. There's one additional parameter in our file: base theme = bluemarine The base theme parameter is what we use to inform Drupal that our theme is a subtheme, derived from bluemarine. If we were creating a theme from scratch, we would not include this line. For the time being, this is all we need in our theme file. Later, we will add more. Modifying .info files and clearing the cacheTo improve performance, Drupal caches theme information, particularly the theme's .info file. When you change the contents of that file (for example, when you add a new script or stylesheet), you will need to clear the theme information cache to force Drupal to re-read the .info file. The most reliable way to do this is through Administer | Site configuration | Performance. At the bottom of that page is a button labeled Clear cached data. Press that button to clear the cache. Adding files to the theme At this point, we've actually created a working theme. Only the theme's directory and .info file are required. With just those two elements, we can now go to Administer | Site building | Themes and select our Frobnitz theme. Of course, all Frobnitz will be at this point is an exact duplicate of Bluemarine The following screenshot shows a sample of the Frobnitz theme: The logo image, titles, and all other information in the screenshot is showing through the regular site configuration. The look and feel should be identical whether we choose Bluemarine or our new Frobnitz style. What we want to do now is add something new to our theme, and what better place to start than with a stylesheet. Our theme will import all of the stylesheets of its parent. So in our theme, we inherit style.css from Bluemarine. Looking at the HTML source for a page rendered with Frobnitz, we would see a line like this: <link type="text/css" rel="stylesheet" media="all" href="/drupal/themes/bluemarine/style.css" /> If we didn't want that style to be loaded from Bluemarine, we could simply create another file named style.css in our own theme's directory. This new file would override Bluemarine's. But we don't want to start over and rebuild the stylesheet. We just want to add a few extra styles. To do this, we will create a new stylesheet called frobnitz.css. This CSS file will also go inside our sites/all/themes/frobnitz/ folder. Like PHP and JavaScript, the Drupal project defines coding standards for CSS. You can learn more about these here: http://drupal.org/node/302199. To begin, all we will do is add a black, one-pixel border on the right side of the lefthand column. The stylesheet looks like this: #sidebar-left { border-right: 1px solid black;} Cascade: the 'C' in 'CSS'Drupal will add styles in a specific order, with theme styles added last. Because of this, you can predictably make use of the CSS cascading behavior. The previous declaration will be added to the declaration made in Bluemarine's style.css file. That means we will get the combination of styles in style.css and frobnitz.css, with frobnitz.css's declarations taking precedence. But before our new stylesheet will have any effect, we need to tell Drupal to include it as part of the theme. This is done with a simple addition to the frobnitz.info file: ; $Id$name = Frobnitzdescription = Table-based multi-column theme with JavaScript enhancements.version = 1.0core = 6.xbase theme = bluemarinestylesheets[all][] = frobnitz.css Only that last line, which is highlighted, is different. This informs Drupal that there is a stylesheet that should be used on all format types for this page, and is named frobnitz.css. The all keyword indicates that this stylesheet applies to all media format types. CSS format types include print (for printed media), screen (for screen displays), and other types. While this directive uses an array-like syntax, it does not function like an array. You cannot, for example, refer to stylesheets[all][1].
Read more
  • 0
  • 0
  • 2971

article-image-introducing-web-components
Packt
19 May 2015
16 min read
Save for later

Introducing Web Components

Packt
19 May 2015
16 min read
In this article by Sandeep Kumar Patel, author of the book Learning Web Component Development, we will learn about the web component specification in detail. Web component is changing the web application development process. It comes with standard and technical features, such as templates, custom elements, Shadow DOM, and HTML Imports. The main topics that we will cover in this article about web component specification are as follows: What are web components? Benefits and challenges of web components The web component architecture Template element HTML Import (For more resources related to this topic, see here.) What are web components? Web components are a W3C specification to build a standalone component for web applications. It helps developers leverage the development process to build reusable and reliable widgets. A web application can be developed in various ways, such as page focus development and navigation-based development, where the developer writes the code based on the requirement. All of these approaches fulfil the present needs of the application, but may fail in the reusability perspective. This problem leads to component-based development. Benefits and challenges of web components There are many benefits of web components: A web component can be used in multiple applications. It provides interoperability between frameworks, developing the web component ecosystem. This makes it reusable. A web component has a template that can be used to put the entire markup separately, making it more maintainable. As web components are developed using HTML, CSS, and JavaScript, it can run on different browsers. This makes it platform independent. Shadow DOM provides encapsulation mechanism to style, script, and HTML markup. This encapsulation mechanism provides private scope and prevents the content of the component being affected by the external document. Equally, some of the challenges for a web component include: Implementation: The W3C web component specification is very new to the browser technology and not completely implemented by the browsers. Shared resource: A web component has its own scoped resources. There may be cases where some of the resources between the components are common. Performance: Increase in the number of web components takes more time to get used inside the DOM. Polyfill size: The polyfill are a workaround for a feature that is not currently implemented by the browsers. These polyfill files have a large memory foot print. SEO: As the HTML markup present inside the template is inert, it creates problems in the search engine for the indexing of web pages. The web component architecture The W3C web component specification has four main building blocks for component development. Web component development is made possible by template, HTML Imports, Shadow DOM, and custom elements and decorators. However, decorators do not have a proper specification at present, which results in the four pillars of web component paradigm. The following diagram shows the building blocks of web component: These four pieces of technology power a web component that can be reusable across the application. In the coming section, we will explore these features in detail and understand how they help us in web component development. Template element The HTML <template> element contains the HTML markup, style, and script, which can be used multiple times. The templating process is nothing new to a web developer. Handlebars, Mustache, and Dust are the templating libraries that are already present and heavily used for web application development. To streamline this process of template use, W3C web component specification has included the <template> element. This template element is very new to web development, so it lacks features compared to the templating libraries such as Handlebars.js that are present in the market. In the near future, it will be equipped with new features, but, for now, let's explore the present template specification. Template element detail The HTML <template> element is an HTMLTemplateElement interface. The interface definition language (IDL) definition of the template element is listed in the following code: interface HTMLTemplateElement : HTMLElement {readonly attribute DocumentFragment content;}; The preceding code is written in IDL language. This IDL language is used by the W3C for writing specification. Browsers that support HTML Import must implement the aforementioned IDL. The details of the preceding code are listed here: HTMLTemplateElement: This is the template interface and extends the HTMLElement class. content: This is the only attribute of the HTML template element. It returns the content of the template and is read-only in nature. DocumentFragment: This is a return type of the content attribute. DocumentFragment is a lightweight version of the document and does not have a parent. To find out more about DocumentFargment, use the following link: https://developer.mozilla.org/en/docs/Web/API/DocumentFragment Template feature detection The HTML <template> element is very new to web application development and not completely implemented by all browsers. Before implementing the template element, we need to check the browser support. The JavaScript code for template support in a browser is listed in the following code: <!DOCTYPE html><html><head lang="en"><meta charset="UTF-8"><title>Web Component: template support</title></head><body><h1 id="message"></h1><script>var isTemplateSupported = function () {var template = document.createElement("template");return 'content' in template;};var isSupported = isTemplateSupported(),message = document.getElementById("message");if (isSupported) {message.innerHTML = "Template element is supported by thebrowser.";} else {message.innerHTML = "Template element is not supported bythe browser.";}</script></body></html> In the preceding code, the isTemplateSupported method checks the content property present inside the template element. If the content attribute is present inside the template element, this method returns either true or false. If the template element is supported by the browser, the h1 element will show the support message. The browser that is used to run the preceding code is Chrome 39 release. The output of the preceding code is shown in following screenshot: The preceding screenshot shows that the browser used for development is supporting the HTML template element. There is also a great online tool called "Can I Use for checking support for the template element in the current browser. To check out the template support in the browser, use the following link: http://caniuse.com/#feat=template The following screenshot shows the current status of the support for the template element in the browsers using the Can I Use online tool: Inert template The HTML content inside the template element is inert in nature until it is activated. The inertness of template content contributes to increasing the performance of the web application. The following code demonstrates the inertness of the template content: <!DOCTYPE html><html><head lang="en"><meta charset="UTF-8"><title>Web Component: A inert template content example.</title></head><body><div id="message"></div><template id="aTemplate"><img id="profileImage"src="http://www.gravatar.com/avatar/c6e6c57a2173fcbf2afdd5fe6786e92f.png"><script>alert("This is a script.");</script></template><script>(function(){var imageElement =document.getElementById("profileImage"),messageElement = document.getElementById("message");messageElement.innerHTML = "IMG element "+imageElement;})();</script></body></html> In the preceding code, a template contains an image element with the src attribute, pointing to a Gravatar profile image, and an inline JavaScript alert method. On page load, the document.getElementById method is looking for an HTML element with the #profileImage ID. The output of the preceding code is shown in the following screenshot: The preceding screenshot shows that the script is not able to find the HTML element with the profileImage ID and renders null in the browser. From the preceding screenshot it is evident that the content of the template is inert in nature. Activating a template By default, the content of the <template> element is inert and are not part of the DOM. The two different ways that can be used to activate the nodes are as follows: Cloning a node Importing a node Cloning a node The cloneNode method can be used to duplicate a node. The syntax for the cloneNode method is listed as follows: <Node> <target node>.cloneNode(<Boolean parameter>) The details of the preceding code syntax are listed here: This method can be applied on a node that needs to be cloned. The return type of this method is Node. The input parameter for this method is of the Boolean type and represents a type of cloning. There are 2 different types of cloning, listed as follows: Deep cloning: In deep cloning, the children of the targeted node also get copied. To implement deep cloning, the Boolean input parameter to cloneNode method needs to be true. Shallow cloning: In shallow cloning, only the targeted node is copied without the children. To implement shallow cloning the Boolean input parameter to cloneNode method needs to be false. The following code shows the use of the cloneNode method to copy the content of a template, having the h1 element with some text: <!DOCTYPE html><html><head lang="en"><meta charset="UTF-8"><title>Web Component: Activating template using cloneNode method</title></head><body><div id="container"></div><template id="aTemplate"><h1>Template is activated using cloneNode method.</h1></template><script>var aTemplate = document.querySelector("#aTemplate"),container = document.getElementById("container"),templateContent = aTemplate.content,activeContent = templateContent.cloneNode(true);container.appendChild(activeContent);</script></body></html> In the preceding code, the template element has the aTemplate ID and is referenced using the querySelector method. The HTML markup content inside the template is then retrieved using a content property and saved in a templateContent variable. The cloneNode method is then used for deep cloning to get the activated node that is later appended to a div element. The following screenshot shows the output of the preceding code: To find out more about the cloneNode method visit: https://developer.mozilla.org/en-US/docs/Web/API/Node.cloneNode Importing a node The importNode method is another way of activating the template content. The syntax for the aforementioned method is listed in the following code: <Node> document.importNode(<target node>,<Boolean parameter>) The details of the preceding code syntax are listed as follows: This method returns a copy of the node from an external document. This method takes two input parameters. The first parameter is the target node that needs to be copied. The second parameter is a Boolean flag and represents the way the target node is cloned. If the Boolean flag is false, the importNode method makes a shallow copy, and for a true value, it makes a deep copy. The following code shows the use of the importNode method to copy the content of a template containing an h1 element with some text: <!DOCTYPE html><html><head lang="en"><meta charset="UTF-8"><title>Web Component: Activating template using importNode method</title></head><body><div id="container"></div><template id="aTemplate"><h1>Template is activated using importNode method.</h1></template><script>var aTemplate = document.querySelector("#aTemplate"),container = document.getElementById("container"),templateContent = aTemplate.content,activeContent = document.importNode(templateContent,true);container.appendChild(activeContent);</script></body></html> In the preceding code, the template element has the aTemplate ID and is referenced using the querySelector method. The HTML markup content inside the template is then retrieved using the content property and saved in the templateContent variable. The importNode method is then used for deep cloning to get the activated node that is later appended to a div element. The following screenshot shows the output of the preceding code: To find out more about the importNode method, visit: http://mdn.io/importNode HTML Import The HTML Import is another important piece of technology of the W3C web component specification. It provides a way to include another HTML document present in a file with the current document. HTML Imports provide an alternate solution to the Iframe element, and are also great for resource bundling. The syntax of the HTML Imports is listed as follows: <link rel="import" href="fileName.html"> The details of the preceding syntax are listed here: The HTML file can be imported using the <link> tag and the rel attribute with import as the value. The href string points to the external HTML file that needs to be included in the current document. The HTML import element is implemented by the HTMLElementLink class. The IDL definition of HTML Import is listed in the following code: partial interface LinkImport {readonly attribute Document? import;};HTMLLinkElement implements LinkImport; The preceding code shows IDL for the HTML Import where the parent interface is LinkImport which has the readonly attribute import. The HTMLLinkElement class implements the LinkImport parent interface. The browser that supports HTML Import must implement the preceding IDL. HTML Import feature detection The HTML Import is new to the browser and may not be supported by all browsers. To check the support of the HTML Import in the browser, we need to check for the import property that is present inside a <link> element. The code to check the HTML import support is as follows: <!DOCTYPE html><html><head lang="en"><meta charset="UTF-8"><title>Web Component: HTML import support</title></head><body><h1 id="message"></h1><script>var isImportSupported = function () {var link = document.createElement("link");return 'import' in link;};var isSupported = isImportSupported(),message = document.getElementById("message");if (isSupported) {message.innerHTML = "Import is supported by the browser.";} else {message.innerHTML = "Import is not supported by thebrowser.";}</script></body></html> The preceding code has a isImportSupported function, which returns the Boolean value for HTML import support in the current browser. The function creates a <link> element and then checks the existence of an import attribute using the in operator. The following screenshot shows the output of the preceding code: The preceding screenshot shows that the import is supported by the current browser as the isImportSupported method returns true. The Can I Use tool can also be utilized for checking support for the HTML Import in the current browser. To check out the template support in the browser, use the following link: http://caniuse.com/#feat=imports The following screenshot shows the current status of support for the HTML Import in browsers using the Can I Use online tool: Accessing the HTML Import document The HTML Import includes the external document to the current page. We can access the external document content using the import property of the link element. In this section, we will learn how to use the import property to refer to the external document. The message.html file is an external HTML file document that needs to be imported. The content of the message.html file is as follows: <h1>This is from another HTML file document.</h1> The following code shows the HTML document where the message.html file is loaded and referenced by the import property: <!DOCTYPE html><html><head lang="en"><link rel="import" href="message.html"></head><body><script>(function(){var externalDocument =document.querySelector('link[rel="import"]').import;headerElement = externalDocument.querySelector('h1')document.body.appendChild(headerElement.cloneNode(true));})();</script></body></html> The details of the preceding code are listed here: In the header section, the <link> element is importing the HTML document present inside the message.html file. In the body section, an inline <script> element using the document.querySelector method is referencing the link elements having the rel attribute with the import value. Once the link element is located, the content of this external document is copied using the import property to the externalDocument variable. The header h1 element inside the external document is then located using a quesrySelector method and saved to the headerElement variable. The header element is then deep copied using the cloneNode method and appended to the body element of the current document. The following screenshot shows the output of the preceding code: HTML Import events The HTML <link> element with the import attribute supports two event handlers. These two events are listed "as follows: load: This event is fired when the external HTML file is imported successfully onto the current page. A JavaScript function can be attached to the onload attribute, which can be executed on a successful load of the external HTML file. error: This event is fired when the external HTML file is not loaded or found(HTTP code 404 not found). A JavaScript function can be attached to the onerror attribute, which can be executed on error of importing the external HTML file. The following code shows the use of these two event types while importing the message.html file to the current page: <!DOCTYPE html><html><head lang="en"><script async>function handleSuccess(e) {//import load Successfulvar targetLink = e.target,externalDocument = targetLink.import;headerElement = externalDocument.querySelector('h1'),clonedHeaderElement = headerElement.cloneNode(true);document.body.appendChild(clonedHeaderElement);}function handleError(e) {//Error in loadalert("error in import");}</script><link rel="import" href="message.html"onload="handleSuccess(event)"onerror="handleError(event)"></head><body></body></html> The details of the preceding code are listed here: handleSuccess: This method is attached to the onload attribute which is executed on the successful load of message.html in the current document. The handleSuccess method imports the document present inside the message.html file, then it finds the h1 element, and makes a deep copy of it . The cloned h1 element then gets appended to the body element. handleError: This method is attached to the onerror attribute of the <link> element. This method will be executed if the message.html file is not found. As the message.html file is imported successfully, the handleSuccess method gets executed and header element h1 is rendered in the browser. The following screenshot shows the output of the preceding code: Summary In this article, we learned about the web component specification. We also explored the building blocks of web components such as HTML Imports and templates. Resources for Article: Further resources on this subject: Learning D3.js Mapping [Article] Machine Learning [Article] Angular 2.0 [Article]
Read more
  • 0
  • 0
  • 2968
article-image-working-compliance
Packt
19 Apr 2016
10 min read
Save for later

Working With Compliance

Packt
19 Apr 2016
10 min read
In this article by Abhijeet Shriram Janwalkar, the author of VMware vRealize Configuration Manager Cookbook, we will discuss how to check compliance, create exceptions so that we don't get any false positives, and finally, create some Alert Rules that will alert us when non-compliant rules are found. (For more resources related to this topic, see here.) Checking the compliance of the infrastructure After creating all the rules, rule groups, and templates, we need to check the compliance of the infrastructure. We will learn how to check how compliant we are against internal standards, or we can directly use standard compliance packs we have already downloaded and imported. We will use a standard imported template for this recipe. Getting ready All the heavy lifting should have been done on the VCM server: it should be ready with the templates and at least one machine group, which will have the machines for whom we need to check the compliance, or we can use the default machine groups available. Using our own machine group is preferable. How to do it... As mentioned earlier, we will use an imported standard template, International Organization for Standardization 27001-27002- Windows 2008 R2 Mbr Server Controls, and we will run this against the default machine group, All Machines. Follow these steps to check the compliance of the Windows servers: Once logged in to VCM, go to Compliance | Templates Make sure the correct machine group is selected from the top; this is how VCM decides which machines to apply the template to measure the compliance. If you want to change the machine group, click on the Machine Group, and from the popup, select the correct machine group. Select the required template from the right-hand side and click on Run.   Depending upon the organization policies, decide to enforce or not enforce the compliance. Not all rules are enforceable; also, we can cause issues such as breaking a working application; for example, if the print spooler service is required to be disabled and we disable the service when we enforce the compliance, this will create an issue on the printer farm as it will stop functioning. So it is better that we first learn what is non-compliant and then make necessary exceptions. We can then enforce compliance from VCM or can ask the respective server owners to take the necessary action.   In a few minutes, depending on how many machines there are to check in the machine group, the compliance run will finish. Click on Close.   The compliance status can be viewed by navigating to the template on the left-hand side and selecting the correct machine group from the top.   In our case, our support team needs to work a lot as we are non-compliant. How it works... When we ask VCM to check compliance, it first applies the filters available in the rule groups, and then, only the machines that pass those filters are considered. The compliance checks are performed on the data collected by VCM and are available in the database, unlike some other tools that perform the checks at the client end, after which the client submits the data to VCM. The process followed by VCM is better as this can be performed on servers that are offline at that time, and when we check the result, we get the value because of which the machine is non-compliant for a rule. Again, this has some issues as well: first, we need to make sure our VCM is clean. By this, I mean whether a machine is purged from VCM when it is decommissioned, or else we will have details of machines that are not present in the infrastructure, and that could affect our final compliance score. The second issue is that it does not give us live details as it works on the data in its database; again, this can produce false positives. To counter this issue, we can schedule a compliance check after a full data collection for that machine group, in which way we will not have stale data to process. Once the compliance has been checked, and if we have chosen to enforce the compliance, it will create jobs to enforce them and will start executing on the managed machines; for example, if we have rules to check the status of a service and expect certain services in the running state, then VCM will start those services. Creating compliance exceptions As you know, every rule has an exception, and this is applicable to compliance as well: you create a rule for blocking the SMTP port on all the servers, and then, you have mail servers that need this port active. Now, we can't block the port, but at the same time, we know this is a known and accepted deviation; hence, we don't want our compliance score to suffer a hit because of this. To solve this, what we can do is add an exception so that this will not create issues while checking compliance. Getting ready Our organization has a policy to disable unwanted services on servers, and the print spooler is considered an unwanted service, so it must be disabled on all the servers but, of course, the exceptions are the print servers. We will create an exception for the print server machine group to be excused from this mandate. We will need rules created in VCM along with a machine group that will include all the print servers. How to do it... Let's create an exception for our print servers by following these steps: Log in to VCM and go to Compliance | Machine Group Compliance | Exceptions. Click on Add.   Provide a descriptive Name and Description, and click on Next.   Select the template for which you want this machine group to be excluded. In this case, we are selecting the one created by our organization rules. Click on Next.   Select the machine group created for this exception; in our case, it is named Print Servers. Click on Next. Select Override non-compliant results to compliant.  I really don't know why there is another option, but there must be a use case that I am not aware of.   We want this exception only for our rule for the print spooler server, called Service_Print_Spooler; so select that rule. Depending upon you requirement, you can have the exception for a complete rule group as well. But having exception for a single rule is sufficient in our case. Click on Finish.   You can enable/disable this exception as per requirement.   How it works... Exceptions are considered when we do a compliance check, and a final score is calculated. By creating an exception, we make sure that we don't get a bad score just because we need to have some things non-compliant. Also, this helps when we are enforcing compliance like in the earlier case, where we enforced Service Status to be disabled then VCM disabled the print spooler service on all the servers including the print servers, and that would have affected productivity. So, creating compliance exception is a win-win situation for both teams: the security team has a nice compliant environment and the printer admin team has a working print farm. Creating compliance alert rules Nobody likes to wait and nobody likes to work on Excel, so what if we get a ticket in our ticketing tool if a managed machine is non-complaint. We can create alerts and then maybe integrate them with a ticketing tool that can create a ticket for us, or VCM can send an e-mail to configured e-mail IDs. Getting ready We will need a working VCM server that is configured to check compliance. How to do it... This is a two-step process; first, we need to create an alert rule and then associate the created alert with the machine group. So, let's begin creating a compliance alert: Log in to VCM and go to Administration | Alerts | Rules. Click on Add.   In the wizard, give descriptive name and add a description. Click on Next. Select Compliance Results Data as the Data Type and click on Next.   As we want to create an alert for the non-compliancy of the rules created for our organization standards, select the appropriate compliance template. If we want an alert for the ISO 27001-27002 standard, we should have opted for that template.   On the next page, accept the newly create rule by clicking on Finish (the button is not in the screenshot).   The next process is to associate this Rule to correct Machine group. So we will continue to step 6. Now move to Administration | AlertsàMachine Group Configuration, and select the Machine group for which you would like the alert to be generated and click Add.   Select the alert we created and click on Next.   Select Severity and click on Next (not shown in the screenshot).   Select the actions that need to be done when the alert is created: we can send an e-mail, we can send an SNMP trap to a monitoring system or VCO that will create an alert in the organization ticketing system, or we can write the log to the Windows event log, and then, from there it will be picked up by the monitoring system to create a ticket. We are choosing to send an e-mail to the concerned people or teams.   Provide the details of who should receive the e-mail, the sender's e-mail ID, the SMTP server, e-mail subject, and modify the message body.   If required, you can check for alerts and click on Finish to close the wizard (the button is not shown in the screenshot).   The alerts can be seen at Console| Alerts.   How it works... We can't just depend on reports for checking compliance, even though that is a good way to check the status, but getting alerts for a non-compliant machine can be more proactive than going through a report. When we check or schedule a check for compliance, the result can be stored in the VCM database and is fetched when we visit the Compliance tab on the VCM console, Alerts provide a more proactive approach: they tell you that there is something wrong and you need to check it, so after every compliance check, if that machine group has something non-compliant, an alert will be created and that will take configured actions like sending an e-mail, sending an SNMP trap, or writing an event to the Windows logs. Those can be proactively worked upon rather than going to the console and checking the reports.   Summary In this article, we learned how to check compliance using a standard imported template. We also learned how to create exceptions for our compliance rules so that standard services can be run without causing our score to go down. Finally, we looked at alerts and ticketing systems. Resources for Article: Further resources on this subject: VM, It Is Not What You Think! [article] vRealize Automation and the Deconstruction of Components [article] Deploying New Hosts with vCenter [article]
Read more
  • 0
  • 0
  • 2967

article-image-advanced-playbooks
Packt
24 Apr 2015
10 min read
Save for later

Advanced Playbooks

Packt
24 Apr 2015
10 min read
In this article by the author, Daniel Hall, of the book, Ansible Configuration Management - Second Edition, we learn to start digging a bit deeper into playbooks. We will be covering the following topics: External data lookups Storing results Processing data Debugging playboks (For more resources related to this topic, see here.) External data lookups Ansible introduced the lookup plugins in version 0.9. These plugins allow Ansible to fetch data from outside sources. Ansible provides several plugins, but you can also write your own. This really opens the doors and allows you to be flexible in your configuration. Lookup plugins are written in Python and run on the controlling machine. They are executed in two different ways: direct calls and with_* keys. Direct calls are useful when you want to use them like you would use variables. Using the with_* keys is useful when you want to use them as loops. In the next example, we use a lookup plugin directly to get the http_proxy value from environment and send it through to the configured machine. This makes sure that the machines we are configuring will use the same proxy server to download the file. --- - name: Downloads a file using a proxy hosts: all tasks:    - name: Download file      get_url:        dest: /var/tmp/file.tar.gz         url: http://server/file.tar.gz      environment:        http_proxy: "{{ lookup('env', 'http_proxy') }}" You can also use lookup plugins in the variable section. This doesn't immediately lookup the result and put it in the variable as you might assume; instead, it stores it as a macro and looks it up every time you use it. This is good to know if you are using something, the value of which might change over time. Using lookup plugins in the with_* form will allow you to iterate over things you wouldn't normally be able to. You can use any plugin like this, but ones that return a list are most useful. In the following code, we show how to dynamically register a webapp farm. --- - name: Registers the app server farm hosts: localhost connection: local vars:    hostcount: 5 tasks:    - name: Register the webapp farm      local_action: add_host name={{ item }} groupname=webapp      with_sequence: start=1 end={{ hostcount }} format=webapp%02x If you were using this example, you would append a task to create each as a virtual machine and then a new play to configure each of them. Situations where lookup plugins are useful are as follows: Copying a whole directory of Apache config to a conf.d style directory Using environment variables to adjust what the playbooks does Getting configuration from DNS TXT records Fetching the output of a command into a variable Storing results Almost every module outputs something, even the debug module. Most of the time, the only variable used is the one named changed. The changed variable helps Ansible decide whether to run handlers or not and which color to print the output in. However, if you wish to, you can store the returned values and use them later in the playbook. In this example, we look at the mode in the /tmp directory and create a new directory named /tmp/subtmp with the same mode as shown here. --- - name: Using register hosts: ansibletest user: root tasks:    - name: Get /tmp info    file:        dest: /tmp        state: directory      register: tmp      - name: Set mode on /var/tmp      file:        dest: /tmp/subtmp        mode: "{{ tmp.mode }}"        state: directory Some modules, such as the file module in the previous example, can be configured to simply give information. By combining this with the register feature, you can create playbooks that can examine the environment and calculate how to proceed. Combining the register feature and the set_fact module allows you to perform data processing on data you receive back from the modules. This allows you to compute values and perform data processing on these values. This makes your playbooks even smarter and more flexible than ever. Register allows you to make your own facts about hosts from modules already available to you. This can be useful in many different circumstances: Getting a list of files in a remote directory and downloading them all with fetch Running a task when a previous task changes, before the handlers run Getting the contents of the remote host SSH key and building a known_hosts file Processing data Ansible uses Jinja2 filters to allow you to transform data in ways that aren't possible with basic templates. We use filters when the data available to us in our playbooks is not in the format we want, or require further complex processing before it can be used with modules or templates. Filters can be used anywhere we would normally use a variable, such as in templates, as arguments to modules, and in conditionals. Filters are used by providing the variable name, a pipe character, and then the filter name. We can use multiple filter names separated with pipe characters to use multiple pipes, which are then applied left to right. Here is an example where we ensure that all users are created with lowercase usernames: --- - name: Create user accounts hosts: all vars:    users: tasks:    - name: Create accounts      user: name={{ item|lower }} state=present      with_items:        - Fred        - John        - DanielH Here are a few popular filters that you may find useful: Filter Description min When the argument is a list it returns only the smallest value. max When the argument is a list it returns only the largest value. random When the argument is a list it picks a random item from the list. changed When used on a variable created with the register keyword, it returns true if the task changed anything; otherwise, it returns false. failed When used on a variable created with the register keyword, it returns true if the task failed; otherwise, it returns false. skipped When used on a variable created with the register keyword, it returns true if the task changed anything; otherwise, it returns false. default(X) If the variable does not exist, then the value of X will be used instead. unique When the argument is a list, return a list without any duplicate items. b64decode Convert the base64 encoded string in the variable to its binary representation. This is useful with the slurp modules, as it returns its data as a base64 encoded string. replace(X, Y) Return a copy of the string with any occurrences of X replaced by Y. join(X) When the variable is a list, return a string with all the entries separated by X. Debugging playbooks There are a few ways in which you can debug a playbook. Ansible includes both a verbose mode and a debug module specifically for debugging. You can also use modules such as fetch and get_url for help. These debugging techniques can also be used to examine how modules behave when you wish to learn how to use them. The debug module Using the debug module is really quite simple. It takes two optional arguments, msg and fail.msg to set the message that will be printed by the module and fail, if set to yes, indicates a failure to Ansible, which will cause it to stop processing the playbook for that host. We used this module earlier in the skipping modules section to bail out of a playbook if the operating system was not recognized. In the following example, we will show how to use the debug module to list all the interfaces available on the machine: --- - name: Demonstrate the debug module hosts: ansibletest user: root vars:    hostcount: 5 tasks:    - name: Print interface      debug:        msg: "{{ item }}"      with_items: ansible_interfaces The preceding code gives the following output: PLAY [Demonstrate the debug module] *********************************   GATHERING FACTS ***************************************************** ok: [ansibletest]   TASK: [Print interface] ********************************************* ok: [ansibletest] => (item=lo) => {"item": "lo", "msg": "lo"} ok: [ansibletest] => (item=eth0) => {"item": "eth0", "msg": "eth0"}   PLAY RECAP ********************************************************** ansibletest               : ok=2   changed=0   unreachable=0   failed=0 As you can see, the debug module is easy to use to see the current value of a variable during the play. The verbose mode Your other option for debugging is the verbose option. When running Ansible with verbose, it prints out all the values that were returned by each module after it runs. This is especially useful if you are using the register keyword introduced in the previous section. To run ansible-playbook in verbose mode, simply add --verbose to your command line as follows: ansible-playbook --verbose playbook.yml The check mode In addition to the verbose mode, Ansible also includes a check mode and a diff mode. You can use the check mode by adding --check to the command line, and --diff to use the diff mode. The check mode instructs Ansible to walk through the play without actually making any changes to remote systems. This allows you to obtain a listing of the changes that Ansible plans to make to the configured system. It is important here to note that the check mode of Ansible is not perfect. Any modules that do not implement the check feature are skipped. Additionally, if a module is skipped that provides more variables, or the variables depend on a module actually changing something (such as file size), then they will not be available. This is an obvious limitation when using the command or shell modules The diff mode shows the changes that are made by the template module. This limitation is because the template file only works with text files. If you were to provide a diff of a binary file from the copy module, the result would almost be unreadable. The diff mode also works with the check mode to show you the planned changes that were not made due to being in check mode. The pause module Another technique is to use the pause module to pause the playbook while you examine the configured machine as it runs. This way, you can see changes that the modules have made at the current position in the play, and then watch while it continues with the rest of the play. Summary In this article, we explored the more advanced details of writing playbooks. You should now be able to use features such as delegation, looping, conditionals, and fact registration to make your plays much easier to maintain and edit. We also looked at how to access information from other hosts, configure the environment for a module, and gather data from external sources. Finally, we covered some techniques for debugging plays that are not behaving as expected. Resources for Article: Further resources on this subject: Static Data Management [article] Drupal 8 and Configuration Management [article] Introduction to Drupal Web Services [article]
Read more
  • 0
  • 0
  • 2966
Modal Close icon
Modal Close icon