Skip to content

Commit 8e5c80b

Browse files
Tommy WangTommy Wang
authored andcommitted
initial commit
0 parents  commit 8e5c80b

File tree

9 files changed

+664
-0
lines changed

9 files changed

+664
-0
lines changed

.gitignore

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
2+
# Created by https://www.gitignore.io/api/vim,python
3+
4+
### Vim ###
5+
# swap
6+
[._]*.s[a-w][a-z]
7+
[._]s[a-w][a-z]
8+
# session
9+
Session.vim
10+
# temporary
11+
.netrwhist
12+
*~
13+
# auto-generated tag files
14+
tags
15+
16+
17+
### Python ###
18+
# Byte-compiled / optimized / DLL files
19+
__pycache__/
20+
*.py[cod]
21+
*$py.class
22+
23+
# C extensions
24+
*.so
25+
26+
# Distribution / packaging
27+
.Python
28+
env/
29+
build/
30+
develop-eggs/
31+
dist/
32+
downloads/
33+
eggs/
34+
.eggs/
35+
lib/
36+
lib64/
37+
parts/
38+
sdist/
39+
var/
40+
*.egg-info/
41+
.installed.cfg
42+
*.egg
43+
44+
# PyInstaller
45+
# Usually these files are written by a python script from a template
46+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
47+
*.manifest
48+
*.spec
49+
50+
# Installer logs
51+
pip-log.txt
52+
pip-delete-this-directory.txt
53+
54+
# Unit test / coverage reports
55+
htmlcov/
56+
.tox/
57+
.coverage
58+
.coverage.*
59+
.cache
60+
nosetests.xml
61+
coverage.xml
62+
*,cover
63+
.hypothesis/
64+
65+
# Translations
66+
*.mo
67+
*.pot
68+
69+
# Django stuff:
70+
*.log
71+
local_settings.py
72+
73+
# Flask stuff:
74+
instance/
75+
.webassets-cache
76+
77+
# Scrapy stuff:
78+
.scrapy
79+
80+
# Sphinx documentation
81+
docs/_build/
82+
83+
# PyBuilder
84+
target/
85+
86+
# Jupyter Notebook
87+
.ipynb_checkpoints
88+
89+
# pyenv
90+
.python-version
91+
92+
# celery beat schedule file
93+
celerybeat-schedule
94+
95+
# dotenv
96+
.env
97+
98+
# virtualenv
99+
.venv/
100+
venv/
101+
ENV/
102+
103+
# Spyder project settings
104+
.spyderproject
105+
106+
# Rope project settings
107+
.ropeproject
6.41 KB
Loading

