Skip to content

Commit

Permalink
Add scheduler and launcher basic support (#7)
Browse files Browse the repository at this point in the history
US54114 alertlogic-cli: scheduler, launcher basic support
* Add scheduler commands to list/scan hosts
* Add launcher commands to show deployment status
  • Loading branch information
Alexei Osin authored and Anton Benkevich committed Jun 13, 2017
1 parent 174a1e3 commit ce67f58
Show file tree
Hide file tree
Showing 12 changed files with 1,748 additions and 46 deletions.
422 changes: 422 additions & 0 deletions alertlogic/api_data/launcher.json

Large diffs are not rendered by default.

760 changes: 760 additions & 0 deletions alertlogic/api_data/scan_scheduler.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions alertlogic/api_data/update.sh
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#! /bin/bash

# space separted list of services
APIS="sources"
APIS="sources scan_scheduler launcher"
URL="https://console.cloudinsight.alertlogic.com/api"

for api in $APIS; do
for api in $APIS; do
echo -ne "fetching api_data: ${api} ... "
dest="$(dirname $0)/${api}.json"
curl -s ${URL}/${api}/api_data.json -o ${dest}.tmp
Expand Down
47 changes: 34 additions & 13 deletions alertlogic/dynapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
import json
import logging
import os.path
import urllib, urlparse

API_DATA_DIR = os.path.abspath(os.path.dirname(__file__)+"/api_data")

API_SERVICES = ["sources"]
API_SERVICES = ["sources", "scan_scheduler", "launcher"]

log = logging.getLogger()

Expand Down Expand Up @@ -133,18 +134,10 @@ def parse_url(self, url_args):
"/scheduler/v1/12345678/BA395435-551B-4250-B52E-71FCCFF73124/scan?asset=/aws/us-east-1/host/i-023c7629"
:param url_args: dict with values to replace url parameters
"""
parts = [part for part in self.url.lower().split("/") if len(part) > 0]
parsed_url = ""
for part in parts:
if part.startswith(":"):
required_arg = part[1:] # removes ":" at the beginning of the string
if required_arg in url_args:
parsed_url += "/"+url_args[required_arg]
else:
raise InvalidEndpointCall("missing required url argument {}".format(required_arg))
else:
parsed_url += "/"+part
return parsed_url
parsed = list(urlparse.urlparse(self.url.lower()))
parsed[2] = substitute_path_args(parsed[2], url_args)
parsed[4] = substitute_query_args(parsed[4], url_args)
return urlparse.urlunparse(parsed)

def call(self, session, url_args, json=None):
"""parses the url (see parse_url()), and makes an http call, uses session as requests auth plugin
Expand All @@ -155,3 +148,31 @@ def call(self, session, url_args, json=None):
parsed_url = session.api_endpoint + self.parse_url(url_args)
log.debug("calling requests: operation={} url={} json={}".format(self.operation, parsed_url, json))
return requests.request(self.operation, parsed_url, json=json, auth=session)

def substitute_path_args(path, args):
parts = [part for part in path.lower().split("/") if len(part) > 0]
substituted = ""
for part in parts:
if part.startswith(":"):
required_arg = part[1:] # removes ":" at the beginning of the string
if required_arg in args:
substituted += "/" + args[required_arg]
else:
raise InvalidEndpointCall("missing required url argument {}".format(required_arg))
else:
substituted += "/" + part
return substituted

def substitute_query_args(query, args):
parsed = urlparse.parse_qs(query)
for key in parsed:
value = parsed[key][0]
if value.startswith(":"):
required_arg = value[1:] # removes ":" at the beginning of the string
if required_arg in args:
parsed[key] = args[required_arg]
else:
raise InvalidEndpointCall("missing required url argument {}".format(required_arg))
substituted = urllib.urlencode(parsed)
substituted = urllib.unquote_plus(substituted)
return substituted
1 change: 1 addition & 0 deletions alertlogiccli/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import inspect
from abc import ABCMeta, abstractmethod


class CLIModule:
"""Base class to represent comamnd line interface module
At the moment each command belongs to a module defining scope of command.
Expand Down
7 changes: 3 additions & 4 deletions alertlogiccli/commands/environment/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ class Environments(CLIModule):

@classmethod
def get_parser(cls, subparsers):
parser_environment = subparsers.add_parser(cls.command, help="environment specific actions")
subparsers_environment = parser_environment.add_subparsers(dest="subcommand")

return subparsers_environment
parser = subparsers.add_parser(cls.command, help="environment specific actions")
parser.add_argument("-e", "--environment_id", help="environment id (uuid)")
return parser.add_subparsers(dest="subcommand")
46 changes: 46 additions & 0 deletions alertlogiccli/commands/environment/deployment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# This module defines commands to manipulate scheduler queues for a given environment

from alertlogiccli.commands import CLICommand
from alertlogiccli.commands import InvalidHTTPResponse, InvalidParameter, InvalidServiceResponse
import requests
import json

class ListDeployedResourcesCommand(CLICommand):
"""Command to list security infrastructure resources deployed to a given environment"""
command = "list_deployed_resources"
def __init__(self, services):
CLICommand.__init__(self, services)

@classmethod
def get_parser(cls, subparsers):
cmd_help = "lists security infrastructure resources deployed to a given environment"
parser = subparsers.add_parser(cls.command, help=cmd_help)

def execute(self, environment_id, **kwargs):
try:
response = self.services.launcher.getawsresourcesbyenvironment(environment_id=environment_id)
response.raise_for_status()
except requests.exceptions.HTTPError as e:
raise InvalidHTTPResponse(self.command, e.message)
content = response.json()
return json.dumps(content, sort_keys=True, indent=4)

class GetDeploymentStatusCommand(CLICommand):
"""Command to get deployment status for a given environment"""
command = "get_deployment_status"
def __init__(self, services):
CLICommand.__init__(self, services)

@classmethod
def get_parser(cls, subparsers):
cmd_help = "gets deployment status for a given environment"
parser = subparsers.add_parser(cls.command, help=cmd_help)

def execute(self, environment_id, **kwargs):
try:
response = self.services.launcher.getdeploymentstatus(environment_id=environment_id)
response.raise_for_status()
except requests.exceptions.HTTPError as e:
raise InvalidHTTPResponse(self.command, e.message)
content = response.json()
return json.dumps(content, sort_keys=True, indent=4)
15 changes: 5 additions & 10 deletions alertlogiccli/commands/environment/deployment_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ def __init__(self, services):
@classmethod
def get_parser(cls, subparsers):
parser_get_deployment_mode = subparsers.add_parser(cls.command, help="gets environment deployment mode")
parser_get_deployment_mode.add_argument("-e", "--environment_id", help="environment id (uuid)")


def execute(self, environment_id=None, **kwargs):
response = self.validate_environment(self.services, environment_id)
Expand All @@ -56,17 +54,14 @@ def __init__(self, services):
@classmethod
def get_parser(cls, subparsers):
parser_set_deployment_mode = subparsers.add_parser(cls.command, help="sets environment deployment mode")
parser_set_deployment_mode.add_argument("-e", "--environment_id", help="environment id (uuid)")
parser_set_deployment_mode.add_argument("-m", "--deployment_mode", required=True,
choices=["readonly", "automatic"])
parser_set_deployment_mode.add_argument("-m", "--mode", required=True, choices=["readonly", "automatic"])

def execute(self, environment_id=None, deployment_mode=None, **kwargs):
def execute(self, environment_id=None, mode=None, **kwargs):
response = self.validate_environment(self.services, environment_id)
try:
new_config = { "source": { "config": { "deployment_mode": deployment_mode } } }
new_config = { "source": { "config": { "deployment_mode": mode } } }
response = self.services.sources.merge_source(id=environment_id, json=new_config)
response.raise_for_status()
except requests.exceptions.HTTPError as e:
raise InvalidHTTPResponse("update deployment mode", e.message)

return "ok"
raise InvalidHTTPResponse("set_deployment_mode", e.message)
return "ok"
60 changes: 60 additions & 0 deletions alertlogiccli/commands/environment/scan_queue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# This module defines commands to manipulate scheduler queues for a given environment

from alertlogiccli.commands import CLICommand
from alertlogiccli.commands import InvalidHTTPResponse, InvalidParameter, InvalidServiceResponse
import requests
import json

class ListScanQueuesCommand(CLICommand):
"""List hosts in scan queues for a given environment"""
command = "list_scan_queues"
def __init__(self, services):
CLICommand.__init__(self, services)

@classmethod
def get_parser(cls, subparsers):
cmd_help = "lists hosts in scan queues for a given environment"
parser = subparsers.add_parser(cls.command, help=cmd_help)
parser.add_argument("--vpc_key", help="filter hosts for a given VPC")

def execute(self, environment_id, vpc_key=None, **kwargs):
try:
response = self.services.scan_scheduler.listscanassets(environment_id=environment_id)
response.raise_for_status()
except requests.exceptions.HTTPError as e:
raise InvalidHTTPResponse(self.command, e.message)
content = response.json()
regular = group_by_vpc(content["assets"], vpc_key)
immediate = group_by_vpc(content["immediate"], vpc_key)
result = {"regular": regular, "immediate": immediate}
return json.dumps(result, sort_keys=True, indent=4)

class ScanHostCommand(CLICommand):
"""Puts a host to the immediate scan queue"""
command = "scan_host"
def __init__(self, services):
CLICommand.__init__(self, services)

@classmethod
def get_parser(cls, subparsers):
cmd_help = "puts a host in the immediate scan queue"
parser = subparsers.add_parser(cls.command, help=cmd_help)
parser.add_argument("--host_key", required=True, help="a host key to put in the queue")

def execute(self, environment_id, host_key, **kwargs):
try:
response = self.services.scan_scheduler.scanasset(environment_id=environment_id, asset_key=host_key)
response.raise_for_status()
except requests.exceptions.HTTPError as e:
raise InvalidHTTPResponse(self.command, e.message)
return "ok"

def group_by_vpc(assets, filter_vpc_key):
acc = {}
for asset in assets:
vpc_key = asset["vpc"]
if not filter_vpc_key or filter_vpc_key == vpc_key:
group = acc.get(vpc_key, {"vpc": vpc_key, "hosts": []})
group["hosts"].append(asset)
acc[vpc_key] = group
return acc.values()
82 changes: 65 additions & 17 deletions share/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,68 @@ datacenter = us

## Usage

alertlogic-cli currently supports the following commands and subcommands:

### `environment`:
* `set_deployment_mode`: for a given environment changes deployment mode between readonly or manual, usage:
``` set_deployment_mode <environment_id> <readonly|manual>```, example:
``` bash
$ alertlogic-cli environment set_deployment_mode --environment_id 0D2CD709-F70B-4584-A544-B209CEC8F99A --deployment_mode readonly
ok
```
* `get_deployment_mode`: for a given environment gets current deployment mode, usage:
``` get_deployment_mode <environment_id>```, example:
``` bash
$ alertlogic-cli environment get_deployment_mode --environment_id 0D2CD709-F70B-4584-A544-B209CEC8F99A
readonly
```

For further information run `alertlogic-cli --help`.
Alert Logic CLI currently supports the following commands and subcommands:

1. `environment` - groups the environment related operations

Options available:

* `--environment_id ENVIRONMENT_ID` - to point on a customer environment

Operations available:

* `set_deployment_mode` - changes environment deployment mode between readonly or manual

Options available:

`--mode {readonly,automatic}` - deployment mode needed

Example:
``` bash
$ alertlogic-cli environment --environment_id 00000000-0000-0000-0000-000000000000 set_deployment_mode --mode readonly
```

* `get_deployment_mode` - shows environment deployment mode:

Example:
``` bash
$ alertlogic-cli environment --environment_id 00000000-0000-0000-0000-000000000000 get_deployment_mode
```

* `get_deployment_status` - gets deployment status for a given environment

Example:
``` bash
$ alertlogic-cli environment --environment_id 00000000-0000-0000-0000-000000000000 get_deployment_status
```

* `list_deployed_resources` - lists security infrastructure resources deployed

Example:
``` bash
$ alertlogic-cli environment --environment_id 00000000-0000-0000-0000-000000000000 list_deployed_resources
```

* `list_scan_queues` - lists hosts in scan queues for a given environment

Options available:

`--vpc_key VPC_KEY` - filter hosts for a given VPC

Example:
``` bash
$ alertlogic-cli environment --environment_id 00000000-0000-0000-0000-000000000000 list_scan_queues
```

* `scan_host` - puts a host in the immediate scan queue

Options available:

`--host_key HOST_KEY` - a host to put in the queue

Example:
``` bash
$ alertlogic-cli environment --environment_id 00000000-0000-0000-0000-000000000000 scan_host --host_key /aws/us-east-1/host/i-00000000000000000
```

For further information run `alertlogic-cli --help`.
Loading

0 comments on commit ce67f58

Please sign in to comment.