Thursday, July 7, 2016

Creating an FTP server on AWS with Centos

So I needed a micro server that would host files for a VERY dump ftp server. The use case was simple. Protect our production server while opening up ftp access for one specific client to one specific set of files. On my production server, I'll setup an rsync with a cron job, and I'll be all set.

What I found, however was a configuration nightmare. OK, truly, it wasn't that bad, but my inexperience with setting up FTP servers really became a bottleneck. So for future reference, and for anyone attempting the same, here is the script I came up with, after much trial and error.

  1. Create your ec2 instance:
    1. In my case, I used "CentOS 7 (x86_64) - with Updates HVM" from the marketplace as it is my goto AMI. 
    2. I selected a t2.nano, as I know the traffic to this server will be minimal. 
    3. I chose the correct VPC and Subnet to ensure public accessability.
    4. I then chose a moderately sized magnetic volume as I know that the load will be minimal.
    5. For security groups, I have configured a security group for each use case. This allows me to easily add and remove security groups to each server as needed. Simply looking at the list of groups shows me what permissions have been added. I added my internal group, FTP for port 21 & 22, and FTP - passv for the port range that I selected in pasv mode (see step x below). Depending on your setup, you may also want to add port 22 to allow ssh access. That is built into my internal group.
    6. Next I added the appropriate keys and launched my server.
    7. Then, I added an elastic IP address so that I can easily swap instances if needed.
    8. Finally, I added a dns record pointing to the elastic ip.
  2. Configure your instance:
    1. SSH into your instance and give yourself root access: sudo su
    2. Update the server: yum -y update
    3. Install vsfptd: yum -y install vsftpd
    4. Configure vsftpd by editing vsftpd.conf, adding the following to the bottom of the config file, replacing the min/max ports with whatever range you would like, and the pasv_address to the elastic ip you assigned above:
      1. anonymous_enable=NO
        local_enable=YES
        chroot_local_user=YES
        pasv_enable=yes
        pasv_min_port=1224
        pasv_max_port=1248
        pasv_address=xxx.xxx.xxx.xxx
    5. Add an FTP user: useradd -d /home/ftpuser -s /sbin/nologin ftpuser
    6. Set the Password: passwd ftpuser.
    7. You could stop there, but you might get an error like this: "500 OOPS: vsftpd: refusing to run with writable root inside chroot ()" 
      1. To fix that, adjust the permissions of the directory: chmod a-w /home/ftpuser
      2. Then run: setsebool -P allow_ftpd_full_access 1


That should be it! In my case I also setup an rsync script in my production server's crontab to populate the files onto the ftp server.

Friday, March 18, 2016

Custom phone car mount

I was over at microcenter a couple weeks ago and picked up a generic phone mount for my truck. It mounts in the vent and has a nice ball joint for adjusting. Similar to this:


Perfect, I thought. Then I installed it and headed down the road...

One problem, while the vent may seem like an attractive mount point, what happens when you have a vent that pivots? With every turn your phone flings to the right or left. I was about to return it but then remembered I have a buddy with a 3d printer =D

30 minutes later, with the help of SketchUp, I designed this: (.stl file)


It's a simple block with two screw holes for mounting and a hole to receive the peg end of the ball joint. My buddy recommended separating the parts to reduce the amount of scaffolding needed to print the parts. A bit of acetone on the peg, insert that into the block, and the parts will naturally fuse together.

I will screw this into a useless pocket in my truck's dashboard and the phone mount will secure nicely.


Lastly, I will run a usb cable power supply, hard wired, out of a small hole in the bottom of that pocket, allowing for a convenient power supply for my device.

I'll update with pictures once the install is complete!

Wednesday, March 16, 2016

Postgresql upgrade issues - Checking for reg* system OID user data types

So I am prepping for an upgrade of postgres from version 9.2 to 9.4. Since this is a major version upgrade, I chose to use pg_upgrade to try and minimize downtime. My first attempt in one of our dev environments went fairly well, up until I actually launched the upgrade process.

My stopwatch was ready, my commands were ready, my server was ready!

Start the stopwatch...
#/etc/init.d/postgresql-9.2  stop#sudo -u postgres /usr/pgsql-9.4/bin/pg_upgrade --old-datadir=/var/lib/pgsql/9.2/data/ --new-datadir=/var/lib/pgsql/9.4/data/ --old-bindir=/usr/pgsql-9.2/bin/ --new-bindir=/usr/pgsql-9.4/bin/


HERE WE GO!