aws.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import os
2+
import sys
3+
4+
from six.moves import configparser
5+
6+
import boto3
7+
import click
8+
from jinja2 import Environment, FileSystemLoader
9+
from workflow import Workflow3
10+
from workflow import (
11+
MATCH_ALL,
12+
MATCH_ALLCHARS,
13+
MATCH_ATOM,
14+
MATCH_CAPITALS,
15+
MATCH_INITIALS,
16+
MATCH_INITIALS_CONTAIN,
17+
MATCH_INITIALS_STARTSWITH,
18+
MATCH_STARTSWITH,
19+
MATCH_SUBSTRING,
20+
)
21+
22+
pass_wf = click.make_pass_decorator(Workflow3)
23+
log = None
24+
25+
26+
def get_ec2_instances():
27+
client = boto3.client('ec2')
28+
next_token = {}
29+
instances = []
30+
while True:
31+
log.debug('calling describe_instances')
32+
response = client.describe_instances(MaxResults=1000, **next_token)
33+
for reservation in response['Reservations']:
34+
for instance in reservation['Instances']:
35+
if 'Tags' in instance:
36+
for tag in instance['Tags']:
37+
instance['Tag:%s' % tag['Key']] = tag['Value']
38+
instances.append(instance)
39+
if 'NextToken' in response:
40+
next_token['NextToken'] = response['NextToken']
41+
else:
42+
break
43+
return instances
44+
45+
46+
def dedupe(lofd, key):
47+
seen = set()
48+
res = []
49+
for d in lofd:
50+
if d[key] not in seen:
51+
seen.add(d[key])
52+
res.append(d)
53+
return res
54+
55+
56+
def find_ec2(wf, profile, quicklook, query):
57+
instances = wf.cached_data('%s-ec2' % profile, get_ec2_instances, max_age=600)
58+
59+
if query:
60+
matched = wf.filter(query, instances, key=lambda i: unicode(i['InstanceId']), match_on=MATCH_STARTSWITH)
61+
matched += wf.filter(query, instances, key=lambda i: i.get('Tag:Name', u''))
62+
# TODO: parse query for facet:query to perform faceted search
63+
# matched += wf.filter(query, instances, key=lambda i: i.get('Tag:Application', u''))
64+
# matched += wf.filter(query, instances, key=lambda i: i.get('Tag:Role', u''))
65+
# matched += wf.filter(query, instances, key=lambda i: i.get('Tag:Vertical', u''))
66+
# matched += wf.filter(query, instances, key=lambda i: i.get('Tag:Vpc', u''))
67+
# matched += wf.filter(query, instances, key=lambda i: i.get('Tag:Environment', u''))
68+
else:
69+
matched = instances
70+
71+
matched = dedupe(matched, 'InstanceId')
72+
73+
for instance in matched:
74+
if 'Tag:Name' in instance:
75+
title = '%s (%s)' % (instance['Tag:Name'], instance['InstanceId'])
76+
else:
77+
title = instance['InstanceId']
78+
uid = '%s-ec2-%s' % (profile, instance['InstanceId'])
79+
valid = instance['State']['Name'] == 'running'
80+
quicklookurl = None
81+
# quicklookurl = quicklook(uid, 'ec2', {
82+
# 'title': title,
83+
# 'uid': uid,
84+
# 'instance': instance,
85+
# })
86+
87+
item = wf.add_item(
88+
title,
89+
subtitle='private ip',
90+
arg=instance.get('PrivateIpAddress', 'N/A'),
91+
valid=valid and 'PrivateIpAddress' in instance,
92+
uid=uid,
93+
icon='icons/ec2.eps',
94+
type='default',
95+
quicklookurl=quicklookurl
96+
)
97+
item.setvar('title', title)
98+
item.add_modifier(
99+
"shift",
100+
subtitle='public ip',
101+
arg=instance.get('PublicIpAddress', 'N/A'),
102+
valid=valid and 'PublicIpAddress' in instance,
103+
)
104+
item.add_modifier(
105+
"cmd",
106+
subtitle='open in console',
107+
arg='https://us-west-2.console.aws.amazon.com/ec2/v2/home?region=us-west-2#Instances:search=%s;sort=instanceState' % instance['InstanceId'],
108+
valid=True,
109+
)
110+
111+
112+
@click.group()
113+
@pass_wf
114+
def cli(wf):
115+
pass
116+
117+
@cli.command()
118+
@pass_wf
119+
def list_profiles(wf):
120+
parser = configparser.ConfigParser()
121+
parser.read(os.path.expanduser('~/.aws/credentials'))
122+
for profile in parser.sections():
123+
wf.add_item(
124+
title=profile,
125+
valid=True,
126+
arg=profile,
127+
)
128+
wf.send_feedback()
129+
130+
@cli.command()
131+
@click.argument('profile')
132+
@pass_wf
133+
def set_profile(wf, profile):
134+
wf.settings['profile'] = profile
135+
136+
@cli.command()
137+
@click.argument('query')
138+
@pass_wf
139+
def search(wf, query):
140+
profile = wf.settings['profile']
141+
if profile is None:
142+
raise Exception('no profile selected')
143+
144+
os.environ['AWS_PROFILE'] = profile
145+
146+
def _quicklook_closure():
147+
env = Environment(loader=FileSystemLoader(os.path.join(wf.workflowdir, 'quicklook')))
148+
def build_quicklook(uid, template, context):
149+
filename = wf.cachefile('%s.html' % uid)
150+
template = env.get_template('%s.html.j2' % template)
151+
with open(filename, 'w') as f:
152+
f.write(template.render(**context))
153+
return filename
154+
return build_quicklook
155+
quicklook = _quicklook_closure()
156+
157+
find_ec2(wf, profile, quicklook, query)
158+
159+
wf.send_feedback()
160+
161+
if __name__ == '__main__':
162+
wf = Workflow3()
163+
log = wf.logger
164+
wf.run(lambda wf: cli(obj=wf, auto_envvar_prefix='WF'))

build.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash -x
2+
virtualenv env
3+
sed -i -e '1 s,^.*$,#!/usr/bin/env python,g' env/bin/pip
4+
source env/bin/activate
5+
pip install --target="$PWD" -r requirements.txt
6+
deactivate
7+
rm -rf env

icon.png

33 KB
Loading

icons/ec2.eps

972 KB
Binary file not shown.

0 commit comments

Comments
 (0)