Implement tenant CRUD operations
diff --git a/api-gateway-config/conf.d/management_apis.conf b/api-gateway-config/conf.d/management_apis.conf
index 0d9e30d..47f8ee8 100644
--- a/api-gateway-config/conf.d/management_apis.conf
+++ b/api-gateway-config/conf.d/management_apis.conf
@@ -52,6 +52,25 @@
         }
     }
 
+    location /Tenants {
+        access_by_lua_block {
+            local mgmt = require("management")
+            local requestMethod = ngx.req.get_method()
+            if requestMethod == "GET" then
+                mgmt.getTenants()
+            elseif requestMethod == "PUT" then
+                mgmt.addTenant()
+            elseif requestMethod == "POST" then
+                mgmt.addTenant()
+            elseif requestMethod == "DELETE" then
+                mgmt.deleteTenant()
+            else
+                ngx.status = 400
+                ngx.say("Invalid verb")
+            end
+        }
+    }
+
     location /subscriptions {
          access_by_lua_block {
              local mgmt = require("management")
diff --git a/api-gateway-config/scripts/lua/lib/redis.lua b/api-gateway-config/scripts/lua/lib/redis.lua
index 7ea41b2..2687248 100644
--- a/api-gateway-config/scripts/lua/lib/redis.lua
+++ b/api-gateway-config/scripts/lua/lib/redis.lua
@@ -192,7 +192,7 @@
   return resourceObj
 end
 
---- Delete resource int redis
+--- Delete resource in redis
 -- @param red redis client instance
 -- @param key redis resource key
 -- @param field redis resource field
@@ -213,6 +213,55 @@
 end
 
 -----------------------------
+---------- Tenants ----------
+-----------------------------
+
+--- Add tenant to redis
+-- @param red Redis client instance
+-- @param id id of tenant
+-- @param tenantObj the tenant to add
+function _M.addTenant(red, id, tenantObj)
+  local ok, err = red:hset("tenants", id, tenantObj)
+  if not ok then
+    request.err(500, utils.concatStrings({"Failed adding tenant to redis: ", err}))
+  end
+end
+
+--- Get all tenants from redis
+-- @param red Redis client instance
+function _M.getAllTenants(red)
+  local res, err = red:hgetall("tenants")
+  if not res then
+    request.err(500, utils.concatStrings({"Failed getting tenants from redis: ", err}))
+  end
+  return res
+end
+
+--- Get a single tenant from redis given its id
+-- @param redis Redis client instance
+-- @param id id of tenant to get
+function _M.getTenant(red, id)
+  local tenant, err = red:hget("tenants", id)
+  if not tenant then
+    request.err(500, utils.concatStrings({"Failed getting tenants from redis: ", err}))
+  end
+  if tenant == ngx.null then
+    request.err(404, utils.concatStrings({"Unknown tenant id ", id, "."}))
+  end
+  return cjson.decode(tenant)
+end
+
+--- Delete an tenant from redis given its id
+-- @param redis Redis client instance
+-- @param id id of tenant to delete
+function _M.deleteTenant(red, id)
+  local ok, err = red:hdel("tenants", id)
+  if not ok then
+    request.err(500, utils.concatStrings({"Failed deleting tenant from redis: ", err}))
+  end
+end
+
+-----------------------------
 --- API Key Subscriptions ---
 -----------------------------
 
diff --git a/api-gateway-config/scripts/lua/management.lua b/api-gateway-config/scripts/lua/management.lua
index 8cd3a65..6648007 100644
--- a/api-gateway-config/scripts/lua/management.lua
+++ b/api-gateway-config/scripts/lua/management.lua
@@ -42,7 +42,7 @@
 
 --- Add an api to the Gateway
 -- PUT http://0.0.0.0:9000/APIs
--- PUT JSON body:
+-- body:
 -- {
 --    "name": *(String) name of API
 --    "basePath": *(String) base path for api
@@ -252,7 +252,95 @@
 ---------- Tenants ----------
 -----------------------------
 
+--- Add a tenant to the Gateway
+-- PUT http://0.0.0.0:9000/Tenants
+-- body:
+-- {
+--    "namespace": *(String) tenant namespace
+--    "instance": *(String) tenant instance
+-- }
+function _M.addTenant()
+  -- Read in the PUT JSON Body
+  ngx.req.read_body()
+  local args = ngx.req.get_body_data()
+  if not args then
+    request.err(400, "Missing request body")
+  end
+  -- Convert json into Lua table
+  local decoded = cjson.decode(args)
+  -- Error checking
+  local fields = {"namespace", "instance"}
+  for k, v in pairs(fields) do
+    if not decoded[v] then
+      request.err(400, utils.concatStrings({"Missing field '", v, "' in request body."}))
+    end
+  end
+  -- Generate random uuid for tenant
+  local uuid = utils.uuid()
+  local tenantObj = {
+    id = uuid,
+    namespace = decoded.namespace,
+    instance = decoded.instance
+  }
+  tenantObj = cjson.encode(tenantObj)
+  local red = redis.init(REDIS_HOST, REDIS_PORT, REDIS_PASS, 1000)
+  redis.addTenant(red, uuid, tenantObj)
+  redis.close(red)
+  ngx.header.content_type = "application/json; charset=utf-8"
+  request.success(200, tenantObj)
+end
 
+--- Get one or all tenants from the gateway
+-- PUT http://0.0.0.0:9000/Tenants
+function _M.getTenants()
+  local uri = string.gsub(ngx.var.request_uri, "?.*", "")
+  if uri:len() <= 9 then
+    getAllTenants()
+  else
+    local id = uri:sub(10)
+    getTenant(id)
+  end
+end
+
+--- Get all tenants in redis
+function getAllTenants()
+  local red = redis.init(REDIS_HOST, REDIS_PORT, REDIS_PASS, 1000)
+  local res = redis.getAllTenants(red)
+  redis.close(red)
+  local tenantList = {}
+  for k, v in pairs(res) do
+    if k%2 == 0 then
+      tenantList[#tenantList+1] = cjson.decode(v)
+    end
+  end
+  tenantList = cjson.encode(tenantList)
+  ngx.header.content_type = "application/json; charset=utf-8"
+  request.success(200, tenantList)
+end
+
+--- Get tenant by its id
+-- @param id
+function getTenant(id)
+  local red = redis.init(REDIS_HOST, REDIS_PORT, REDIS_PASS, 1000)
+  local tenant = redis.getTenant(red, id)
+  redis.close(red)
+  ngx.header.content_type = "application/json; charset=utf-8"
+  request.success(200, cjson.encode(tenant))
+end
+
+--- Delete tenant from gateway
+-- DELETE http://0.0.0.0:9000/Tenants/<id>
+function _M.deleteTenant()
+  local uri = string.gsub(ngx.var.request_uri, "?.*", "")
+  if uri:len() <= 9 then
+    request.err(400, "No id specified.")
+  end
+  local id = uri:sub(10)
+  local red = redis.init(REDIS_HOST, REDIS_PORT, REDIS_PASS, 1000)
+  redis.deleteTenant(red, id)
+  redis.close(red)
+  request.success(200, {})
+end
 
 ------------------------------
 ----- Pub/Sub with Redis -----