Performing Consistency Checks
-----------------------------
Checking cluster versions                                   ok
Checking database user is a superuser                       ok
Checking database connection settings                       ok
Checking for prepared transactions                          ok
Checking for reg* system OID user data types                fatal

NOOOOOO!!!!




Quick.....
#/etc/init.d/postgresql-9.2 start

Thank goodness that was only dev... So what now?? Running cat of tables_using_reg.txt, showed me that there were several tables affected:

  public.pg_ts_dict.dict_init
  public.pg_ts_dict.dict_lexize
  public.pg_ts_parser.prs_start
  public.pg_ts_parser.prs_nexttoken
  public.pg_ts_parser.prs_end
  public.pg_ts_parser.prs_headline
  public.pg_ts_parser.prs_lextype

The good news is, it looks like these are remnants of the old pgsql 8.x days when tsearch2 was not part of the distribution.

My solution? Drop pg_ts_dict & pg_ts_parser. Once upgraded, I'll test everything, as long as there are not any issues, we are good to go. Worst case scenario, I can dump those two tables (5 rows total between them) and run an import post upgrade.

Monday, March 14, 2016

First go with AliExpress

So in search of some components for some arduino/rasp-pi hacking, I was getting frustrated with cost of some of the most basic components. I should not have to spend $10-15 on a simple Temperature & Humidity sensor! Sadly, that is one of the cheaper components.
Humidity and Temperature Sensor - RHT03


After some digging, I stumbled upon AliExpress!

www.aliexpress.com

They are basically the Amazon of China. Loads of great deals on about anything you can think of... but this is especially true of electronic components. That sensor alone, also known as a DHT22, is priced at a full 1/4 of the US based outlets (that's $2.50 if you don't want to do the math)!

And that's not all! They also have dozens of component kits on the seriously cheap, like this 37 sensor kit for just over $12! Or how about 600 misc. resistors for $2.60!
http://g03.a.alicdn.com/kf/HTB1DcfKLpXXXXa8XFXXq6xXFXXXN/37-IN-1-SENSOR-KITS-FOR-ARDUINO-HIGH-QUALITY-FREE-SHIPPING-Works-with-Official-for-Arduino.jpghttp://g02.a.alicdn.com/kf/HTB1z17WKFXXXXc8XXXXq6xXFXXXO/Free-Shipping-600-Pcs-30-Kinds-Each-Value-Metal-Film-Resistor-pack-1-4W-1-resistor.jpg

I feel like a kid in a penny candy store!!!

Here's the best part, most of these components come with free shipping!

So what's the catch? Can you have your cake and eat it too? Is this all a bit scam?

The great new is, like amazon, this site is made up of hundreds of sellers, each trying to make a living, and their reputation will make or break their AliExpress store. On top of this, AliExpress seems to have some great dispute tools. In fact, they even hold your payment from the seller until after you have indicated that you have received your order and are satisfied with it!

The downsides? It's all being shipped from China, so unless you want to pay boatloads on shipping, you are not going to enjoy the same second day delivery that Amazon Prime has spoiled us with! We'll see how long things end up taking, so far, 5 of my 7 orders have shipped within 2 days of ordering. They still have to travel over the ocean and through our post office. At these crazy low prices though, they are totally worth the extra wait!

What can I say??? Crazy cheap prices! Free shipping! Excited to make something with my 7 year old!

Paper making: Take 1

So yesterday, I took my first stab at making paper. It's part of a larger goal of making my own Journal. It wasn't perfect, but you've gotta start somewhere. Unfortunately, I did not take pictures of the process, only the results. When I run my second trial, I'll be sure to take pictures of the whole process to share.

My observations thus far are:
  • I need a better frame. 
  • My frame size needs to accommodate for trimming the edges.
  • I need to figure out a better way to regulate the paper thickness. 
  • I need a bucket that is sized closer to my frame.
  • I need to figure out how to whiten the paper, if I am going to continue to use non-white recycling.

I'll give some details about the process after the pictures. Without further ado:

Here is my paper. It's about the thickness and texture of construction paper. It was made primarily of recycled paper bags plus a few old homework pages that were headed to the trash.

Here is the frame I used. It worked ok, but I sized it according to the page size I wanted, not counting for edge trimming. Also, because you need the frame to "catch" the pulp, I need to modify the frame so that the pulp cannot seep between the screen and the frame, which made paper removal very difficult. For my next trial, I will add some furring strips to the top of the frame, screwing the two pieces of wood together. I may actually end up using the furring strip side for the paper making, as the shallow depth might help with paper removal as well.

 Here is the back side of the frame. You can see that I just stapled the screen material to the frame.


