Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 37490fc

Browse files
authoredJul 18, 2017
refactor configuration; make base installation more light-weight; lazy load libraries (localstack#177)
1 parent 8a55937 commit 37490fc

12 files changed

+72
-97
lines changed
 

‎LICENSE.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
Copyright @ 2016 - 2016 Atlassian Pty Ltd
1+
Copyright (c) 2017 LocalStack contributors
2+
Copyright (c) 2016 Atlassian Pty Ltd
23

34
Licensed under the Apache License, Version 2.0 (the "License");
45
you may not use this file except in compliance with the License.

‎Makefile

+2-25
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,20 @@ IMAGE_NAME_BASE ?= localstack/java-maven-node-python
33
IMAGE_TAG ?= $(shell cat localstack/constants.py | grep '^VERSION =' | sed "s/VERSION = ['\"]\(.*\)['\"].*/\1/")
44
VENV_DIR ?= .venv
55
VENV_RUN = . $(VENV_DIR)/bin/activate
6-
AWS_STS_URL = http://central.maven.org/maven2/com/amazonaws/aws-java-sdk-sts/1.11.14/aws-java-sdk-sts-1.11.14.jar
7-
AWS_STS_TMPFILE = $(TMPDIR)aws-java-sdk-sts.jar
8-
LOCALSTACK_JAR_URL = https://bitbucket.org/atlassian/localstack/raw/mvn/release/com/atlassian/localstack-utils/1.0-SNAPSHOT/localstack-utils-1.0-SNAPSHOT.jar
9-
LOCALSTACK_JAR_PATH = localstack/infra/localstack-utils.jar
106
PIP_CMD ?= pip
117

128
usage: ## Show this help
139
@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//'
1410

15-
install: ## Install npm/pip dependencies, compile code
16-
make setup-venv && \
17-
make install-libs && \
18-
make compile
19-
20-
setup-venv: # Setup virtualenv
11+
install: ## Install dependencies in virtualenv
2112
(test `which virtualenv` || $(PIP_CMD) install --user virtualenv) && \
2213
(test -e $(VENV_DIR) || virtualenv $(VENV_OPTS) $(VENV_DIR)) && \
2314
($(VENV_RUN) && $(PIP_CMD) install --upgrade pip) && \
2415
(test ! -e requirements.txt || ($(VENV_RUN); $(PIP_CMD) install six==1.10.0 ; $(PIP_CMD) install -r requirements.txt))
2516

26-
install-libs: ## Install npm/pip dependencies
27-
(test -e localstack/infra/amazon-kinesis-client/aws-java-sdk-sts.jar || \
28-
{ (test -e $(AWS_STS_TMPFILE) || curl -o $(AWS_STS_TMPFILE) $(AWS_STS_URL)); \
29-
mkdir -p localstack/infra/amazon-kinesis-client; \
30-
cp $(AWS_STS_TMPFILE) localstack/infra/amazon-kinesis-client/aws-java-sdk-sts.jar; }) && \
31-
(test -e $(LOCALSTACK_JAR_PATH) || curl -o $(LOCALSTACK_JAR_PATH) $(LOCALSTACK_JAR_URL))
32-
3317
install-web: ## Install npm dependencies for dashboard Web UI
3418
(cd localstack/dashboard/web && (test ! -e package.json || npm install --silent > /dev/null))
3519

36-
compile: ## Compile Java code (KCL library utils, Java Lambda executor)
37-
echo "Compiling"
38-
javac -cp $(shell $(VENV_RUN); python -c 'from localstack.utils.kinesis import kclipy_helper; print(kclipy_helper.get_kcl_classpath())') localstack/utils/kinesis/java/com/atlassian/*.java
39-
(test ! -e localstack/ext/java || (cd localstack/ext/java && mvn -q -DskipTests package))
40-
4120
publish: ## Publish the library to the central PyPi repository
4221
# build and upload archive
4322
($(VENV_RUN) && ./setup.py sdist upload)
@@ -111,7 +90,5 @@ clean: ## Clean up (npm dependencies, downloaded infrastructure code
11190
rm -rf localstack/node_modules/
11291
rm -rf $(VENV_DIR)
11392
rm -f localstack/utils/kinesis/java/com/atlassian/*.class
114-
rm -f $(AWS_STS_TMPFILE)
115-
rm -f $(TMPDIR)localstack.es.zip
11693

117-
.PHONY: usage compile clean install web install-web infra test install-libs
94+
.PHONY: usage compile clean install web install-web infra test

‎README.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ localstack web
291291

292292
## Change Log
293293

294+
* v0.6.2: Major refactoring of installation process, lazy loading of dependencies
294295
* v0.6.1: Add CORS headers; platform compatibility fixes (remove shell commands and sh module); add CloudFormation validate-template; fix Lambda execution in Docker; basic domain handling in ES API; API Gateway authorizers
295296
* v0.6.0: Load services as plugins; fix service default ports; fix SQS->SNS and MD5 of message attributes; fix Host header for S3
296297
* v0.5.5: Enable SSL encryption for all service endpoints (`USE_SSL` config); create Docker base image; fix issue with DATA_DIR
@@ -353,9 +354,12 @@ individual developer who contributes code to this repository. Please refer to th
353354

354355
## License
355356

357+
Copyright (c) 2017 *LocalStack* contributors.
358+
356359
Copyright (c) 2016 Atlassian and others.
357360

358-
*LocalStack* is released under the Apache License, Version 2.0 (see LICENSE.txt).
361+
This version of *LocalStack* is released under the Apache License,
362+
Version 2.0 (see LICENSE.txt).
359363

360364
We build on a number of third-party software tools, with the following licenses:
361365

@@ -377,8 +381,6 @@ pep8 | Expat license
377381
requests | Apache License 2.0
378382
subprocess32 | PSF License
379383
**Node.js/npm modules:** |
380-
dynalite | MIT License
381384
kinesalite | MIT License
382385
**Other tools:** |
383386
Elasticsearch | Apache License 2.0
384-

‎localstack/constants.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import sys
33

44
# LocalStack version
5-
VERSION = '0.6.1'
5+
VERSION = '0.6.2'
66

77
# default AWS region
88
if 'DEFAULT_REGION' not in os.environ:

‎localstack/services/firehose/firehose_api.py

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from localstack.constants import *
1717
from localstack.services.generic_proxy import GenericProxy
1818
from localstack.utils.common import short_uid, to_str
19-
from localstack.utils.testutil import get_s3_client
2019
from localstack.utils.aws.aws_stack import *
2120
from six import iteritems
2221

‎localstack/services/infra.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import six
1313
import warnings
1414
import pkgutil
15-
from localstack import constants
15+
from localstack import constants, config
1616
from localstack.config import *
1717
from localstack.utils.aws import aws_stack
1818
from localstack.utils import common, persistence
@@ -92,16 +92,14 @@ def load_plugins():
9292

9393
loaded_files = []
9494
for module in pkgutil.iter_modules():
95+
file_path = None
9596
if six.PY3 and not isinstance(module, tuple):
9697
file_path = '%s/%s/plugins.py' % (module.module_finder.path, module.name)
97-
if file_path not in loaded_files:
98-
load_plugin_from_path(file_path)
99-
loaded_files.append(file_path)
10098
elif six.PY3 or isinstance(module[0], pkgutil.ImpImporter):
10199
file_path = '%s/%s/plugins.py' % (module[0].path, module[1])
102-
if file_path not in loaded_files:
103-
load_plugin_from_path(file_path)
104-
loaded_files.append(file_path)
100+
if file_path and file_path not in loaded_files:
101+
load_plugin_from_path(file_path)
102+
loaded_files.append(file_path)
105103

106104

107105
# -----------------
@@ -315,7 +313,7 @@ def start_infra(async=False, apis=None):
315313
LOGGER.setLevel(logging.INFO)
316314

317315
if not apis:
318-
apis = list(SERVICE_PORTS.keys())
316+
apis = list(config.SERVICE_PORTS.keys())
319317
# set environment
320318
os.environ['AWS_REGION'] = DEFAULT_REGION
321319
os.environ['ENV'] = ENV_DEV

‎localstack/services/install.py

+41-8
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22

33
import os
44
import sys
5+
import glob
6+
import shutil
57
import logging
68
from localstack.constants import DEFAULT_SERVICE_PORTS, ELASTICSEARCH_JAR_URL, DYNAMODB_JAR_URL
79
from localstack.config import *
8-
from localstack.utils.common import download, parallelize, run
9-
10+
from localstack.utils.common import download, parallelize, run, mkdir
1011

1112
THIS_PATH = os.path.dirname(os.path.realpath(__file__))
1213
ROOT_PATH = os.path.realpath(os.path.join(THIS_PATH, '..'))
@@ -15,9 +16,17 @@
1516
INSTALL_DIR_NPM = '%s/node_modules' % ROOT_PATH
1617
INSTALL_DIR_ES = '%s/elasticsearch' % INSTALL_DIR_INFRA
1718
INSTALL_DIR_DDB = '%s/dynamodb' % INSTALL_DIR_INFRA
19+
INSTALL_DIR_KCL = '%s/amazon-kinesis-client' % INSTALL_DIR_INFRA
20+
INSTALL_PATH_LOCALSTACK_JAR = '%s/localstack-utils.jar' % INSTALL_DIR_INFRA
1821
TMP_ARCHIVE_ES = os.path.join(tempfile.gettempdir(), 'localstack.es.zip')
1922
TMP_ARCHIVE_DDB = os.path.join(tempfile.gettempdir(), 'localstack.ddb.zip')
23+
TMP_ARCHIVE_STS = os.path.join(tempfile.gettempdir(), 'aws-java-sdk-sts.jar')
24+
URL_STS_JAR = 'http://central.maven.org/maven2/com/amazonaws/aws-java-sdk-sts/1.11.14/aws-java-sdk-sts-1.11.14.jar'
25+
URL_LOCALSTACK_JAR = ('https://bitbucket.org/atlassian/localstack/raw/mvn/release/' +
26+
'com/atlassian/localstack-utils/1.0-SNAPSHOT/localstack-utils-1.0-SNAPSHOT.jar')
2027

28+
# list of additional pip packages to install
29+
EXTENDED_PIP_LIBS = ['amazon_kclpy==1.4.4']
2130

2231
# set up logger
2332
LOGGER = logging.getLogger(os.path.basename(__file__))
@@ -34,10 +43,6 @@ def install_elasticsearch():
3443
for dir_name in ('data', 'logs', 'modules', 'plugins', 'config/scripts'):
3544
cmd = 'cd %s && mkdir -p %s && chmod -R 777 %s'
3645
run(cmd % (INSTALL_DIR_ES, dir_name, dir_name))
37-
# install plugins
38-
# TODO remove
39-
# cmd = 'echo y | %s/bin/elasticsearch-plugin install x-pack'
40-
# run(cmd % INSTALL_DIR_ES)
4146

4247

4348
def install_kinesalite():
@@ -58,7 +63,7 @@ def is_alpine():
5863
def install_dynamodb_local():
5964
if not os.path.exists(INSTALL_DIR_DDB):
6065
LOGGER.info('Downloading and installing local DynamoDB server. This may take some time.')
61-
run('mkdir -p %s' % INSTALL_DIR_DDB)
66+
mkdir(INSTALL_DIR_DDB)
6267
if not os.path.exists(TMP_ARCHIVE_DDB):
6368
download(DYNAMODB_JAR_URL, TMP_ARCHIVE_DDB)
6469
cmd = 'cd %s && cp %s ddb.zip && unzip -q ddb.zip && rm ddb.zip'
@@ -74,18 +79,46 @@ def install_dynamodb_local():
7479
run("curl -L -o %s/DynamoDBLocal_lib/sqlite4java.jar '%s'" % (INSTALL_DIR_DDB, patched_jar))
7580

7681

82+
def install_amazon_kinesis_libs():
83+
# install KCL/STS JAR files
84+
if not os.path.exists(INSTALL_DIR_KCL):
85+
mkdir(INSTALL_DIR_KCL)
86+
if not os.path.exists(TMP_ARCHIVE_STS):
87+
download(URL_STS_JAR, TMP_ARCHIVE_STS)
88+
shutil.copy(TMP_ARCHIVE_STS, INSTALL_DIR_KCL)
89+
# install LocalStack JAR file
90+
if not os.path.exists(INSTALL_PATH_LOCALSTACK_JAR):
91+
download(URL_LOCALSTACK_JAR, INSTALL_PATH_LOCALSTACK_JAR)
92+
# install extended libs
93+
try:
94+
from amazon_kclpy import kcl
95+
except Exception as e:
96+
for lib in EXTENDED_PIP_LIBS:
97+
run('pip install %s' % lib)
98+
# Compile Java files
99+
from localstack.utils.kinesis import kclipy_helper
100+
classpath = kclipy_helper.get_kcl_classpath()
101+
java_files = '%s/utils/kinesis/java/com/atlassian/*.java' % ROOT_PATH
102+
class_files = '%s/utils/kinesis/java/com/atlassian/*.class' % ROOT_PATH
103+
if not glob.glob(class_files):
104+
run('javac -cp "%s" %s' % (classpath, java_files))
105+
ext_java_dir = '%s/ext/java' % ROOT_PATH
106+
if not glob.glob('%s/target/*.jar' % ext_java_dir):
107+
run('cd "%s"; mvn -DskipTests package' % (ext_java_dir))
108+
109+
77110
def install_component(name):
78111
if name == 'kinesis':
79112
install_kinesalite()
80113
elif name == 'dynamodb':
81-
# install_dynalite()
82114
install_dynamodb_local()
83115
elif name == 'es':
84116
install_elasticsearch()
85117

86118

87119
def install_components(names):
88120
parallelize(install_component, names)
121+
install_amazon_kinesis_libs()
89122

90123

91124
def install_all_components():

‎localstack/utils/aws/aws_stack.py

+8
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,14 @@ def render_velocity_template(template, context, as_json=False):
198198
return replaced
199199

200200

201+
def get_s3_client():
202+
return boto3.resource('s3',
203+
endpoint_url=config.TEST_S3_URL,
204+
config=boto3.session.Config(
205+
s3={'addressing_style': 'path'}),
206+
verify=False)
207+
208+
201209
def get_account_id(account_id=None, env=None):
202210
if account_id:
203211
return account_id

‎localstack/utils/common.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
LOGGER = logging.getLogger(__name__)
4848

4949

50-
# Helper class to convert JSON documents with datetime or decimals.
50+
# Helper class to convert JSON documents with datetime, decimals, or bytes.
5151
class CustomEncoder(json.JSONEncoder):
5252
def default(self, o):
5353
if isinstance(o, decimal.Decimal):
@@ -57,6 +57,8 @@ def default(self, o):
5757
return int(o)
5858
if isinstance(o, datetime):
5959
return str(o)
60+
if isinstance(o, six.binary_type):
61+
return to_str(o)
6062
return super(CustomEncoder, self).default(o)
6163

6264

‎localstack/utils/testutil.py

+1-9
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,6 @@ def find_recursive(key, value, obj):
183183
return False
184184

185185

186-
def get_s3_client():
187-
return boto3.resource('s3',
188-
endpoint_url=TEST_S3_URL,
189-
config=boto3.session.Config(
190-
s3={'addressing_style': 'path'}),
191-
verify=False)
192-
193-
194186
def list_all_s3_objects():
195187
return map_all_s3_objects().values()
196188

@@ -203,7 +195,7 @@ def download_s3_object(s3, bucket, path):
203195

204196

205197
def map_all_s3_objects(to_json=True):
206-
s3_client = get_s3_client()
198+
s3_client = aws_stack.get_s3_client()
207199
result = {}
208200
for bucket in s3_client.buckets.all():
209201
for key in bucket.objects.all():

‎requirements.txt

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
airspeed==0.5.5.dev20160812
2-
amazon_kclpy==1.4.4
32
awscli==1.11.86
43
boto==2.46.1
54
boto3==1.4.4
@@ -10,7 +9,7 @@ flask==0.10.1
109
flask-cors==3.0.3
1110
flask_swagger==0.2.12
1211
jsonpath-rw==1.4.0
13-
localstack-ext==0.6.1.4
12+
localstack-ext
1413
moto-ext==1.0.1.4
1514
nose==1.3.7
1615
pep8==1.7.0

‎setup.py

+2-38
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@
55
import os
66
import sys
77
import re
8-
import subprocess
9-
import setuptools
108
from setuptools import find_packages, setup
11-
from setuptools.command.install_lib import install_lib
129

10+
# parameter variables
1311
install_requires = []
1412
dependency_links = []
1513
package_data = {}
@@ -21,9 +19,9 @@
2119
version = re.search(r'^\s*VERSION\s*=\s*[\'"](.+)[\'"]\s*$', constants, re.MULTILINE).group(1)
2220

2321

22+
# determine requirements
2423
with open('requirements.txt') as f:
2524
requirements = f.read()
26-
2725
for line in re.split('\n', requirements):
2826
if line and line[0] == '#' and '#egg=' in line:
2927
line = re.search(r'#\s*(.*)', line).group(1)
@@ -32,37 +30,6 @@
3230
install_requires.append(line)
3331

3432

35-
def do_make_install(workdir=None):
36-
if workdir:
37-
prev_workdir = os.getcwd()
38-
os.chdir(workdir)
39-
try:
40-
subprocess.check_output('make install', shell=True)
41-
except subprocess.CalledProcessError as e:
42-
print(e.output)
43-
raise e
44-
if workdir:
45-
os.chdir(prev_workdir)
46-
47-
48-
class InstallLibCommand(install_lib):
49-
50-
def run(self):
51-
install_lib.run(self)
52-
# prepare filesystem
53-
main_dir_name = 'localstack'
54-
target_dir = '%s/%s' % (self.install_dir, main_dir_name)
55-
infra_dir = '%s/infra' % (main_dir_name)
56-
# delete existing directory
57-
subprocess.check_output('rm -r %s' % (main_dir_name), shell=True)
58-
# create symlink
59-
subprocess.check_output('ln -s %s %s' % (target_dir, main_dir_name), shell=True)
60-
# delete infra directory (if it exists) to force re-install
61-
subprocess.check_output('rm -rf %s' % (infra_dir), shell=True)
62-
# run 'make install'
63-
do_make_install()
64-
65-
6633
package_data = {
6734
'': ['Makefile', '*.md'],
6835
'localstack': [
@@ -94,9 +61,6 @@ def run(self):
9461
dependency_links=dependency_links,
9562
test_suite='tests',
9663
license='Apache License 2.0',
97-
cmdclass={
98-
'install_lib': InstallLibCommand
99-
},
10064
zip_safe=False,
10165
classifiers=[
10266
'Programming Language :: Python :: 2',

0 commit comments

Comments
 (0)