Now for the process:

Making the pulp, Part 1:
To make the pulp, you have to start by tearing  and soaking the paper. I did this first so that it would have time to become nice and saturated.
  1. I gathered some misc. paper from the recycle bin. I had some brown paper bags and some old homework. I knew that the paper bag would cause the end result to be brown, I figured for this stage, that didn't matter much.
  2. Put a kettle of water on to boil. This is optional, but I've read that it greatly speeds up the soaking process.
  3. Tear the paper into shreds. I got my kids to help with this part, they loved it! Breaking the paper up like this will help it to saturate faster.
  4. Place the paper into a large boiling-water-safe bowl and pour the boiling water on top and give it a quick stir.
  5. We'll come back to the soaking paper later.

Build the frame:
  1. I cut a 1x2 we had lying around with 90deg. angles to the desired size. One mistake here was, I should have added a margin for error so that I had room for trimming the edges when the paper finished drying. I think an extra 1/2" in width and length would be plenty for trimming. Also, I used a skill saw instead of taking the time to break out our chop saw. It's hard (at least for me) to make accurate cuts, let alone accurate diagonal cuts using hand power tools. I knew this was a trial, so I just went with it.
  2. Next, I screwed the four sides at the corners. I used a 2x4 block to help keep things square during the screwing process. 
  3. I then measured diagonally for square and had to make a couple of minor adjustments by slightly loosening and tightening specific screws.
  4. I salvaged the screen material from an old window screen we had lying behind our shed. It was not perfect, but was good enough for the learning process. Like with the chop saw, when I get ready to build a set of production frames, I'll run to the big box and buy some new window screen.
  5. I attached the screen to one side of the frame with far more staples than I probably needed.
  6. Then stretched the screen around the front of the frame and attached the opposite side. I should have rinsed the screen first, as this turned out to be a dirty set of steps.
  7. I stretched the next side and secured it, then I folded the corners to keep everything nice an neat.
  8. Next, I stretched and attached the last side. 
  9. Lastly, I washed the whole frame, hoping the dirt and grim would not attach itself to my soon to be paper.
 Making the pulp, Part 2:
  1. Take the now saturated pulp and drop it into your favorite blender/food processor. I kept the batches to less than half our blender at a time.
  2. Add enough water to be sure the paper will blend.  I don't think there is any danger to using too much water in this step, though this was my first attempt, so....
  3. Blend away, until you have a nice smooth sludge.
  4. Pour the sludge into another bowl for safe keeping.
  5. Rinse & repeat, until you have blended all of your pulp.
Making the paper:
  1. Get a water proof box of some sort, I used a plastic bin we had in our garage, and fill it with a few inches of water. 
  2. Add a bit of liquid starch. This is not corn starch. You can find it in the cleaning section of the store, near the ironing stuff. This will "final" or "finish" the paper, allowing the ink to stick to the page without it bleeding and soaking through. I did not have any on hand, so I skipped it this time. I'll get some for my next attempt.
  3. Add your pulp. For my first attempt, I made the mistake of just adding it all. I think a measured amount will be key for making a consistent page thickness.
  4. Give your water/pulp a gentle stir to thin out the pulp and watch for big clumps. You'll want to remove any you find.
  5. Submerge your frame in the concoction and give the water a few seconds to settle. You'll see the pulp even out on the surface of the water. 
  6. Slowly lift the screen. Since mine is made of wood, it was buoyant and naturally floated. I found it helped if I left the screen *just* submerged, maybe an 1/8th of an inch to allow the pulp to settle on the screen.
  7. Slowly lift the screen out of the water and let the water drain out.
  8. Lay a towl on your counter and set the frame on top.
  9. Carefully lay another towel on top and start gently pressing the towel onto the paper.  Once you have the initial amount of water pressed out, it seems safe to start pressing harder. The goal here is to draw out as much of the water as possible. I've seen some people recommend using a sponge on top of the towel to draw out even more water. I'm thinking I'll get one of those squeegee towels that are super absorbent and wring out well.
  10. When you feel like you have removed as much of the moisture as you can, it's time to carefully pull the paper off the screen. One blog I read said to flip the frame and the paper should genitally fall off. This was not the case for me. Either my screen was too course, or the pulp that bleed between the screen and the frame prevent this all together. Either way, I had to get in there with a butter knife to peel up a corner, then I slowly pulled the paper off the screen. While the paper was somewhat fragile, it held together much better than I feared.
  11. Place the freshly peeled page onto a towel or parchment paper to dry a bit longer. From here, some people suggested hang-drying. I was impatient, so I heated the oven to 170 degrees, placed my pages inside and turned the oven off. This worked pretty well, though I will probably skip that with my next trail.
  12. Finally, when your paper is thoroughly and completely dry, trim your paper! My wife had a crafting paper cutter with a blade that follows a track. This made for nice clean edges all the way around.

What are my takeaways. I still have more to figure out. I need to fix the process of making and removing the fresh paper. Then I can focus on getting a consistent thickness. Finally, I'll start playing with pulp materials to work on the texture and color. I'm happy with using recycled paper, but I may experiment with plant based pulp as well.

Monday, November 4, 2013

Installing Zabbix on Jelastic

For months, I have looked over several paid and open source server monitoring products, and have seem to landed on Zabbix. It's an enterprise ready, fully open source, fully free, monitor ANYTHING platform. As I have been evaluating Jelastic as a future host for some personal projects, I decided it would be fitting to attempt an installation there. Below you will find the steps I have taken to setup and install Zabbix on the Jelastic platform.

Deploy Zabbix

To kick things off, you need to start by creating a new environment. Log in with your Jelastic credentials. While in the Jelastic dashboard, click the Create environment button. In this case, we only need a VDS and a MySQL* instance. Enter an Environment name and click Create. (*Note for the time being, you may need to enable a public IP in order for the Zabbix server to connect to the database. This will hopefully be corrected soon.)



Once the environment is deployed, you will receive an few emails which include your authentication information for your various servers. Starting with your VDS, you'll need your Login (most likely root), Password, and Public IP. I have found using a standard terminal is much faster than using the web terminal. SSH into your VDS using a command similar to this:
# SSH root@xxx.xxx.xxx.xxx

Of course, you'll need to replace the x's with the actual IP address assigned to your VDS instance. Once connected, you'll need to enter your secure password. From there, its time to install the Zabbix server:
# rpm -ivh http://repo.zabbix.com/zabbix/2.0/rhel/6/x86_64/zabbix-release-2.0-1.el6.noarch.rpm
# yum install zabbix-server-mysql zabbix-web-mysql
You will need to type 'y' a few times to agree to install the various pieces of the application, but in a few moments, the base of the Zabbix server will be installed.

Initialize the database

While still in the VDS terminal, setting up the database is easy. You will need the Access URL, Login, & Password. Enter the following to get the database setup:

# mysql -h{{Access URL}} -uroot -p{{Password}}   
mysql> CREATE DATABASE zabbix CHARACTER SET utf8 COLLATE utf8_bin;
mysql> CREATE USER 'zabbix'@'%' IDENTIFIED BY '{{secure password}}'
mysql> GRANT ALL PRIVILEGES ON zabbix.* TO 'zabbix'@'%';
mysql> EXIT

If you want to be a bit more secure, feel free to replace % with the IP address of your VDS server. That will limit the access to a single IP address. Next, we'll need import the .sql scripts to initialize the database.

# mysql -h{{Access URL}} -uroot -p{{Password}} zabbix < /usr/share/doc/zabbix-server-mysql-2.0.8/create/schema.sql
# mysql -h{{Access URL}} -uroot -p{{Password}} zabbix < /usr/share/doc/zabbix-server-mysql-2.0.8/create/images.sql
# mysql -h{{Access URL}} -uroot -p{{Password}} zabbix < /usr/share/doc/zabbix-server-mysql-2.0.8/create/data.sql

That's it, your base database is now setup and ready to go.

Configure the server

Back on the VDS via the shell (# ssh root@xxx.xxx.xxx.xxx), you'll want to edit the zabbix_server.conf file with the following settings. DBHost will correspond the Access URL included in your confirmation email:
# vi /etc/zabbix/zabbix_server.conf
DBHost=mysql-{{Your server name}}.jelastic.servint.net
DBName=zabbix
DBUser=zabbix
DBPassword={{Your secure password}}

Then, start the Zabbix server:
# service zabbix-server start
Now configure PHP by editing the zabbix.conf file. You'll need to validate/adjust the following settings... Of course adjusting the timezone to match yours:
# vi /etc/httpd/conf.d/zabbix.conf
php_value max_execution_time 300
php_value memory_limit 128M
php_value post_max_size 16M
php_value upload_max_filesize 2M
php_value max_input_time 300
php_value date.timezone America/Denver

Finally, start the http server:
# service httpd start 

Configure the web interface

You are all set and ready to launch the server! Point your browser at http://xxx.xxx.xxx.xxx/zabbix/, replacing the x's with your IP address, of course. If all went well, you'll see the following Welcome page. Click the Next button.



Here you will see the results of the pre-requisites check. You should have a page of OK's. Click Next.



On the Database configuration page, the Database host will be the Access URL received in the email you received from Jelastic. You'll use zabbix as the Database name and User, along with the secure password you setup. Press the Test connection button.




If all went well, you will get a nice little OK over the Test connection button. Click Next.



The default settings on the Zabbix server details page should be fine. Click Next. Click Next on the pre-installation summary as well. Finally, Click Finish



There you have it. Using the IP address of the VDS, you can now log in with the credentials UN: Admin (case sensitive) and PW: zabbix

Of course you are going to want to change the password right away.


All that is left is installing the Zabbix Agents on your Jelastic instances. For now, it seems the only way to accomplish that will be through the use of their VDS instances. Perhaps in a future release, this could be a plugin to enable the use of their standard server type instances. Regardless, I'll leave the task of installing the Zabbix Agents to a future post.

Thursday, October 31, 2013

Getting started with Apigility

Rationale

During ZendCon 2013, I was excited to hear about a new toolset called Apigility that the folks of Zend Framework have just released. It is an API toolset built on top of ZF2. The exciting thing is that this Apigility takes care of all the API dirty work for us. HAL content, error handling, JSON structure, and so much more!

What I find funny about this toolset, from an implementation standpoint, is that it is not that much different from what we have tooled together ourselves on top of ZF2. Whats better is, we had yet to implement HAL and our error handling logic was still sub-par. So testing this toolset is exciting, in that its another portion of our code that I do not need to implement (well... finish implementing) and maintain.

My focus on this Apigility tutorial will be primarily from the perspective of a Code-Connected REST API's. While the Database-Connected REST API's are fantastic, our internal approach to development has shifted to an API First development strategy. This design decision is implemented by first creating an internal class based API, then leverage Apigility to greatly simplify the creation of a public facing API.

Getting Started - Installation

So, lets dive right in! Before you can begin playing with Apigility, you need to "install" it. The makers of this toolset were kind enough to implement the entire structure and logic flow in just code. This means, no databases to setup, no proxies to configure, no complex routing to setup. Simply bring in the code that is needed and you are ready to go!

There are a number of methods you could use to bring down the code. For me, the simplest was running a Composer script. This requires you have composer installed, but since I did... Move to the directory you wish to place your new API and execute these commands from your favorite terminal:
url -s https://getcomposer.org/installer | php -- 
php composer.phar create-project -sdev --repository-url="https://packages.zendframework.com/" zfcampus/zf-apigility-skeleton /var/www/apigility
For more installation options, check out the README on Apigility's GitHub account. These alternative options include both a downloadable Tarball and a Git clone option.

Next, you will want to place your local instance of Apigility into development mode. This will give you access to all of the nifty tools that streamline the scaffolding of your API. A couple things to keep in mind... You will NOT want to leave your Apigility instance in development mode for your production uses as it exposes many of the configuration options at the hart of your new API. Also, once you have a solid understanding of the structure and makeup of Apigility, you honestly will not need to use the admin interface all that often... of course it does handle a lot of the back end wiring that is needed, so it may be handy to have available, perhaps when you want to iterate the version of your API. To enable development mode, simply type this into your terminal:
php public/index.php development enable
Now we just need to initialize our new application. This can be done by modifying your virtual hosts file or simply spinning up a server using the new to PHP 5.4 built-in php web server. Simply execute this command in your terminal:
php -S 0:8080 -t public/ public/index.php
You can now access Apigility by pointing your web browser at http://localhost:8080!

Installation Summary

Below is the exact code I am using to install Apigility on my local linux box. This is a summary of the above commands, plus a few supplemental commands needed for my specific use case. My webroot is located at /var/www. You may need to make adjustments to this for it to work for you as well.


cd /var/www
mkdir apigility
curl -s https://getcomposer.org/installer | php --
php composer.phar create-project -sdev --repository-url="https://packages.zendframework.com/" zfcampus/zf-apigility-skeleton /var/www/apigility 
rm composer.phar 
cd apigility
php public/index.php development enable
php -S 0:8080 -t public/ public/index.php

Creating Your First API

Once you point your web browser at http://localhost:8080, you will be presented with a welcome screen. Simply hit the Get Started! button:



Next, you'll hit the Create New API button:



Type "Compnay" in the text box then click the Create API button:



Then click the REST Services link:



Followed by the Create New REST Service button.



Here we will name our first REST service. Lets make one that will return a list of employees, along with some basic employee information. Select the Code-Connected tab, enter Employees as the REST Service Name, and click the Create REST Service button.



Your new API structure is now built and ready to be populated with code.



If you were to make a request from the API now (http://localhost:8080/employees), it would return an error about the GET method not being defined.



So lets define the methods for our new API. We'll start by creating the item entity. We'll use the fields employee_id, name, title, & base_salary. Set the class vars as private, add a getter method for each, and the constructor will set each based on an optionally passed in array. We will do all of this in the module/Company/src/Company/V1/Rest/Employees/EmployeesEntity.php file.
<?php
namespace Company\V1\Rest\Employees;
class EmployeesEntity{
  private $employee_id;
  private $name;
  private $title;
  private $base_salary;
  public function __construct(array $entity = null){
    if($entity !== null && is_array($entity)){
      foreach(array_keys(get_class_vars(__CLASS__)) as $key){
        if(isset($entity[$key])){
           $this->$key = $entity[$key];
         }
      }
    }
  }
  public function getEmployeeId(){
    return $this->employee_id;
  }
  public function getName(){
    return $this->name;
  }
  public function getTitle(){
    return $this->title;
  }
  public function getBaseSalary(){
    return $this->base_salary;
  }
}
Next, we need to edit the module/Company/src/Company/V1/Rest/Employees/EmployeesResource.php file. Normally, you would interface directly with your internal API classes. For the sake of this simple implementation, we will add a getData() method that will return an array of employee information:
private function getData(){
  return array(
    1 => array(
      'employees_id' => 1,
      'name' => 'John Doe',
      'title' => 'Cat Behavior Consultant',
      'base_salary' => 42000
    ),
    2 => array(
      'employees_id' => 2,
      'name' => 'Jane Poe',
      'title' => 'Cheif Bottlewasher',
      'base_salary' => 37000
    ),
    3 => array(
      'employees_id' => 3,
      'name' => 'Robert Roe',
      'title' => 'Town Crier',
      'base_salary' => 14000
    ),
    4 => array(
      'employees_id' => 4,
      'name' => 'Mark Moe',
      'title' => 'Creative director, Unicorn Division',
      'base_salary' => 73000
    ),
    5 => array(
      'employees_id' => 5,
      'name' => 'Brett Boe',
      'title' => 'Executive Moonshiner',
      'base_salary' => 58000
    )
  );
}
Next, we need to modify the fetch method to retrieve the correct employee entity based on the passed employee_id. In this case, we simply:
public function fetch($id){
  if(is_int($id)){
    return new EmployeesEntity($this->getData()[$id]);
  }else{
    return new ApiProblem(405, 'Invalid id passed');
  }
}
Then the fetchAll method. We will get the full dataset and pass it into an ArrayAdapter. We will then pass the adapter into the EmployeesCollection. While it's true we have not implemented any code in the EmployeesCollection, the fact that it extends Zend Paginator gives us the functionality we need to afford API pagination.
public function fetchAll($params = array()){
  $adapter = new ArrayAdapter($this->getData());
  $collection = new EmployeesCollection($adapter);
  return $collection;
}
Since we are using the ArrayAdapter in the fetchAll method, we'll need to include the ArrayAdapter at the top of the file:
use Zend\Paginator\Adapter\ArrayAdapter;

Finally, we need to define a strategy for hydrating the EmployeesEntity. In this case, we simply need to use the ClassMethods hydrator. In the module/Company/config/module.config.php file, locate the zf-hal -> metadata_map -> Company\\V1\\Rest\\Employees\\EmployeesEntity section and add 'hydrator' => 'ClassMethods', directly after the element rout_name like this:
'zf-hal' =>
  array (
    'metadata_map' =>
    array (
      'Company\\V1\\Rest\\Employees\\EmployeesEntity' =>
      array (
        'identifier_name' => 'employees_id',
        'route_name' => 'company.rest.employees',
        'hydrator' => 'ClassMethods',
      ),


That should be it! You now have a working Apigility Api. In my next post, I'll dig a bit more into tying this directly into your internal Api class structure, as well as some tips on easing the job of interacting with your new API using a great Chrome extension Advanced REST Client.