Initial public commit
This commit is contained in:
commit
0ccf3e1443
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
*.pyc
|
||||
.settings/
|
||||
.venv
|
||||
build/
|
||||
dist/
|
||||
doc/source/sourcecode
|
||||
*.db
|
||||
.*.swp
|
||||
*.log
|
||||
*.pid
|
||||
pidfile
|
||||
*.komodoproject
|
||||
.coverage
|
||||
.DS_Store
|
26
AUTHORS
Normal file
26
AUTHORS
Normal file
@ -0,0 +1,26 @@
|
||||
V2
|
||||
--
|
||||
Joshua Harlow <harlowja@yahoo-inc.com>
|
||||
Ken Thomas <krt@yahoo-inc.com>
|
||||
|
||||
V1
|
||||
--
|
||||
Andy Smith <github@anarkystic.com>
|
||||
Anthony Young <sleepsonthefloor@gmail.com>
|
||||
Brad Hall <brad@nicira.com>
|
||||
Chmouel Boudjnah <chmouel@chmouel.com>
|
||||
Dean Troyer <dtroyer@gmail.com>
|
||||
Devin Carlen <devin.carlen@gmail.com>
|
||||
Eddie Hebert <edhebert@gmail.com>
|
||||
Jake Dahn <admin@jakedahn.com>
|
||||
James E. Blair <james.blair@rackspace.com>
|
||||
Jason Cannavale <jason.cannavale@rackspace.com>
|
||||
Jay Pipes <jaypipes@gmail.com>
|
||||
Jesse Andrews <anotherjesse@gmail.com>
|
||||
Justin Shepherd <galstrom21@gmail.com>
|
||||
Kiall Mac Innes <kiall@managedit.ie>
|
||||
Scott Moser <smoser@ubuntu.com>
|
||||
Todd Willey <xtoddx@gmail.com>
|
||||
Tres Henry <tres@treshenry.net>
|
||||
Vishvananda Ishaya <vishvananda@gmail.com>
|
||||
Yun Mao <yunmao@gmail.com>
|
59
README.md
Normal file
59
README.md
Normal file
@ -0,0 +1,59 @@
|
||||
Devstack v2 is a set of python scripts and utilities to quickly deploy an OpenStack cloud.
|
||||
|
||||
# Goals
|
||||
|
||||
* To quickly build dev OpenStack environments in a clean environment (as well as start, stop, and uninstall those environments)
|
||||
* To describe working configurations of OpenStack (which code branches work together? what do config files look like for those branches? what packages are needed for installation?)
|
||||
* To make it easier for developers to dive into OpenStack so that they can productively contribute without having to understand every part of the system at once
|
||||
* To make it easy to prototype cross-project features
|
||||
|
||||
Read more at <http://devstack.org>
|
||||
|
||||
IMPORTANT: Be sure to carefully read *stack* and any other scripts you execute before you run them, as they install software and may alter your networking configuration. We strongly recommend that you run stack in a clean and disposable vm when you are first getting started.
|
||||
|
||||
# Help
|
||||
|
||||
In order to determine what *stack* can do run the following.
|
||||
|
||||
./stack --help
|
||||
|
||||
This will typically produce:
|
||||
|
||||
$ ./stack --help
|
||||
Usage: stack [options]
|
||||
|
||||
Options:
|
||||
-h, --help show this help message and exit
|
||||
-a ACTION, --action=ACTION
|
||||
action to perform, ie (start, stop, install,
|
||||
uninstall)
|
||||
-d DIR, --directory=DIR
|
||||
root DIR for new components or DIR with existing
|
||||
components (ACTION dependent)
|
||||
-c COMPONENT, --component=COMPONENT
|
||||
stack component, ie (rabbit, db, nova, keystone,
|
||||
horizon, quantum, glance, swift)
|
||||
|
||||
# Actions
|
||||
|
||||
You will note that *stack* can uninstall, install, start and stop openstack components. Typically the interaction would be that you install a set of components and then start them.
|
||||
|
||||
# Config
|
||||
|
||||
If you want to change which devstack branches or other various devstack configurations.
|
||||
Check out *conf/stack.ini* for various configuration settings applied (branches, git repositories...).
|
||||
When you see a configuration in *stack.ini* with the format *${NAME:-DEFAULT}* this means that the environment the *stack* script is running in while be referred to and if that value exists it will be used (otherwise the *DEFAULT* will be used).
|
||||
Also check out *conf/* for various component specific settings and *conf/pkgs* for package listings (with versions) for various distributions.
|
||||
|
||||
# To start a dev cloud (Installing in a dedicated, disposable vm is safer than installing on your dev machine!):
|
||||
|
||||
./stack -a install -d $HOME/openstack && ./stack -a start -d $HOME/openstack
|
||||
|
||||
When the script finishes executing, you should be able to access OpenStack endpoints, like so:
|
||||
|
||||
* Horizon: http://myhost/
|
||||
* Keystone: http://myhost:5000/v2.0/
|
||||
|
||||
# Customizing
|
||||
|
||||
You can override environment variables used in *stack* by editing *stack.ini* or by sourcing a file that contains your overrides before your run *stack*.
|
28
conf/apache/000-default.template
Normal file
28
conf/apache/000-default.template
Normal file
@ -0,0 +1,28 @@
|
||||
<VirtualHost *:80>
|
||||
WSGIScriptAlias / %HORIZON_DIR%/openstack-dashboard/dashboard/wsgi/django.wsgi
|
||||
WSGIDaemonProcess horizon user=%USER% group=%USER% processes=3 threads=10
|
||||
SetEnv APACHE_RUN_USER %USER%
|
||||
SetEnv APACHE_RUN_GROUP %USER%
|
||||
WSGIProcessGroup horizon
|
||||
|
||||
DocumentRoot %HORIZON_DIR%/.blackhole/
|
||||
Alias /media %HORIZON_DIR%/openstack-dashboard/dashboard/static
|
||||
Alias /vpn /opt/stack/vpn
|
||||
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
</Directory>
|
||||
|
||||
<Directory %HORIZON_DIR%/>
|
||||
Options Indexes FollowSymLinks MultiViews
|
||||
AllowOverride None
|
||||
Order allow,deny
|
||||
allow from all
|
||||
</Directory>
|
||||
|
||||
ErrorLog /var/log/apache2/error.log
|
||||
LogLevel warn
|
||||
CustomLog /var/log/apache2/access.log combined
|
||||
</VirtualHost>
|
||||
|
9
conf/apt/sources.list
Normal file
9
conf/apt/sources.list
Normal file
@ -0,0 +1,9 @@
|
||||
deb http://mirror.rackspace.com/ubuntu/ %DIST% main restricted
|
||||
deb http://mirror.rackspace.com/ubuntu/ %DIST%-updates main restricted
|
||||
deb http://mirror.rackspace.com/ubuntu/ %DIST% universe
|
||||
deb http://mirror.rackspace.com/ubuntu/ %DIST%-updates universe
|
||||
deb http://mirror.rackspace.com/ubuntu/ %DIST% multiverse
|
||||
deb http://mirror.rackspace.com/ubuntu/ %DIST%-updates multiverse
|
||||
deb http://security.ubuntu.com/ubuntu %DIST%-security main restricted
|
||||
deb http://security.ubuntu.com/ubuntu %DIST%-security universe
|
||||
deb http://security.ubuntu.com/ubuntu %DIST%-security multiverse
|
184
conf/glance/glance-api.conf
Normal file
184
conf/glance/glance-api.conf
Normal file
@ -0,0 +1,184 @@
|
||||
[DEFAULT]
|
||||
# Show more verbose log output (sets INFO log level output)
|
||||
verbose = True
|
||||
|
||||
# Show debugging output in logs (sets DEBUG log level output)
|
||||
debug = True
|
||||
|
||||
# Which backend store should Glance use by default is not specified
|
||||
# in a request to add a new image to Glance? Default: 'file'
|
||||
# Available choices are 'file', 'swift', and 's3'
|
||||
default_store = file
|
||||
|
||||
# Address to bind the API server
|
||||
bind_host = 0.0.0.0
|
||||
|
||||
# Port the bind the API server to
|
||||
bind_port = 9292
|
||||
|
||||
# Address to find the registry server
|
||||
registry_host = 0.0.0.0
|
||||
|
||||
# Port the registry server is listening on
|
||||
registry_port = 9191
|
||||
|
||||
# Log to this file. Make sure you do not set the same log
|
||||
# file for both the API and registry servers!
|
||||
#log_file = %DEST%/glance/api.log
|
||||
|
||||
# Send logs to syslog (/dev/log) instead of to file specified by `log_file`
|
||||
use_syslog = %SYSLOG%
|
||||
|
||||
# ============ Notification System Options =====================
|
||||
|
||||
# Notifications can be sent when images are create, updated or deleted.
|
||||
# There are three methods of sending notifications, logging (via the
|
||||
# log_file directive), rabbit (via a rabbitmq queue) or noop (no
|
||||
# notifications sent, the default)
|
||||
notifier_strategy = noop
|
||||
|
||||
# Configuration options if sending notifications via rabbitmq (these are
|
||||
# the defaults)
|
||||
rabbit_host = localhost
|
||||
rabbit_port = 5672
|
||||
rabbit_use_ssl = false
|
||||
rabbit_userid = guest
|
||||
rabbit_password = guest
|
||||
rabbit_virtual_host = /
|
||||
rabbit_notification_topic = glance_notifications
|
||||
|
||||
# ============ Filesystem Store Options ========================
|
||||
|
||||
# Directory that the Filesystem backend store
|
||||
# writes image data to
|
||||
filesystem_store_datadir = %DEST%/glance/images/
|
||||
|
||||
# ============ Swift Store Options =============================
|
||||
|
||||
# Address where the Swift authentication service lives
|
||||
swift_store_auth_address = 127.0.0.1:8080/v1.0/
|
||||
|
||||
# User to authenticate against the Swift authentication service
|
||||
swift_store_user = jdoe
|
||||
|
||||
# Auth key for the user authenticating against the
|
||||
# Swift authentication service
|
||||
swift_store_key = a86850deb2742ec3cb41518e26aa2d89
|
||||
|
||||
# Container within the account that the account should use
|
||||
# for storing images in Swift
|
||||
swift_store_container = glance
|
||||
|
||||
# Do we create the container if it does not exist?
|
||||
swift_store_create_container_on_put = False
|
||||
|
||||
# What size, in MB, should Glance start chunking image files
|
||||
# and do a large object manifest in Swift? By default, this is
|
||||
# the maximum object size in Swift, which is 5GB
|
||||
swift_store_large_object_size = 5120
|
||||
|
||||
# When doing a large object manifest, what size, in MB, should
|
||||
# Glance write chunks to Swift? This amount of data is written
|
||||
# to a temporary disk buffer during the process of chunking
|
||||
# the image file, and the default is 200MB
|
||||
swift_store_large_object_chunk_size = 200
|
||||
|
||||
# Whether to use ServiceNET to communicate with the Swift storage servers.
|
||||
# (If you aren't RACKSPACE, leave this False!)
|
||||
#
|
||||
# To use ServiceNET for authentication, prefix hostname of
|
||||
# `swift_store_auth_address` with 'snet-'.
|
||||
# Ex. https://example.com/v1.0/ -> https://snet-example.com/v1.0/
|
||||
swift_enable_snet = False
|
||||
|
||||
# ============ S3 Store Options =============================
|
||||
|
||||
# Address where the S3 authentication service lives
|
||||
s3_store_host = 127.0.0.1:8080/v1.0/
|
||||
|
||||
# User to authenticate against the S3 authentication service
|
||||
s3_store_access_key = <20-char AWS access key>
|
||||
|
||||
# Auth key for the user authenticating against the
|
||||
# S3 authentication service
|
||||
s3_store_secret_key = <40-char AWS secret key>
|
||||
|
||||
# Container within the account that the account should use
|
||||
# for storing images in S3. Note that S3 has a flat namespace,
|
||||
# so you need a unique bucket name for your glance images. An
|
||||
# easy way to do this is append your AWS access key to "glance".
|
||||
# S3 buckets in AWS *must* be lowercased, so remember to lowercase
|
||||
# your AWS access key if you use it in your bucket name below!
|
||||
s3_store_bucket = <lowercased 20-char aws access key>glance
|
||||
|
||||
# Do we create the bucket if it does not exist?
|
||||
s3_store_create_bucket_on_put = False
|
||||
|
||||
# ============ Image Cache Options ========================
|
||||
|
||||
image_cache_enabled = False
|
||||
|
||||
# Directory that the Image Cache writes data to
|
||||
# Make sure this is also set in glance-pruner.conf
|
||||
image_cache_datadir = /var/lib/glance/image-cache/
|
||||
|
||||
# Number of seconds after which we should consider an incomplete image to be
|
||||
# stalled and eligible for reaping
|
||||
image_cache_stall_timeout = 86400
|
||||
|
||||
# ============ Delayed Delete Options =============================
|
||||
|
||||
# Turn on/off delayed delete
|
||||
delayed_delete = False
|
||||
|
||||
# Delayed delete time in seconds
|
||||
scrub_time = 43200
|
||||
|
||||
# Directory that the scrubber will use to remind itself of what to delete
|
||||
# Make sure this is also set in glance-scrubber.conf
|
||||
scrubber_datadir = /var/lib/glance/scrubber
|
||||
|
||||
[pipeline:glance-api]
|
||||
#pipeline = versionnegotiation context apiv1app
|
||||
# NOTE: use the following pipeline for keystone
|
||||
pipeline = versionnegotiation authtoken auth-context apiv1app
|
||||
|
||||
# To enable Image Cache Management API replace pipeline with below:
|
||||
# pipeline = versionnegotiation context imagecache apiv1app
|
||||
# NOTE: use the following pipeline for keystone auth (with caching)
|
||||
# pipeline = versionnegotiation authtoken auth-context imagecache apiv1app
|
||||
|
||||
[app:apiv1app]
|
||||
paste.app_factory = glance.common.wsgi:app_factory
|
||||
glance.app_factory = glance.api.v1.router:API
|
||||
|
||||
[filter:versionnegotiation]
|
||||
paste.filter_factory = glance.common.wsgi:filter_factory
|
||||
glance.filter_factory = glance.api.middleware.version_negotiation:VersionNegotiationFilter
|
||||
|
||||
[filter:cache]
|
||||
paste.filter_factory = glance.common.wsgi:filter_factory
|
||||
glance.filter_factory = glance.api.middleware.cache:CacheFilter
|
||||
|
||||
[filter:cachemanage]
|
||||
paste.filter_factory = glance.common.wsgi:filter_factory
|
||||
glance.filter_factory = glance.api.middleware.cache_manage:CacheManageFilter
|
||||
|
||||
[filter:context]
|
||||
paste.filter_factory = glance.common.wsgi:filter_factory
|
||||
glance.filter_factory = glance.common.context:ContextMiddleware
|
||||
|
||||
[filter:authtoken]
|
||||
paste.filter_factory = keystone.middleware.auth_token:filter_factory
|
||||
service_protocol = http
|
||||
service_host = 127.0.0.1
|
||||
service_port = 5000
|
||||
auth_host = 127.0.0.1
|
||||
auth_port = 35357
|
||||
auth_protocol = http
|
||||
auth_uri = http://127.0.0.1:5000/
|
||||
admin_token = %SERVICE_TOKEN%
|
||||
|
||||
[filter:auth-context]
|
||||
paste.filter_factory = glance.common.wsgi:filter_factory
|
||||
glance.filter_factory = keystone.middleware.glance_auth_token:KeystoneContextMiddleware
|
74
conf/glance/glance-registry.conf
Normal file
74
conf/glance/glance-registry.conf
Normal file
@ -0,0 +1,74 @@
|
||||
[DEFAULT]
|
||||
# Show more verbose log output (sets INFO log level output)
|
||||
verbose = True
|
||||
|
||||
# Show debugging output in logs (sets DEBUG log level output)
|
||||
debug = True
|
||||
|
||||
# Address to bind the registry server
|
||||
bind_host = 0.0.0.0
|
||||
|
||||
# Port the bind the registry server to
|
||||
bind_port = 9191
|
||||
|
||||
# Log to this file. Make sure you do not set the same log
|
||||
# file for both the API and registry servers!
|
||||
#log_file = %DEST%/glance/registry.log
|
||||
|
||||
# Where to store images
|
||||
filesystem_store_datadir = %DEST%/glance/images
|
||||
|
||||
# Send logs to syslog (/dev/log) instead of to file specified by `log_file`
|
||||
use_syslog = %SYSLOG%
|
||||
|
||||
# SQLAlchemy connection string for the reference implementation
|
||||
# registry server. Any valid SQLAlchemy connection string is fine.
|
||||
# See: http://www.sqlalchemy.org/docs/05/reference/sqlalchemy/connections.html#sqlalchemy.create_engine
|
||||
sql_connection = %SQL_CONN%
|
||||
|
||||
# Period in seconds after which SQLAlchemy should reestablish its connection
|
||||
# to the database.
|
||||
#
|
||||
# MySQL uses a default `wait_timeout` of 8 hours, after which it will drop
|
||||
# idle connections. This can result in 'MySQL Gone Away' exceptions. If you
|
||||
# notice this, you can lower this value to ensure that SQLAlchemy reconnects
|
||||
# before MySQL can drop the connection.
|
||||
sql_idle_timeout = 3600
|
||||
|
||||
# Limit the api to return `param_limit_max` items in a call to a container. If
|
||||
# a larger `limit` query param is provided, it will be reduced to this value.
|
||||
api_limit_max = 1000
|
||||
|
||||
# If a `limit` query param is not provided in an api request, it will
|
||||
# default to `limit_param_default`
|
||||
limit_param_default = 25
|
||||
|
||||
[pipeline:glance-registry]
|
||||
#pipeline = context registryapp
|
||||
# NOTE: use the following pipeline for keystone
|
||||
pipeline = authtoken auth-context context registryapp
|
||||
|
||||
[app:registryapp]
|
||||
paste.app_factory = glance.common.wsgi:app_factory
|
||||
glance.app_factory = glance.registry.api.v1:API
|
||||
|
||||
[filter:context]
|
||||
context_class = glance.registry.context.RequestContext
|
||||
paste.filter_factory = glance.common.wsgi:filter_factory
|
||||
glance.filter_factory = glance.common.context:ContextMiddleware
|
||||
|
||||
[filter:authtoken]
|
||||
paste.filter_factory = keystone.middleware.auth_token:filter_factory
|
||||
service_protocol = http
|
||||
service_host = 127.0.0.1
|
||||
service_port = 5000
|
||||
auth_host = 127.0.0.1
|
||||
auth_port = 35357
|
||||
auth_protocol = http
|
||||
auth_uri = http://127.0.0.1:5000/
|
||||
admin_token = %SERVICE_TOKEN%
|
||||
|
||||
[filter:auth-context]
|
||||
context_class = glance.registry.context.RequestContext
|
||||
paste.filter_factory = glance.common.wsgi:filter_factory
|
||||
glance.filter_factory = keystone.middleware.glance_auth_token:KeystoneContextMiddleware
|
110
conf/horizon/horizon_settings.py
Normal file
110
conf/horizon/horizon_settings.py
Normal file
@ -0,0 +1,110 @@
|
||||
import os
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
PROD = False
|
||||
USE_SSL = False
|
||||
|
||||
LOCAL_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# FIXME: We need to change this to mysql, instead of sqlite.
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(LOCAL_PATH, 'dashboard_openstack.sqlite3'),
|
||||
'TEST_NAME': os.path.join(LOCAL_PATH, 'test.sqlite3'),
|
||||
},
|
||||
}
|
||||
|
||||
# The default values for these two settings seem to cause issues with apache
|
||||
CACHE_BACKEND = 'dummy://'
|
||||
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
|
||||
|
||||
# Send email to the console by default
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
# Or send them to /dev/null
|
||||
#EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'
|
||||
|
||||
# django-mailer uses a different settings attribute
|
||||
MAILER_EMAIL_BACKEND = EMAIL_BACKEND
|
||||
|
||||
# Configure these for your outgoing email host
|
||||
# EMAIL_HOST = 'smtp.my-company.com'
|
||||
# EMAIL_PORT = 25
|
||||
# EMAIL_HOST_USER = 'djangomail'
|
||||
# EMAIL_HOST_PASSWORD = 'top-secret!'
|
||||
|
||||
HORIZON_CONFIG = {
|
||||
'dashboards': ('nova', 'syspanel', 'settings',),
|
||||
'default_dashboard': 'nova',
|
||||
'user_home': 'dashboard.views.user_home',
|
||||
}
|
||||
|
||||
OPENSTACK_HOST = "127.0.0.1"
|
||||
OPENSTACK_KEYSTONE_URL = "http://%s:5000/v2.0" % OPENSTACK_HOST
|
||||
# FIXME: this is only needed until keystone fixes its GET /tenants call
|
||||
# so that it doesn't return everything for admins
|
||||
OPENSTACK_KEYSTONE_ADMIN_URL = "http://%s:35357/v2.0" % OPENSTACK_HOST
|
||||
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "Member"
|
||||
|
||||
SWIFT_PAGINATE_LIMIT = 100
|
||||
|
||||
# Configure quantum connection details for networking
|
||||
QUANTUM_ENABLED = False
|
||||
QUANTUM_URL = '%s' % OPENSTACK_HOST
|
||||
QUANTUM_PORT = '9696'
|
||||
QUANTUM_TENANT = '1234'
|
||||
QUANTUM_CLIENT_VERSION='0.1'
|
||||
|
||||
# If you have external monitoring links, eg:
|
||||
# EXTERNAL_MONITORING = [
|
||||
# ['Nagios','http://foo.com'],
|
||||
# ['Ganglia','http://bar.com'],
|
||||
# ]
|
||||
|
||||
#LOGGING = {
|
||||
# 'version': 1,
|
||||
# # When set to True this will disable all logging except
|
||||
# # for loggers specified in this configuration dictionary. Note that
|
||||
# # if nothing is specified here and disable_existing_loggers is True,
|
||||
# # django.db.backends will still log unless it is disabled explicitly.
|
||||
# 'disable_existing_loggers': False,
|
||||
# 'handlers': {
|
||||
# 'null': {
|
||||
# 'level': 'DEBUG',
|
||||
# 'class': 'django.utils.log.NullHandler',
|
||||
# },
|
||||
# 'console': {
|
||||
# # Set the level to "DEBUG" for verbose output logging.
|
||||
# 'level': 'INFO',
|
||||
# 'class': 'logging.StreamHandler',
|
||||
# },
|
||||
# },
|
||||
# 'loggers': {
|
||||
# # Logging from django.db.backends is VERY verbose, send to null
|
||||
# # by default.
|
||||
# 'django.db.backends': {
|
||||
# 'handlers': ['null'],
|
||||
# 'propagate': False,
|
||||
# },
|
||||
# 'horizon': {
|
||||
# 'handlers': ['console'],
|
||||
# 'propagate': False,
|
||||
# },
|
||||
# 'novaclient': {
|
||||
# 'handlers': ['console'],
|
||||
# 'propagate': False,
|
||||
# },
|
||||
# 'keystoneclient': {
|
||||
# 'handlers': ['console'],
|
||||
# 'propagate': False,
|
||||
# },
|
||||
# 'nose.plugins.manager': {
|
||||
# 'handlers': ['console'],
|
||||
# 'propagate': False,
|
||||
# }
|
||||
# }
|
||||
#}
|
||||
|
||||
# How much ram on each compute host?
|
||||
COMPUTE_HOST_RAM_GB = 16
|
116
conf/keystone/keystone.conf
Normal file
116
conf/keystone/keystone.conf
Normal file
@ -0,0 +1,116 @@
|
||||
[DEFAULT]
|
||||
# Show more verbose log output (sets INFO log level output)
|
||||
verbose = False
|
||||
|
||||
# Show debugging output in logs (sets DEBUG log level output)
|
||||
debug = False
|
||||
|
||||
# Which backend store should Keystone use by default.
|
||||
# Default: 'sqlite'
|
||||
# Available choices are 'sqlite' [future will include LDAP, PAM, etc]
|
||||
default_store = sqlite
|
||||
|
||||
# Log to this file. Make sure you do not set the same log
|
||||
# file for both the API and registry servers!
|
||||
log_file = %DEST%/keystone/keystone.log
|
||||
|
||||
# List of backends to be configured
|
||||
backends = keystone.backends.sqlalchemy
|
||||
#For LDAP support, add: ,keystone.backends.ldap
|
||||
|
||||
# Dictionary Maps every service to a header.Missing services would get header
|
||||
# X_(SERVICE_NAME) Key => Service Name, Value => Header Name
|
||||
service-header-mappings = {
|
||||
'nova' : 'X-Server-Management-Url',
|
||||
'swift' : 'X-Storage-Url',
|
||||
'cdn' : 'X-CDN-Management-Url'}
|
||||
|
||||
#List of extensions currently supported
|
||||
extensions= osksadm,oskscatalog
|
||||
|
||||
# Address to bind the API server
|
||||
# TODO Properties defined within app not available via pipeline.
|
||||
service_host = 0.0.0.0
|
||||
|
||||
# Port the bind the API server to
|
||||
service_port = 5000
|
||||
|
||||
# SSL for API server
|
||||
service_ssl = False
|
||||
|
||||
# Address to bind the Admin API server
|
||||
admin_host = 0.0.0.0
|
||||
|
||||
# Port the bind the Admin API server to
|
||||
admin_port = 35357
|
||||
|
||||
# SSL for API Admin server
|
||||
admin_ssl = False
|
||||
|
||||
# Keystone certificate file (modify as needed)
|
||||
# Only required if *_ssl is set to True
|
||||
certfile = /etc/keystone/ssl/certs/keystone.pem
|
||||
|
||||
# Keystone private key file (modify as needed)
|
||||
# Only required if *_ssl is set to True
|
||||
keyfile = /etc/keystone/ssl/private/keystonekey.pem
|
||||
|
||||
# Keystone trusted CA certificates (modify as needed)
|
||||
# Only required if *_ssl is set to True
|
||||
ca_certs = /etc/keystone/ssl/certs/ca.pem
|
||||
|
||||
# Client certificate required
|
||||
# Only relevant if *_ssl is set to True
|
||||
cert_required = True
|
||||
|
||||
#Role that allows to perform admin operations.
|
||||
keystone-admin-role = Admin
|
||||
|
||||
#Role that allows to perform service admin operations.
|
||||
keystone-service-admin-role = KeystoneServiceAdmin
|
||||
|
||||
#Tells whether password user need to be hashed in the backend
|
||||
hash-password = True
|
||||
|
||||
[keystone.backends.sqlalchemy]
|
||||
# SQLAlchemy connection string for the reference implementation registry
|
||||
# server. Any valid SQLAlchemy connection string is fine.
|
||||
# See: http://bit.ly/ideIpI
|
||||
sql_connection = %SQL_CONN%
|
||||
backend_entities = ['UserRoleAssociation', 'Endpoints', 'Role', 'Tenant',
|
||||
'User', 'Credentials', 'EndpointTemplates', 'Token',
|
||||
'Service']
|
||||
|
||||
# Period in seconds after which SQLAlchemy should reestablish its connection
|
||||
# to the database.
|
||||
sql_idle_timeout = 30
|
||||
|
||||
[pipeline:admin]
|
||||
pipeline =
|
||||
urlrewritefilter
|
||||
admin_api
|
||||
|
||||
[pipeline:keystone-legacy-auth]
|
||||
pipeline =
|
||||
urlrewritefilter
|
||||
legacy_auth
|
||||
RAX-KEY-extension
|
||||
service_api
|
||||
|
||||
[app:service_api]
|
||||
paste.app_factory = keystone.server:service_app_factory
|
||||
|
||||
[app:admin_api]
|
||||
paste.app_factory = keystone.server:admin_app_factory
|
||||
|
||||
[filter:urlrewritefilter]
|
||||
paste.filter_factory = keystone.middleware.url:filter_factory
|
||||
|
||||
[filter:legacy_auth]
|
||||
paste.filter_factory = keystone.frontends.legacy_token_auth:filter_factory
|
||||
|
||||
[filter:RAX-KEY-extension]
|
||||
paste.filter_factory = keystone.contrib.extensions.service.raxkey.frontend:filter_factory
|
||||
|
||||
[filter:debug]
|
||||
paste.filter_factory = keystone.common.wsgi:debug_filter_factory
|
54
conf/keystone/keystone_data.sh
Executable file
54
conf/keystone/keystone_data.sh
Executable file
@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
BIN_DIR=${BIN_DIR:-.}
|
||||
# Tenants
|
||||
$BIN_DIR/keystone-manage $* tenant add admin
|
||||
$BIN_DIR/keystone-manage $* tenant add demo
|
||||
$BIN_DIR/keystone-manage $* tenant add invisible_to_admin
|
||||
|
||||
# Users
|
||||
$BIN_DIR/keystone-manage $* user add admin %ADMIN_PASSWORD%
|
||||
$BIN_DIR/keystone-manage $* user add demo %ADMIN_PASSWORD%
|
||||
|
||||
# Roles
|
||||
$BIN_DIR/keystone-manage $* role add Admin
|
||||
$BIN_DIR/keystone-manage $* role add Member
|
||||
$BIN_DIR/keystone-manage $* role add KeystoneAdmin
|
||||
$BIN_DIR/keystone-manage $* role add KeystoneServiceAdmin
|
||||
$BIN_DIR/keystone-manage $* role add sysadmin
|
||||
$BIN_DIR/keystone-manage $* role add netadmin
|
||||
$BIN_DIR/keystone-manage $* role grant Admin admin admin
|
||||
$BIN_DIR/keystone-manage $* role grant Member demo demo
|
||||
$BIN_DIR/keystone-manage $* role grant sysadmin demo demo
|
||||
$BIN_DIR/keystone-manage $* role grant netadmin demo demo
|
||||
$BIN_DIR/keystone-manage $* role grant Member demo invisible_to_admin
|
||||
$BIN_DIR/keystone-manage $* role grant Admin admin demo
|
||||
$BIN_DIR/keystone-manage $* role grant Admin admin
|
||||
$BIN_DIR/keystone-manage $* role grant KeystoneAdmin admin
|
||||
$BIN_DIR/keystone-manage $* role grant KeystoneServiceAdmin admin
|
||||
|
||||
# Services
|
||||
$BIN_DIR/keystone-manage $* service add nova compute "Nova Compute Service"
|
||||
$BIN_DIR/keystone-manage $* service add ec2 ec2 "EC2 Compatability Layer"
|
||||
$BIN_DIR/keystone-manage $* service add glance image "Glance Image Service"
|
||||
$BIN_DIR/keystone-manage $* service add keystone identity "Keystone Identity Service"
|
||||
if [[ "$ENABLED_SERVICES" =~ "swift" ]]; then
|
||||
$BIN_DIR/keystone-manage $* service add swift object-store "Swift Service"
|
||||
fi
|
||||
|
||||
#endpointTemplates
|
||||
$BIN_DIR/keystone-manage $* endpointTemplates add RegionOne nova http://%HOST_IP%:8774/v1.1/%tenant_id% http://%HOST_IP%:8774/v1.1/%tenant_id% http://%HOST_IP%:8774/v1.1/%tenant_id% 1 1
|
||||
$BIN_DIR/keystone-manage $* endpointTemplates add RegionOne ec2 http://%HOST_IP%:8773/services/Cloud http://%HOST_IP%:8773/services/Admin http://%HOST_IP%:8773/services/Cloud 1 1
|
||||
$BIN_DIR/keystone-manage $* endpointTemplates add RegionOne glance http://%HOST_IP%:9292/v1.1/%tenant_id% http://%HOST_IP%:9292/v1.1/%tenant_id% http://%HOST_IP%:9292/v1.1/%tenant_id% 1 1
|
||||
$BIN_DIR/keystone-manage $* endpointTemplates add RegionOne keystone http://%HOST_IP%:5000/v2.0 http://%HOST_IP%:35357/v2.0 http://%HOST_IP%:5000/v2.0 1 1
|
||||
if [[ "$ENABLED_SERVICES" =~ "swift" ]]; then
|
||||
$BIN_DIR/keystone-manage $* endpointTemplates add RegionOne swift http://%HOST_IP%:8080/v1/AUTH_%tenant_id% http://%HOST_IP%:8080/ http://%HOST_IP%:8080/v1/AUTH_%tenant_id% 1 1
|
||||
fi
|
||||
|
||||
# Tokens
|
||||
$BIN_DIR/keystone-manage $* token add %SERVICE_TOKEN% admin admin 2015-02-05T00:00
|
||||
|
||||
# EC2 related creds - note we are setting the secret key to ADMIN_PASSWORD
|
||||
# but keystone doesn't parse them - it is just a blob from keystone's
|
||||
# point of view
|
||||
$BIN_DIR/keystone-manage $* credentials add admin EC2 'admin' '%ADMIN_PASSWORD%' admin || echo "no support for adding credentials"
|
||||
$BIN_DIR/keystone-manage $* credentials add demo EC2 'demo' '%ADMIN_PASSWORD%' demo || echo "no support for adding credentials"
|
138
conf/nova/nova-api-paste.ini
Normal file
138
conf/nova/nova-api-paste.ini
Normal file
@ -0,0 +1,138 @@
|
||||
############
|
||||
# Metadata #
|
||||
############
|
||||
[composite:metadata]
|
||||
use = egg:Paste#urlmap
|
||||
/: metaversions
|
||||
/latest: meta
|
||||
/2007-01-19: meta
|
||||
/2007-03-01: meta
|
||||
/2007-08-29: meta
|
||||
/2007-10-10: meta
|
||||
/2007-12-15: meta
|
||||
/2008-02-01: meta
|
||||
/2008-09-01: meta
|
||||
/2009-04-04: meta
|
||||
|
||||
[pipeline:metaversions]
|
||||
pipeline = ec2faultwrap logrequest metaverapp
|
||||
|
||||
[pipeline:meta]
|
||||
pipeline = ec2faultwrap logrequest metaapp
|
||||
|
||||
[app:metaverapp]
|
||||
paste.app_factory = nova.api.metadata.handler:Versions.factory
|
||||
|
||||
[app:metaapp]
|
||||
paste.app_factory = nova.api.metadata.handler:MetadataRequestHandler.factory
|
||||
|
||||
#######
|
||||
# EC2 #
|
||||
#######
|
||||
|
||||
[composite:ec2]
|
||||
use = egg:Paste#urlmap
|
||||
/services/Cloud: ec2cloud
|
||||
/services/Admin: ec2admin
|
||||
|
||||
[pipeline:ec2cloud]
|
||||
pipeline = ec2faultwrap logrequest totoken authtoken keystonecontext cloudrequest authorizer ec2executor
|
||||
|
||||
[pipeline:ec2admin]
|
||||
pipeline = ec2faultwrap logrequest totoken authtoken keystonecontext adminrequest authorizer ec2executor
|
||||
|
||||
[pipeline:ec2metadata]
|
||||
pipeline = ec2faultwrap logrequest ec2md
|
||||
|
||||
[pipeline:ec2versions]
|
||||
pipeline = ec2faultwrap logrequest ec2ver
|
||||
|
||||
[filter:ec2faultwrap]
|
||||
paste.filter_factory = nova.api.ec2:FaultWrapper.factory
|
||||
|
||||
[filter:logrequest]
|
||||
paste.filter_factory = nova.api.ec2:RequestLogging.factory
|
||||
|
||||
[filter:ec2lockout]
|
||||
paste.filter_factory = nova.api.ec2:Lockout.factory
|
||||
|
||||
[filter:totoken]
|
||||
paste.filter_factory = keystone.middleware.ec2_token:EC2Token.factory
|
||||
|
||||
[filter:ec2noauth]
|
||||
paste.filter_factory = nova.api.ec2:NoAuth.factory
|
||||
|
||||
[filter:authenticate]
|
||||
paste.filter_factory = nova.api.ec2:Authenticate.factory
|
||||
|
||||
[filter:cloudrequest]
|
||||
controller = nova.api.ec2.cloud.CloudController
|
||||
paste.filter_factory = nova.api.ec2:Requestify.factory
|
||||
|
||||
[filter:adminrequest]
|
||||
controller = nova.api.ec2.admin.AdminController
|
||||
paste.filter_factory = nova.api.ec2:Requestify.factory
|
||||
|
||||
[filter:authorizer]
|
||||
paste.filter_factory = nova.api.ec2:Authorizer.factory
|
||||
|
||||
[app:ec2executor]
|
||||
paste.app_factory = nova.api.ec2:Executor.factory
|
||||
|
||||
#############
|
||||
# Openstack #
|
||||
#############
|
||||
|
||||
[composite:osapi]
|
||||
use = call:nova.api.openstack.v2.urlmap:urlmap_factory
|
||||
/: osversions
|
||||
/v1.1: openstack_api_v2
|
||||
/v2: openstack_api_v2
|
||||
|
||||
[pipeline:openstack_api_v2]
|
||||
pipeline = faultwrap authtoken keystonecontext ratelimit serialize extensions osapi_app_v2
|
||||
|
||||
[filter:faultwrap]
|
||||
paste.filter_factory = nova.api.openstack.v2:FaultWrapper.factory
|
||||
|
||||
[filter:auth]
|
||||
paste.filter_factory = nova.api.openstack.v2.auth:AuthMiddleware.factory
|
||||
|
||||
[filter:noauth]
|
||||
paste.filter_factory = nova.api.openstack.v2.auth:NoAuthMiddleware.factory
|
||||
|
||||
[filter:ratelimit]
|
||||
paste.filter_factory = nova.api.openstack.v2.limits:RateLimitingMiddleware.factory
|
||||
|
||||
[filter:serialize]
|
||||
paste.filter_factory = nova.api.openstack.wsgi:LazySerializationMiddleware.factory
|
||||
|
||||
[filter:extensions]
|
||||
paste.filter_factory = nova.api.openstack.v2.extensions:ExtensionMiddleware.factory
|
||||
|
||||
[app:osapi_app_v2]
|
||||
paste.app_factory = nova.api.openstack.v2:APIRouter.factory
|
||||
|
||||
[pipeline:osversions]
|
||||
pipeline = faultwrap osversionapp
|
||||
|
||||
[app:osversionapp]
|
||||
paste.app_factory = nova.api.openstack.v2.versions:Versions.factory
|
||||
|
||||
##########
|
||||
# Shared #
|
||||
##########
|
||||
|
||||
[filter:keystonecontext]
|
||||
paste.filter_factory = keystone.middleware.nova_keystone_context:NovaKeystoneContext.factory
|
||||
|
||||
[filter:authtoken]
|
||||
paste.filter_factory = keystone.middleware.auth_token:filter_factory
|
||||
service_protocol = http
|
||||
service_host = 127.0.0.1
|
||||
service_port = 5000
|
||||
auth_host = 127.0.0.1
|
||||
auth_port = 35357
|
||||
auth_protocol = http
|
||||
auth_uri = http://127.0.0.1:5000/
|
||||
admin_token = %SERVICE_TOKEN%
|
47
conf/nova/sudo.allowed
Normal file
47
conf/nova/sudo.allowed
Normal file
@ -0,0 +1,47 @@
|
||||
Cmnd_Alias NOVADEVCMDS = /bin/chmod /var/lib/nova/tmp/*/root/.ssh, \
|
||||
/bin/chown /var/lib/nova/tmp/*/root/.ssh, \
|
||||
/bin/chown, \
|
||||
/bin/chmod, \
|
||||
/bin/dd, \
|
||||
/sbin/ifconfig, \
|
||||
/sbin/ip, \
|
||||
/sbin/route, \
|
||||
/sbin/iptables, \
|
||||
/sbin/iptables-save, \
|
||||
/sbin/iptables-restore, \
|
||||
/sbin/ip6tables-save, \
|
||||
/sbin/ip6tables-restore, \
|
||||
/sbin/kpartx, \
|
||||
/sbin/losetup, \
|
||||
/sbin/lvcreate, \
|
||||
/sbin/lvdisplay, \
|
||||
/sbin/lvremove, \
|
||||
/bin/mkdir, \
|
||||
/bin/mount, \
|
||||
/sbin/pvcreate, \
|
||||
/usr/bin/tee, \
|
||||
/sbin/tune2fs, \
|
||||
/bin/umount, \
|
||||
/sbin/vgcreate, \
|
||||
/usr/bin/virsh, \
|
||||
/usr/bin/qemu-nbd, \
|
||||
/usr/sbin/brctl, \
|
||||
/sbin/brctl, \
|
||||
/usr/sbin/radvd, \
|
||||
/usr/sbin/vblade-persist, \
|
||||
/sbin/pvcreate, \
|
||||
/sbin/aoe-discover, \
|
||||
/sbin/vgcreate, \
|
||||
/bin/aoe-stat, \
|
||||
/bin/kill, \
|
||||
/sbin/vconfig, \
|
||||
/usr/sbin/ietadm, \
|
||||
/sbin/vgs, \
|
||||
/sbin/iscsiadm, \
|
||||
/usr/bin/socat, \
|
||||
/sbin/parted, \
|
||||
/usr/sbin/dnsmasq, \
|
||||
/usr/sbin/arping
|
||||
|
||||
%USER% ALL = (root) NOPASSWD: SETENV: NOVADEVCMDS
|
||||
|
10
conf/pkgs/db.pkg
Normal file
10
conf/pkgs/db.pkg
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ubuntu-oneiric": {
|
||||
"mysql-server": {
|
||||
"version": "5.1.58-1ubuntu1",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
}
|
||||
},
|
||||
"rhel-6": {}
|
||||
}
|
96
conf/pkgs/general.pkg
Normal file
96
conf/pkgs/general.pkg
Normal file
@ -0,0 +1,96 @@
|
||||
{
|
||||
"ubuntu-oneiric": {
|
||||
"pep8": {
|
||||
"version": "0.6.1-2ubuntu1",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"pylint": {
|
||||
"version": "0.23.0-1",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"python-pip": {
|
||||
"version": "1.0-1",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"screen": {
|
||||
"version": "4.0.3-14ubuntu8",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"unzip": {
|
||||
"version": "6.0-4ubuntu1",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"wget": {
|
||||
"version": "1.12-3.1ubuntu1",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"psmisc": {
|
||||
"version": "22.14-1",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"git-core": {
|
||||
"version": "1:1.7.5.4-1",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"lsof": {
|
||||
"version": "4.81.dfsg.1-1build1",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"openssh-server": {
|
||||
"version": "1:5.8p1-7ubuntu1",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"vim-nox": {
|
||||
"version": "2:7.3.154+hg~74503f6ee649-2ubuntu3",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"locate": {
|
||||
"version": "4.4.2-1ubuntu3",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"python-virtualenv": {
|
||||
"version": "1.6.4-0ubuntu1",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"python-unittest2": {
|
||||
"version": "0.5.1-1",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"iputils-ping": {
|
||||
"version": "3:20101006-1",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"curl": {
|
||||
"version": "7.21.6-3ubuntu3",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"tcpdump": {
|
||||
"version": "4.1.1-2ubuntu2",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
},
|
||||
"euca2ools": {
|
||||
"version": "2.0.0~bzr464-0ubuntu2",
|
||||
"allowed": ">=",
|
||||
"removable" : false
|
||||
}
|
||||
},
|
||||
"rhel-6": {
|
||||
}
|
||||
}
|
48
conf/pkgs/glance.pkg
Normal file
48
conf/pkgs/glance.pkg
Normal file
@ -0,0 +1,48 @@
|
||||
{
|
||||
"ubuntu-oneiric": {
|
||||
"python-eventlet": {
|
||||
"version": "0.9.15-0ubuntu4",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-routes": {
|
||||
"version": "1.12.3-1",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-greenlet": {
|
||||
"version": "0.3.1-1ubuntu4",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-argparse": {
|
||||
"version": "1.1-1ubuntu1",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-sqlalchemy": {
|
||||
"version": "0.6.8-1",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-wsgiref": {
|
||||
"removable": false
|
||||
},
|
||||
"python-pastedeploy": {
|
||||
"version": "1.5.0-2",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-xattr": {
|
||||
"version": "0.6-1ubuntu2",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-httplib2": {
|
||||
"version": "0.7.1-1ubuntu1",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
}
|
||||
},
|
||||
"rhel-6": {}
|
||||
}
|
106
conf/pkgs/horizon.pkg
Normal file
106
conf/pkgs/horizon.pkg
Normal file
@ -0,0 +1,106 @@
|
||||
{
|
||||
"ubuntu-oneiric": {
|
||||
"apache2": {
|
||||
"version": "2.2.20-1ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"libapache2-mod-wsgi": {
|
||||
"version": "3.3-2ubuntu3",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-dateutil": {
|
||||
"version": "1.4.1-4",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-paste": {
|
||||
"version": "1.7.5.1-4ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-pastedeploy": {
|
||||
"version": "1.5.0-2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-anyjson": {
|
||||
"version": "0.3.1-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-routes": {
|
||||
"version": "1.12.3-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-xattr": {
|
||||
"version": "0.6-1ubuntu2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-sqlalchemy": {
|
||||
"version": "0.6.8-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-webob": {
|
||||
"version": "1.0.8-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-kombu": {
|
||||
"version": "1.0.4-2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"pylint": {
|
||||
"version": "0.23.0-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"pep8": {
|
||||
"version": "0.6.1-2ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-eventlet": {
|
||||
"version": "0.9.15-0ubuntu4",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-nose": {
|
||||
"version": "1.0.0-1ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-sphinx": {
|
||||
"version": "1.0.7+dfsg-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-mox": {
|
||||
"version": "0.5.3-1ubuntu4",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-coverage": {
|
||||
"version": "3.4-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-cherrypy3": {
|
||||
"version": "3.1.2-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-django": {
|
||||
"version": "1.3-2ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-django-mailer": {
|
||||
"version": "0.2a1.dev3-0ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-django-nose": {
|
||||
"version": "0.1.2-2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-django-registration": {
|
||||
"version": "0.7-2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-cloudfiles": {
|
||||
"version": "1.7.9.2-0ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-migrate": {
|
||||
"version": "0.7.1-1",
|
||||
"allowed": ">="
|
||||
}
|
||||
},
|
||||
"rhel-6": {
|
||||
}
|
||||
}
|
73
conf/pkgs/keystone.pkg
Normal file
73
conf/pkgs/keystone.pkg
Normal file
@ -0,0 +1,73 @@
|
||||
{
|
||||
"ubuntu-oneiric": {
|
||||
"python-setuptools": {
|
||||
"version": "0.6.16-1",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-dev": {
|
||||
"version": "2.7.2-7ubuntu2",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-lxml": {
|
||||
"version": "2.3-0.1build1",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-pastescript": {
|
||||
"version": "1.7.3-7",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-pastedeploy": {
|
||||
"version": "1.5.0-2",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-paste": {
|
||||
"version": "1.7.5.1-4ubuntu1",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"sqlite3": {
|
||||
"version": "3.7.7-2ubuntu2",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-pysqlite2": {
|
||||
"version": "2.6.3-2",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-sqlalchemy": {
|
||||
"version": "0.6.8-1",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-webob": {
|
||||
"version": "1.0.8-1",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-greenlet": {
|
||||
"version": "0.3.1-1ubuntu4",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"python-routes": {
|
||||
"version": "1.12.3-1",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
},
|
||||
"libldap2-dev": {
|
||||
"removable": true
|
||||
},
|
||||
"libsasl2-dev": {
|
||||
"version": "2.1.24~rc1.dfsg1+cvs2011-05-23-4ubuntu2",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
}
|
||||
},
|
||||
"rhel-6": {}
|
||||
}
|
18
conf/pkgs/n-cpu.pkg
Normal file
18
conf/pkgs/n-cpu.pkg
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"ubuntu-oneiric": {
|
||||
"lvm2": {
|
||||
"version": "2.02.66-4ubuntu3",
|
||||
"allowed": ">="
|
||||
},
|
||||
"open-iscsi": {
|
||||
"version": "2.0.871-0ubuntu8",
|
||||
"allowed": ">="
|
||||
},
|
||||
"open-iscsi-utils": {
|
||||
"version": "2.0.871-0ubuntu8",
|
||||
"allowed": ">="
|
||||
}
|
||||
},
|
||||
"rhel-6": {
|
||||
}
|
||||
}
|
10
conf/pkgs/n-vnc.pkg
Normal file
10
conf/pkgs/n-vnc.pkg
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ubuntu-oneiric": {
|
||||
"python-numpy": {
|
||||
"version": "1:1.5.1-2ubuntu2",
|
||||
"allowed": ">="
|
||||
}
|
||||
},
|
||||
"rhel-6": {
|
||||
}
|
||||
}
|
18
conf/pkgs/n-vol.pkg
Normal file
18
conf/pkgs/n-vol.pkg
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"ubuntu-oneiric": {
|
||||
"iscsitarget": {
|
||||
"version": "1.4.20.2-5ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"iscsitarget-dkms": {
|
||||
"version": "1.4.20.2-5ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"lvm2": {
|
||||
"version": "2.02.66-4ubuntu3",
|
||||
"allowed": ">="
|
||||
}
|
||||
},
|
||||
"rhel-6": {
|
||||
}
|
||||
}
|
174
conf/pkgs/nova.pkg
Normal file
174
conf/pkgs/nova.pkg
Normal file
@ -0,0 +1,174 @@
|
||||
{
|
||||
"ubuntu-oneiric": {
|
||||
"dnsmasq-base": {
|
||||
"version": "2.57-1ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"dnsmasq-utils": {
|
||||
"version": "2.57-1ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"kpartx": {
|
||||
"version": "0.4.9-2ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"parted": {
|
||||
"version": "2.3-6ubuntu3",
|
||||
"allowed": ">="
|
||||
},
|
||||
"arping": {
|
||||
"version": "2.09-2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"iputils-arping": {
|
||||
"version": "3:20101006-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"mysql-server": {
|
||||
"version": "5.1.58-1ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-mysqldb": {
|
||||
"version": "1.2.3-0ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-xattr": {
|
||||
"version": "0.6-1ubuntu2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-lxml": {
|
||||
"version": "2.3-0.1build1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"kvm": {
|
||||
"version": "1:84+dfsg-0ubuntu16+0.14.1+noroms+0ubuntu6",
|
||||
"allowed": ">="
|
||||
},
|
||||
"gawk": {
|
||||
"version": "1:3.1.8+dfsg-0.1build1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"iptables": {
|
||||
"version": "1.4.10-1ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"ebtables": {
|
||||
"version": "2.0.9.2-2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"sqlite3": {
|
||||
"version": "3.7.7-2ubuntu2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"sudo": {
|
||||
"version": "1.7.4p6-1ubuntu2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"libvirt-bin": {
|
||||
"version": "0.9.2-4ubuntu15",
|
||||
"allowed": ">="
|
||||
},
|
||||
"vlan": {
|
||||
"version": "1.9-3ubuntu3",
|
||||
"allowed": ">="
|
||||
},
|
||||
"curl": {
|
||||
"version": "7.21.6-3ubuntu3",
|
||||
"allowed": ">="
|
||||
},
|
||||
"rabbitmq-server": {
|
||||
"version": "2.5.0-1ubuntu2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"socat": {
|
||||
"version": "1.7.1.3-1.1ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-mox": {
|
||||
"version": "0.5.3-1ubuntu4",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-paste": {
|
||||
"version": "1.7.5.1-4ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-migrate": {
|
||||
"version": "0.7.1-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-gflags": {
|
||||
"version": "1.5.1-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-greenlet": {
|
||||
"version": "0.3.1-1ubuntu4",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-libvirt": {
|
||||
"version": "0.9.2-4ubuntu15",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-libxml2": {
|
||||
"version": "2.7.8.dfsg-4",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-routes": {
|
||||
"version": "1.12.3-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-netaddr": {
|
||||
"version": "0.7.5-4",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-pastedeploy": {
|
||||
"version": "1.5.0-2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-eventlet": {
|
||||
"version": "0.9.15-0ubuntu4",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-cheetah": {
|
||||
"version": "2.4.4-2ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-carrot": {
|
||||
"version": "0.10.7-0ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-tempita": {
|
||||
"version": "0.5.1-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-sqlalchemy": {
|
||||
"version": "0.6.8-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-suds": {
|
||||
"version": "0.4.1-2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-lockfile": {
|
||||
"version": "1:0.8-2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-m2crypto": {
|
||||
"version": "0.20.1+dfsg1-1.1ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-boto": {
|
||||
"version": "2.0-0ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-kombu": {
|
||||
"version": "1.0.4-2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-feedparser": {
|
||||
"version": "5.0.1-1",
|
||||
"allowed": ">="
|
||||
}
|
||||
},
|
||||
"rhel-6": {
|
||||
}
|
||||
}
|
10
conf/pkgs/rabbitmq.pkg
Normal file
10
conf/pkgs/rabbitmq.pkg
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ubuntu-oneiric": {
|
||||
"rabbitmq-server": {
|
||||
"version": "2.5.0-1ubuntu2",
|
||||
"allowed": ">=",
|
||||
"removable": true
|
||||
}
|
||||
},
|
||||
"rhel-6": {}
|
||||
}
|
74
conf/pkgs/swift.pkg
Normal file
74
conf/pkgs/swift.pkg
Normal file
@ -0,0 +1,74 @@
|
||||
{
|
||||
"ubuntu-oneiric": {
|
||||
"curl": {
|
||||
"version": "7.21.6-3ubuntu3",
|
||||
"allowed": ">="
|
||||
},
|
||||
"gcc": {
|
||||
"version": "4:4.6.1-2ubuntu5",
|
||||
"allowed": ">="
|
||||
},
|
||||
"memcached": {
|
||||
"version": "1.4.7-0.1ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-configobj": {
|
||||
"version": "4.7.2+ds-3",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-coverage": {
|
||||
"version": "3.4-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-dev": {
|
||||
"version": "2.7.2-7ubuntu2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-eventlet": {
|
||||
"version": "0.9.15-0ubuntu4",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-greenlet": {
|
||||
"version": "0.3.1-1ubuntu4",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-netifaces": {
|
||||
"version": "0.5-2.1ubuntu2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-nose": {
|
||||
"version": "1.0.0-1ubuntu1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-pastedeploy": {
|
||||
"version": "1.5.0-2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-setuptools": {
|
||||
"version": "0.6.16-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-simplejson": {
|
||||
"version": "2.1.6-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-webob": {
|
||||
"version": "1.0.8-1",
|
||||
"allowed": ">="
|
||||
},
|
||||
"python-xattr": {
|
||||
"version": "0.6-1ubuntu2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"sqlite3": {
|
||||
"version": "3.7.7-2ubuntu2",
|
||||
"allowed": ">="
|
||||
},
|
||||
"xfsprogs": {
|
||||
"version": "3.1.5ubuntu1",
|
||||
"allowed": ">="
|
||||
}
|
||||
},
|
||||
"rhel-6": {
|
||||
}
|
||||
}
|
159
conf/stack.ini
Normal file
159
conf/stack.ini
Normal file
@ -0,0 +1,159 @@
|
||||
# Devstack2 local configuration
|
||||
|
||||
# When a value looks like a bash variable + default then it is parsed like a bash
|
||||
# variable and will perform similar lookups. Ie ${SQL_HOST:-localhost} will
|
||||
# look in environment variable SQL_HOST and if that does not exist then
|
||||
# localhost will be used instead.
|
||||
|
||||
[default]
|
||||
|
||||
# Set api host endpoint
|
||||
host_ip = ${HOST_IP:-127.0.0.1}
|
||||
|
||||
#Sys log enabled or not
|
||||
syslog = 0
|
||||
|
||||
[db]
|
||||
|
||||
sql_host = ${SQL_HOST:-localhost}
|
||||
sql_user = ${SQL_USER:-root}
|
||||
|
||||
#internal commands are dependent on this...
|
||||
type = mysql
|
||||
|
||||
[nova]
|
||||
|
||||
# Nova original used project_id as the *account* that owned resources (servers,
|
||||
# ip address, ...) With the addition of Keystone we have standardized on the
|
||||
# term **tenant** as the entity that owns the resources. **novaclient** still
|
||||
# uses the old deprecated terms project_id. Note that this field should now be
|
||||
# set to tenant_name, not tenant_id.
|
||||
nova_project_id = ${TENANT:-demo}
|
||||
|
||||
# In addition to the owning entity (tenant), nova stores the entity performing
|
||||
# the action as the **user**.
|
||||
nova_username = ${USERNAME:-demo}
|
||||
|
||||
# With Keystone you pass the keystone password instead of an api key.
|
||||
# The most recent versions of novaclient use NOVA_PASSWORD instead of NOVA_API_KEY
|
||||
nova_password = ${ADMIN_PASSWORD:-secrete}
|
||||
|
||||
# With the addition of Keystone, to use an openstack cloud you should
|
||||
# authenticate against keystone, which returns a **Token** and **Service
|
||||
# Catalog**. The catalog contains the endpoint for all services the user/tenant
|
||||
# has access to - including nova, glance, keystone, swift, ... We currently
|
||||
# recommend using the 2.0 *auth api*.
|
||||
#
|
||||
# *NOTE*: Using the 2.0 *auth api* does not mean that compute api is 2.0. We
|
||||
# will use the 1.1 *compute api*
|
||||
nova_url = ${NOVA_URL:-http://$HOST_IP:5000/v2.0/}
|
||||
|
||||
# Currently novaclient needs you to specify the *compute api* version. This
|
||||
# needs to match the config of your catalog returned by Keystone.
|
||||
nova_version = ${NOVA_VERSION:-1.1}
|
||||
|
||||
[ec2]
|
||||
|
||||
# Set the ec2 url so euca2ools works
|
||||
ec2_url = ${EC2_URL:-http://$HOST_IP:8773/services/Cloud}
|
||||
|
||||
# Access key is set in the initial keystone data to be the same as username
|
||||
ec2_access_key = ${USERNAME:-demo}
|
||||
|
||||
# Secret key is set in the initial keystone data to the admin password
|
||||
ec2_secret_key = ${ADMIN_PASSWORD:-secrete}
|
||||
|
||||
[vm]
|
||||
|
||||
# Max time till the vm is bootable
|
||||
boot_timeout = ${BOOT_TIMEOUT:-15}
|
||||
|
||||
# Max time to wait while vm goes from build to active state
|
||||
active_timeout = ${ACTIVE_TIMEOUT:-10}
|
||||
|
||||
# Max time from run instance command until it is running
|
||||
running_timeout = ${RUNNING_TIMEOUT:-$(($active_timeout + $active_timeout))}
|
||||
|
||||
# Max time to wait for proper IP association and dis-association.
|
||||
associate_timeout = ${ASSOCIATE_TIMEOUT:-10}
|
||||
|
||||
[git]
|
||||
|
||||
# compute service
|
||||
nova_repo = https://github.com/openstack/nova.git
|
||||
nova_branch = master
|
||||
|
||||
# storage service
|
||||
swift_repo = https://github.com/openstack/swift.git
|
||||
swift_branch = master
|
||||
|
||||
# swift and keystone integration
|
||||
swift_keystone_repo = https://github.com/cloudbuilders/swift-keystone2.git
|
||||
swift_keystone_branch = master
|
||||
|
||||
# image catalog service
|
||||
glance_repo = https://github.com/openstack/glance.git
|
||||
glance_branch = master
|
||||
|
||||
# unified auth system (manages accounts/tokens)
|
||||
keystone_repo = https://github.com/openstack/keystone.git
|
||||
keystone_branch = stable/diablo
|
||||
|
||||
# a websockets/html5 or flash powered VNC console for vm instances
|
||||
novnc_repo = https://github.com/cloudbuilders/noVNC.git
|
||||
novnc_branch = master
|
||||
|
||||
# django powered web control panel for openstack
|
||||
horizon_repo = https://github.com/openstack/horizon.git
|
||||
horizon_branch = master
|
||||
|
||||
# python client library to nova that horizon (and others) use
|
||||
novaclient_repo = https://github.com/openstack/python-novaclient.git
|
||||
novaclient_branch = master
|
||||
|
||||
# openstackx is a collection of extensions to openstack.compute & nova
|
||||
# that is *deprecated*. The code is being moved into python-novaclient & nova.
|
||||
openstackx_repo = https://github.com/cloudbuilders/openstackx.git
|
||||
openstackx_branch = master
|
||||
|
||||
# quantum service
|
||||
quantum_repo = https://github.com/openstack/quantum
|
||||
quantum_branch = master
|
||||
|
||||
[ci]
|
||||
|
||||
# CI test suite
|
||||
citest_repo = https://github.com/openstack/tempest.git
|
||||
citest_branch = master
|
||||
|
||||
[img]
|
||||
|
||||
# Specify a comma-separated list of uec images to download and install into glance.
|
||||
# supported urls here are:
|
||||
# * "uec-style" images:
|
||||
# If the file ends in .tar.gz, uncompress the tarball and and select the first
|
||||
# .img file inside it as the image. If present, use "*-vmlinuz*" as the kernel
|
||||
# and "*-initrd*" as the ramdisk
|
||||
# example: http://cloud-images.ubuntu.com/releases/oneiric/release/ubuntu-11.10-server-cloudimg-amd64.tar.gz
|
||||
# * disk image (*.img,*.img.gz)
|
||||
# if file ends in .img, then it will be uploaded and registered as a to
|
||||
# glance as a disk image. If it ends in .gz, it is uncompressed first.
|
||||
# example:
|
||||
# http://cloud-images.ubuntu.com/releases/oneiric/release/ubuntu-11.10-server-cloudimg-armel-disk1.img
|
||||
# http://launchpad.net/cirros/trunk/0.3.0/+download/cirros-0.3.0-x86_64-rootfs.img.gz
|
||||
|
||||
# old ttylinux-uec image
|
||||
#image_urls="http://smoser.brickies.net/ubuntu/ttylinux-uec/ttylinux-uec-amd64-11.2_2.6.35-15_1.tar.gz"
|
||||
# cirros full disk image
|
||||
#image_urls="http://launchpad.net/cirros/trunk/0.3.0/+download/cirros-0.3.0-x86_64-disk.img"
|
||||
|
||||
# uec style cirros image
|
||||
image_urls = "http://launchpad.net/cirros/trunk/0.3.0/+download/cirros-0.3.0-x86_64-uec.tar.gz"
|
||||
|
||||
[passwords]
|
||||
|
||||
sql = ${MYSQL_PASSWORD:-}
|
||||
rabbit = ${RABBIT_PASSWORD:-}
|
||||
horizon = ${ADMIN_PASSWORD:-}
|
||||
service_token = ${SERVICE_TOKEN:-}
|
||||
|
20
conf/swift/account-server.conf
Normal file
20
conf/swift/account-server.conf
Normal file
@ -0,0 +1,20 @@
|
||||
[DEFAULT]
|
||||
devices = %NODE_PATH%/node
|
||||
mount_check = false
|
||||
bind_port = %BIND_PORT%
|
||||
user = %USER%
|
||||
log_facility = LOG_LOCAL%LOG_FACILITY%
|
||||
swift_dir = %SWIFT_CONFIG_LOCATION%
|
||||
|
||||
[pipeline:main]
|
||||
pipeline = account-server
|
||||
|
||||
[app:account-server]
|
||||
use = egg:swift#account
|
||||
|
||||
[account-replicator]
|
||||
vm_test_mode = yes
|
||||
|
||||
[account-auditor]
|
||||
|
||||
[account-reaper]
|
22
conf/swift/container-server.conf
Normal file
22
conf/swift/container-server.conf
Normal file
@ -0,0 +1,22 @@
|
||||
[DEFAULT]
|
||||
devices = %NODE_PATH%/node
|
||||
mount_check = false
|
||||
bind_port = %BIND_PORT%
|
||||
user = %USER%
|
||||
log_facility = LOG_LOCAL%LOG_FACILITY%
|
||||
swift_dir = %SWIFT_CONFIG_LOCATION%
|
||||
|
||||
[pipeline:main]
|
||||
pipeline = container-server
|
||||
|
||||
[app:container-server]
|
||||
use = egg:swift#container
|
||||
|
||||
[container-replicator]
|
||||
vm_test_mode = yes
|
||||
|
||||
[container-updater]
|
||||
|
||||
[container-auditor]
|
||||
|
||||
[container-sync]
|
20
conf/swift/object-server.conf
Normal file
20
conf/swift/object-server.conf
Normal file
@ -0,0 +1,20 @@
|
||||
[DEFAULT]
|
||||
devices = %NODE_PATH%/node
|
||||
mount_check = false
|
||||
bind_port = %BIND_PORT%
|
||||
user = %USER%
|
||||
log_facility = LOG_LOCAL%LOG_FACILITY%
|
||||
swift_dir = %SWIFT_CONFIG_LOCATION%
|
||||
|
||||
[pipeline:main]
|
||||
pipeline = object-server
|
||||
|
||||
[app:object-server]
|
||||
use = egg:swift#object
|
||||
|
||||
[object-replicator]
|
||||
vm_test_mode = yes
|
||||
|
||||
[object-updater]
|
||||
|
||||
[object-auditor]
|
33
conf/swift/proxy-server.conf
Normal file
33
conf/swift/proxy-server.conf
Normal file
@ -0,0 +1,33 @@
|
||||
[DEFAULT]
|
||||
bind_port = 8080
|
||||
user = %USER%
|
||||
log_facility = LOG_LOCAL1
|
||||
swift_dir = %SWIFT_CONFIG_LOCATION%
|
||||
|
||||
[pipeline:main]
|
||||
pipeline = healthcheck cache %AUTH_SERVER% proxy-server
|
||||
|
||||
[app:proxy-server]
|
||||
use = egg:swift#proxy
|
||||
allow_account_management = true
|
||||
account_autocreate = true
|
||||
|
||||
[filter:keystone]
|
||||
use = egg:swiftkeystone2#keystone2
|
||||
keystone_admin_token = %SERVICE_TOKEN%
|
||||
keystone_url = http://localhost:35357/v2.0
|
||||
keystone_swift_operator_roles = Member
|
||||
|
||||
[filter:tempauth]
|
||||
use = egg:swift#tempauth
|
||||
user_admin_admin = admin .admin .reseller_admin
|
||||
user_test_tester = testing .admin
|
||||
user_test2_tester2 = testing2 .admin
|
||||
user_test_tester3 = testing3
|
||||
bind_ip = 0.0.0.0
|
||||
|
||||
[filter:healthcheck]
|
||||
use = egg:swift#healthcheck
|
||||
|
||||
[filter:cache]
|
||||
use = egg:swift#memcache
|
79
conf/swift/rsyncd.conf
Normal file
79
conf/swift/rsyncd.conf
Normal file
@ -0,0 +1,79 @@
|
||||
uid = %USER%
|
||||
gid = %GROUP%
|
||||
log file = /var/log/rsyncd.log
|
||||
pid file = /var/run/rsyncd.pid
|
||||
address = 127.0.0.1
|
||||
|
||||
[account6012]
|
||||
max connections = 25
|
||||
path = %SWIFT_DATA_LOCATION%/1/node/
|
||||
read only = false
|
||||
lock file = /var/lock/account6012.lock
|
||||
|
||||
[account6022]
|
||||
max connections = 25
|
||||
path = %SWIFT_DATA_LOCATION%/2/node/
|
||||
read only = false
|
||||
lock file = /var/lock/account6022.lock
|
||||
|
||||
[account6032]
|
||||
max connections = 25
|
||||
path = %SWIFT_DATA_LOCATION%/3/node/
|
||||
read only = false
|
||||
lock file = /var/lock/account6032.lock
|
||||
|
||||
[account6042]
|
||||
max connections = 25
|
||||
path = %SWIFT_DATA_LOCATION%/4/node/
|
||||
read only = false
|
||||
lock file = /var/lock/account6042.lock
|
||||
|
||||
|
||||
[container6011]
|
||||
max connections = 25
|
||||
path = %SWIFT_DATA_LOCATION%/1/node/
|
||||
read only = false
|
||||
lock file = /var/lock/container6011.lock
|
||||
|
||||
[container6021]
|
||||
max connections = 25
|
||||
path = %SWIFT_DATA_LOCATION%/2/node/
|
||||
read only = false
|
||||
lock file = /var/lock/container6021.lock
|
||||
|
||||
[container6031]
|
||||
max connections = 25
|
||||
path = %SWIFT_DATA_LOCATION%/3/node/
|
||||
read only = false
|
||||
lock file = /var/lock/container6031.lock
|
||||
|
||||
[container6041]
|
||||
max connections = 25
|
||||
path = %SWIFT_DATA_LOCATION%/4/node/
|
||||
read only = false
|
||||
lock file = /var/lock/container6041.lock
|
||||
|
||||
|
||||
[object6010]
|
||||
max connections = 25
|
||||
path = %SWIFT_DATA_LOCATION%/1/node/
|
||||
read only = false
|
||||
lock file = /var/lock/object6010.lock
|
||||
|
||||
[object6020]
|
||||
max connections = 25
|
||||
path = %SWIFT_DATA_LOCATION%/2/node/
|
||||
read only = false
|
||||
lock file = /var/lock/object6020.lock
|
||||
|
||||
[object6030]
|
||||
max connections = 25
|
||||
path = %SWIFT_DATA_LOCATION%/3/node/
|
||||
read only = false
|
||||
lock file = /var/lock/object6030.lock
|
||||
|
||||
[object6040]
|
||||
max connections = 25
|
||||
path = %SWIFT_DATA_LOCATION%/4/node/
|
||||
read only = false
|
||||
lock file = /var/lock/object6040.lock
|
26
conf/swift/swift-remakerings
Executable file
26
conf/swift/swift-remakerings
Executable file
@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd %SWIFT_CONFIG_LOCATION%
|
||||
|
||||
rm -f *.builder *.ring.gz backups/*.builder backups/*.ring.gz
|
||||
|
||||
swift-ring-builder object.builder create %SWIFT_PARTITION_POWER_SIZE% 3 1
|
||||
swift-ring-builder object.builder add z1-127.0.0.1:6010/sdb1 1
|
||||
swift-ring-builder object.builder add z2-127.0.0.1:6020/sdb2 1
|
||||
swift-ring-builder object.builder add z3-127.0.0.1:6030/sdb3 1
|
||||
swift-ring-builder object.builder add z4-127.0.0.1:6040/sdb4 1
|
||||
swift-ring-builder object.builder rebalance
|
||||
|
||||
swift-ring-builder container.builder create %SWIFT_PARTITION_POWER_SIZE% 3 1
|
||||
swift-ring-builder container.builder add z1-127.0.0.1:6011/sdb1 1
|
||||
swift-ring-builder container.builder add z2-127.0.0.1:6021/sdb2 1
|
||||
swift-ring-builder container.builder add z3-127.0.0.1:6031/sdb3 1
|
||||
swift-ring-builder container.builder add z4-127.0.0.1:6041/sdb4 1
|
||||
swift-ring-builder container.builder rebalance
|
||||
|
||||
swift-ring-builder account.builder create %SWIFT_PARTITION_POWER_SIZE% 3 1
|
||||
swift-ring-builder account.builder add z1-127.0.0.1:6012/sdb1 1
|
||||
swift-ring-builder account.builder add z2-127.0.0.1:6022/sdb2 1
|
||||
swift-ring-builder account.builder add z3-127.0.0.1:6032/sdb3 1
|
||||
swift-ring-builder account.builder add z4-127.0.0.1:6042/sdb4 1
|
||||
swift-ring-builder account.builder rebalance
|
3
conf/swift/swift-startmain
Executable file
3
conf/swift/swift-startmain
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
swift-init all restart
|
3
conf/swift/swift.conf
Normal file
3
conf/swift/swift.conf
Normal file
@ -0,0 +1,3 @@
|
||||
[swift-hash]
|
||||
# random unique string that can never change (DO NOT LOSE)
|
||||
swift_hash_path_suffix = %SWIFT_HASH%
|
67
devstack/Component.py
Normal file
67
devstack/Component.py
Normal file
@ -0,0 +1,67 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import Util
|
||||
|
||||
"""
|
||||
An abstraction that different components
|
||||
can inherit from to perform or basic install
|
||||
and configure and uninstall actions.
|
||||
"""
|
||||
|
||||
|
||||
class ComponentBase():
|
||||
def __init__(self, component_name, *args, **kargs):
|
||||
self.cfg = kargs.get("cfg")
|
||||
self.packager = kargs.get("pkg")
|
||||
self.distro = kargs.get("distro")
|
||||
self.root = kargs.get("root")
|
||||
self.othercomponents = kargs.get("components")
|
||||
pths = Util.component_pths(self.root, component_name)
|
||||
self.componentroot = pths.get('root_dir')
|
||||
self.tracedir = pths.get("trace_dir")
|
||||
self.appdir = pths.get("app_dir")
|
||||
self.cfgdir = pths.get('config_dir')
|
||||
|
||||
#
|
||||
#the following are just interfaces...
|
||||
#
|
||||
|
||||
|
||||
class InstallComponent():
|
||||
def download(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def configure(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def install(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class UninstallComponent():
|
||||
def unconfigure(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def uninstall(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class RuntimeComponent():
|
||||
def start(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def stop(self):
|
||||
raise NotImplementedError()
|
82
devstack/Config.py
Normal file
82
devstack/Config.py
Normal file
@ -0,0 +1,82 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import re
|
||||
import ConfigParser
|
||||
|
||||
import Shell
|
||||
import Logger
|
||||
import Exceptions
|
||||
from Exceptions import (BadParamException)
|
||||
|
||||
LOG = Logger.getLogger("install.config")
|
||||
PW_TMPL = "Enter a password for %s: "
|
||||
ENV_PAT = re.compile(r"^\s*\$\{([\w\d]+):\-(.*)\}\s*$")
|
||||
|
||||
|
||||
class EnvConfigParser(ConfigParser.RawConfigParser):
|
||||
def __init__(self):
|
||||
ConfigParser.RawConfigParser.__init__(self)
|
||||
self.pws = dict()
|
||||
|
||||
def _makekey(self, section, option):
|
||||
key = option + "@" + section
|
||||
return key
|
||||
|
||||
def get(self, section, option):
|
||||
key = self._makekey(section, option)
|
||||
LOG.debug("Fetching value for param %s" % (key))
|
||||
v = self._get_special(section, option)
|
||||
LOG.debug("Fetched \"%s\" for %s" % (v, key))
|
||||
return v
|
||||
|
||||
def _get_special(self, section, option):
|
||||
key = self._makekey(section, option)
|
||||
v = ConfigParser.RawConfigParser.get(self, section, option)
|
||||
if(v == None):
|
||||
return v
|
||||
mtch = ENV_PAT.match(v)
|
||||
if(mtch):
|
||||
env = mtch.group(1).strip()
|
||||
defv = mtch.group(2)
|
||||
if(len(defv) == 0 and len(env) == 0):
|
||||
msg = "Invalid bash-like value %s for %s" % (v, key)
|
||||
raise BadParamException(msg)
|
||||
if(len(env) == 0):
|
||||
return defv
|
||||
LOG.debug("Looking up environment variable %s" % (env))
|
||||
v = os.getenv(env)
|
||||
if(v == None):
|
||||
LOG.debug("Could not find anything in environment variable %s (using default value)" % (env))
|
||||
v = defv
|
||||
return v
|
||||
else:
|
||||
return v
|
||||
|
||||
def getpw(self, section, option):
|
||||
key = self._makekey(section, option)
|
||||
pw = self.pws.get(key)
|
||||
if(pw != None):
|
||||
return pw
|
||||
pw = self.get(section, option)
|
||||
if(pw == None):
|
||||
pw = ""
|
||||
if(len(pw) == 0):
|
||||
while(len(pw) == 0):
|
||||
pw = Shell.password(PW_TMPL % (key))
|
||||
LOG.debug("Password for %s will be %s" % (key, pw))
|
||||
self.pws[key] = pw
|
||||
return pw
|
244
devstack/Db.py
Normal file
244
devstack/Db.py
Normal file
@ -0,0 +1,244 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import Logger
|
||||
import Component
|
||||
from Component import (ComponentBase, RuntimeComponent,
|
||||
UninstallComponent, InstallComponent)
|
||||
import Util
|
||||
from Util import (DB,
|
||||
get_pkg_list, param_replace,
|
||||
joinlinesep)
|
||||
import Trace
|
||||
from Trace import (TraceWriter, TraceReader)
|
||||
import Shell
|
||||
from Shell import (mkdirslist, execute, deldir)
|
||||
|
||||
LOG = Logger.getLogger("install.mysql")
|
||||
TYPE = DB
|
||||
|
||||
#TODO maybe someday this should be in the pkg info?
|
||||
TYPE_ACTIONS = {
|
||||
'mysql': {
|
||||
'start': ["/etc/init.d/mysql", "start"],
|
||||
'stop' : ["/etc/init.d/mysql", "stop"],
|
||||
'create_db': 'CREATE DATABASE %s;',
|
||||
'drop_db': 'DROP DATABASE IF EXISTS %s;',
|
||||
"before_install": [
|
||||
{
|
||||
'cmd': ["debconf-set-selections"],
|
||||
'stdin': [
|
||||
"mysql-server-5.1 mysql-server/root_password password %PASSWORD%",
|
||||
"mysql-server-5.1 mysql-server/root_password_again password %PASSWORD%",
|
||||
"mysql-server-5.1 mysql-server/start_on_boot boolean %BOOT_START%",
|
||||
],
|
||||
'run_as_root': True,
|
||||
},
|
||||
],
|
||||
'after_install': [
|
||||
{
|
||||
'cmd': [
|
||||
"mysql",
|
||||
'-uroot',
|
||||
'-p%PASSWORD%',
|
||||
'-h127.0.0.1',
|
||||
'-e',
|
||||
"GRANT ALL PRIVILEGES ON *.* TO '%USER%'@'%' identified by '%PASSWORD%';",
|
||||
],
|
||||
'stdin': [],
|
||||
'run_as_root': False,
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
BASE_ERROR = 'Currently we do not know how to %s for database type [%s]'
|
||||
|
||||
|
||||
class DBUninstaller(ComponentBase, UninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
ComponentBase.__init__(self, TYPE, *args, **kargs)
|
||||
self.tracereader = TraceReader(self.tracedir, Trace.IN_TRACE)
|
||||
|
||||
def unconfigure(self):
|
||||
#nothing to unconfigure, we are just a pkg
|
||||
pass
|
||||
|
||||
def uninstall(self):
|
||||
#clean out removeable packages
|
||||
pkgsfull = self.tracereader.packages_installed()
|
||||
if(len(pkgsfull)):
|
||||
am = len(pkgsfull)
|
||||
LOG.info("Removing %s packages" % (am))
|
||||
self.packager.remove_batch(pkgsfull)
|
||||
dirsmade = self.tracereader.dirs_made()
|
||||
if(len(dirsmade)):
|
||||
am = len(dirsmade)
|
||||
LOG.info("Removing %s created directories" % (am))
|
||||
for dirname in dirsmade:
|
||||
deldir(dirname)
|
||||
LOG.info("Removed %s" % (dirname))
|
||||
|
||||
|
||||
class DBInstaller(ComponentBase, InstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
ComponentBase.__init__(self, TYPE, *args, **kargs)
|
||||
self.tracewriter = TraceWriter(self.tracedir, Trace.IN_TRACE)
|
||||
|
||||
def download(self):
|
||||
#nothing to download, we are just a pkg
|
||||
pass
|
||||
|
||||
def configure(self):
|
||||
#nothing to configure, we are just a pkg
|
||||
pass
|
||||
|
||||
def _run_install_cmds(self, cmds):
|
||||
if(not cmds or len(cmds) == 0):
|
||||
return
|
||||
installparams = self._get_install_params()
|
||||
for cmdinfo in cmds:
|
||||
cmd_to_run_templ = cmdinfo.get("cmd")
|
||||
if(not cmd_to_run_templ):
|
||||
continue
|
||||
cmd_to_run = list()
|
||||
for piece in cmd_to_run_templ:
|
||||
cmd_to_run.append(param_replace(piece, installparams))
|
||||
stdin_templ = cmdinfo.get('stdin')
|
||||
stdin = None
|
||||
if(stdin_templ):
|
||||
stdin_full = list()
|
||||
for piece in stdin_templ:
|
||||
stdin_full.append(param_replace(piece, installparams))
|
||||
stdin = joinlinesep(stdin_full)
|
||||
root_run = cmdinfo.get('run_as_root', True)
|
||||
execute(*cmd_to_run, process_input=stdin, run_as_root=root_run)
|
||||
|
||||
def _get_install_params(self):
|
||||
out = dict()
|
||||
out['PASSWORD'] = self.cfg.getpw("passwords", "sql")
|
||||
out['BOOT_START'] = str(True).lower()
|
||||
out['USER'] = self.cfg.get("db", "sql_user")
|
||||
return out
|
||||
|
||||
def _pre_install(self, pkgs):
|
||||
dbtype = self.cfg.get("db", "type")
|
||||
dbactions = TYPE_ACTIONS.get(dbtype)
|
||||
if(dbactions and dbactions.get("before_install")):
|
||||
LOG.info("Running pre-install commands.")
|
||||
self._run_install_cmds(dbactions.get("before_install"))
|
||||
|
||||
def _post_install(self, pkgs):
|
||||
dbtype = self.cfg.get("db", "type")
|
||||
dbactions = TYPE_ACTIONS.get(dbtype)
|
||||
if(dbactions and dbactions.get("after_install")):
|
||||
LOG.info("Running post-install commands.")
|
||||
self._run_install_cmds(dbactions.get("after_install"))
|
||||
|
||||
def install(self):
|
||||
#just install the pkgs
|
||||
pkgs = get_pkg_list(self.distro, TYPE)
|
||||
#run any pre-installs cmds
|
||||
self._pre_install(pkgs)
|
||||
#now install the pkgs
|
||||
pkgnames = sorted(pkgs.keys())
|
||||
LOG.debug("Installing packages %s" % (", ".join(pkgnames)))
|
||||
installparams = self._get_install_params()
|
||||
self.packager.install_batch(pkgs, installparams)
|
||||
for name in pkgnames:
|
||||
packageinfo = pkgs.get(name)
|
||||
version = packageinfo.get("version", "")
|
||||
remove = packageinfo.get("removable", True)
|
||||
# This trace is used to remove the pkgs
|
||||
self.tracewriter.package_install(name, remove, version)
|
||||
dirsmade = mkdirslist(self.tracedir)
|
||||
# This trace is used to remove the dirs created
|
||||
self.tracewriter.dir_made(*dirsmade)
|
||||
#run any post-installs cmds
|
||||
self._post_install(pkgs)
|
||||
#TODO
|
||||
# # Update the DB to give user "$MYSQL_USER"@"%" full control of the all databases:
|
||||
#sudo mysql -uroot -p$MYSQL_PASSWORD -h127.0.0.1 -e "GRANT ALL PRIVILEGES ON *.* TO '$MYSQL_USER'@'%' identified by '$MYSQL_PASSWORD';"
|
||||
#TODO
|
||||
# Edit /etc/mysql/my.cnf to change "bind-address" from localhost (127.0.0.1) to any (0.0.0.0) and stop the mysql service:
|
||||
#sudo sed -i 's/127.0.0.1/0.0.0.0/g' /etc/mysql/my.cnf
|
||||
return self.tracedir
|
||||
|
||||
|
||||
class DBRuntime(ComponentBase, RuntimeComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
ComponentBase.__init__(self, TYPE, *args, **kargs)
|
||||
self.tracereader = TraceReader(self.tracedir, Trace.IN_TRACE)
|
||||
|
||||
def start(self):
|
||||
pkgsinstalled = self.tracereader.packages_installed()
|
||||
if(len(pkgsinstalled) == 0):
|
||||
msg = "Can not start %s since it was not installed" % (TYPE)
|
||||
raise StartException(msg)
|
||||
dbtype = cfg.get("db", "type")
|
||||
typeactions = TYPE_ACTIONS.get(dbtype.lower())
|
||||
if(typeactions == None):
|
||||
msg = BASE_ERROR % ('start', dbtype)
|
||||
raise NotImplementedError(msg)
|
||||
startcmd = typeactions.get('start')
|
||||
if(startcmd):
|
||||
execute(*startcmd, run_as_root=True)
|
||||
return None
|
||||
|
||||
def stop(self):
|
||||
pkgsinstalled = self.tracereader.packages_installed()
|
||||
if(len(pkgsinstalled) == 0):
|
||||
msg = "Can not stop %s since it was not installed" % (TYPE)
|
||||
raise StopException(msg)
|
||||
dbtype = cfg.get("db", "type")
|
||||
typeactions = TYPE_ACTIONS.get(dbtype.lower())
|
||||
if(typeactions == None):
|
||||
msg = BASE_ERROR % ('start', dbtype)
|
||||
stopcmd = typeactions.get('stop')
|
||||
if(stopcmd):
|
||||
execute(*stopcmd, run_as_root=True)
|
||||
return None
|
||||
|
||||
|
||||
def drop_db(cfg, dbname):
|
||||
dbtype = cfg.get("db", "type")
|
||||
dbtypelo = dbtype.lower()
|
||||
if(dbtypelo == 'mysql'):
|
||||
#drop it
|
||||
basesql = TYPE_ACTIONS.get(dbtypelo).get('drop_db')
|
||||
sql = basesql % (dbname)
|
||||
user = cfg.get("db", "sql_user")
|
||||
pw = cfg.get("passwords", "sql")
|
||||
cmd = ['mysql', '-u' + user, '-p' + pw, '-e', sql]
|
||||
execute(*cmd)
|
||||
else:
|
||||
msg = BASE_ERROR % ('drop', dbtype)
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
|
||||
def create_db(cfg, dbname):
|
||||
dbtype = cfg.get("db", "type")
|
||||
dbtypelo = dbtype.lower()
|
||||
if(dbtypelo == 'mysql'):
|
||||
#create it
|
||||
basesql = TYPE_ACTIONS.get(dbtypelo).get('create_db')
|
||||
sql = basesql % (dbname)
|
||||
user = cfg.get("db", "sql_user")
|
||||
pw = cfg.get("passwords", "sql")
|
||||
cmd = ['mysql', '-u' + user, '-p' + pw, '-e', sql]
|
||||
execute(*cmd)
|
||||
else:
|
||||
msg = BASE_ERROR % ('create', dbtype)
|
||||
raise NotImplementedError(msg)
|
32
devstack/Downloader.py
Normal file
32
devstack/Downloader.py
Normal file
@ -0,0 +1,32 @@
|
||||
from urlparse import urlparse
|
||||
import re
|
||||
|
||||
from Shell import (execute, mkdirslist)
|
||||
from Util import (create_regex, MASTER_BRANCH)
|
||||
import Logger
|
||||
|
||||
LOG = Logger.getLogger("install.downloader")
|
||||
EXT_REG = create_regex(r"/^(.*?)\.git\s*$/i")
|
||||
|
||||
|
||||
def _gitdownload(storewhere, uri, branch=None):
|
||||
dirsmade = mkdirslist(storewhere)
|
||||
LOG.info("Downloading from %s to %s" % (uri, storewhere))
|
||||
cmd = ["git", "clone"] + [uri, storewhere]
|
||||
execute(*cmd)
|
||||
if(branch and branch != MASTER_BRANCH):
|
||||
LOG.info("Adjusting git branch to %s" % (branch))
|
||||
cmd = ['git', 'checkout'] + [branch]
|
||||
execute(*cmd, cwd=storewhere)
|
||||
return dirsmade
|
||||
|
||||
|
||||
def download(storewhere, uri, branch=None):
|
||||
#figure out which type
|
||||
up = urlparse(uri)
|
||||
if(up and up.scheme.lower() == "git" or
|
||||
EXT_REG.match(up.path)):
|
||||
return _gitdownload(storewhere, uri, branch)
|
||||
else:
|
||||
msg = "Currently we do not know how to download %s" % (uri)
|
||||
raise NotImplementedError(msg)
|
60
devstack/Exceptions.py
Normal file
60
devstack/Exceptions.py
Normal file
@ -0,0 +1,60 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
class InstallException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BadRegexException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BadParamException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class NoReplacementException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class StartException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class StopException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class FileException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ProcessExecutionError(IOError):
|
||||
def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None,
|
||||
description=None):
|
||||
self.exit_code = exit_code
|
||||
self.stderr = stderr
|
||||
self.stdout = stdout
|
||||
self.cmd = cmd
|
||||
self.description = description
|
||||
if description is None:
|
||||
description = ('Unexpected error while running command.')
|
||||
if exit_code is None:
|
||||
exit_code = '-'
|
||||
message = ('%(description)s\nCommand: %(cmd)s\n'
|
||||
'Exit code: %(exit_code)s\nStdout: %(stdout)r\n'
|
||||
'Stderr: %(stderr)r' % locals())
|
||||
IOError.__init__(self, message)
|
307
devstack/Glance.py
Normal file
307
devstack/Glance.py
Normal file
@ -0,0 +1,307 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
import os.path
|
||||
|
||||
import Logger
|
||||
import Component
|
||||
import Shell
|
||||
import Util
|
||||
import Trace
|
||||
from Trace import (TraceWriter, TraceReader)
|
||||
import Downloader
|
||||
import Runner
|
||||
import runners.Foreground as Foreground
|
||||
from runners.Foreground import (ForegroundRunner)
|
||||
from Util import (GLANCE,
|
||||
get_pkg_list,
|
||||
param_replace, get_dbdsn,
|
||||
)
|
||||
from Shell import (execute, deldir, mkdirslist, unlink,
|
||||
joinpths, load_file, write_file, touch_file)
|
||||
import Exceptions
|
||||
from Exceptions import (StopException, StartException, InstallException)
|
||||
|
||||
LOG = Logger.getLogger("install.glance")
|
||||
|
||||
#naming + config files
|
||||
TYPE = GLANCE
|
||||
API_CONF = "glance-api.conf"
|
||||
REG_CONF = "glance-registry.conf"
|
||||
CONFIGS = [API_CONF, REG_CONF]
|
||||
DB_NAME = "glance"
|
||||
|
||||
#why doesn't --record do anything??
|
||||
PY_INSTALL = ['python', 'setup.py', 'develop']
|
||||
PY_UNINSTALL = ['python', 'setup.py', 'develop', '--uninstall']
|
||||
|
||||
#what to start
|
||||
APPS_TO_START = ['glance-api', 'glance-registry']
|
||||
APP_OPTIONS = {
|
||||
'glance-api': ['--config-file', joinpths('%ROOT%', "etc", API_CONF)],
|
||||
'glance-registry': ['--config-file', joinpths('%ROOT%', "etc", REG_CONF)]
|
||||
}
|
||||
|
||||
|
||||
class GlanceBase(Component.ComponentBase):
|
||||
def __init__(self, *args, **kargs):
|
||||
Component.ComponentBase.__init__(self, TYPE, *args, **kargs)
|
||||
#note not config
|
||||
self.cfgdir = joinpths(self.appdir, "etc")
|
||||
|
||||
|
||||
class GlanceUninstaller(GlanceBase, Component.UninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
GlanceBase.__init__(self, *args, **kargs)
|
||||
self.tracereader = TraceReader(self.tracedir, Trace.IN_TRACE)
|
||||
|
||||
def unconfigure(self):
|
||||
#get rid of all files configured
|
||||
cfgfiles = self.tracereader.files_configured()
|
||||
if(len(cfgfiles)):
|
||||
am = len(cfgfiles)
|
||||
LOG.info("Removing %s configuration files" % (am))
|
||||
for fn in cfgfiles:
|
||||
if(len(fn)):
|
||||
unlink(fn)
|
||||
LOG.info("Removed %s" % (fn))
|
||||
|
||||
def uninstall(self):
|
||||
#clean out removeable packages
|
||||
pkgsfull = self.tracereader.packages_installed()
|
||||
if(len(pkgsfull)):
|
||||
am = len(pkgsfull)
|
||||
LOG.info("Removing %s packages" % (am))
|
||||
self.packager.remove_batch(pkgsfull)
|
||||
#clean out files touched
|
||||
filestouched = self.tracereader.files_touched()
|
||||
if(len(filestouched)):
|
||||
am = len(pkgsfull)
|
||||
LOG.info("Removing %s touched files" % (am))
|
||||
for fn in filestouched:
|
||||
if(len(fn)):
|
||||
unlink(fn)
|
||||
LOG.info("Removed %s" % (fn))
|
||||
#undevelop python???
|
||||
#how should this be done??
|
||||
pylisting = self.tracereader.py_listing()
|
||||
if(pylisting != None):
|
||||
execute(*PY_UNINSTALL, cwd=self.appdir, run_as_root=True)
|
||||
#clean out dirs created
|
||||
dirsmade = self.tracereader.dirs_made()
|
||||
if(len(dirsmade)):
|
||||
am = len(dirsmade)
|
||||
LOG.info("Removing %s created directories" % (am))
|
||||
for dirname in dirsmade:
|
||||
deldir(dirname)
|
||||
LOG.info("Removed %s" % (dirname))
|
||||
|
||||
|
||||
class GlanceRuntime(GlanceBase, Component.RuntimeComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
GlanceBase.__init__(self, *args, **kargs)
|
||||
self.foreground = kargs.get("foreground", True)
|
||||
self.tracereader = TraceReader(self.tracedir, Trace.IN_TRACE)
|
||||
self.tracewriter = TraceWriter(self.tracedir, Trace.START_TRACE)
|
||||
self.starttracereader = TraceReader(self.tracedir, Trace.START_TRACE)
|
||||
|
||||
def start(self):
|
||||
#ensure it was installed
|
||||
pylisting = self.tracereader.py_listing()
|
||||
if(len(pylisting) == 0):
|
||||
msg = "Can not start %s since it was not installed" % (TYPE)
|
||||
raise StartException(msg)
|
||||
#select how we are going to start i
|
||||
if(self.foreground):
|
||||
starter = ForegroundRunner()
|
||||
else:
|
||||
raise NotImplementedError("Can not yet start in screen mode")
|
||||
#start all apps
|
||||
fns = list()
|
||||
replacements = dict()
|
||||
replacements['ROOT'] = self.appdir
|
||||
for app in APPS_TO_START:
|
||||
#adjust the program options now that we have real locations
|
||||
program_opts = []
|
||||
for opt in APP_OPTIONS.get(app):
|
||||
program_opts.append(param_replace(opt, replacements))
|
||||
LOG.info("Starting %s with options [%s]" % (app, ", ".join(program_opts)))
|
||||
#start it with the given settings
|
||||
fn = starter.start(app, app, *program_opts,
|
||||
app_dir=self.appdir, trace_dir=self.tracedir)
|
||||
if(fn):
|
||||
fns.append(fn)
|
||||
LOG.info("Started %s, details are in %s" % (app, fn))
|
||||
# This trace is used to locate details about what to stop
|
||||
self.tracewriter.started_info(app, fn)
|
||||
else:
|
||||
LOG.info("Started %s" % (app))
|
||||
return fns
|
||||
|
||||
def stop(self):
|
||||
#ensure it was installed
|
||||
pylisting = self.tracereader.py_listing()
|
||||
if(pylisting == None or len(pylisting) == 0):
|
||||
msg = "Can not start %s since it was not installed" % (TYPE)
|
||||
raise StopException(msg)
|
||||
#we can only stop what has a started trace
|
||||
start_traces = self.starttracereader.apps_started()
|
||||
killedam = 0
|
||||
for mp in start_traces:
|
||||
#extract the apps name and where its trace is
|
||||
fn = mp.get('trace_fn')
|
||||
name = mp.get('name')
|
||||
#missing some key info, skip it
|
||||
if(fn == None or name == None):
|
||||
continue
|
||||
#figure out which class will stop it
|
||||
contents = Trace.parse_fn(fn)
|
||||
runtype = None
|
||||
for (cmd, action) in contents:
|
||||
if(cmd == Runner.RUN_TYPE and action == Foreground.RUN_TYPE):
|
||||
runtype = ForegroundRunner
|
||||
break
|
||||
#we can try to stop it
|
||||
if(runtype != None):
|
||||
LOG.info("Stopping %s with %s in %s" % (name, runtype, self.tracedir))
|
||||
killer = runtype()
|
||||
killer.stop(name, trace_dir=self.tracedir)
|
||||
killedam += 1
|
||||
#if we got rid of them all get rid of the trace
|
||||
if(killedam == len(start_traces)):
|
||||
fn = self.starttracereader.trace_fn
|
||||
LOG.info("Deleting trace file %s" % (fn))
|
||||
unlink(fn)
|
||||
|
||||
|
||||
class GlanceInstaller(GlanceBase, Component.InstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
GlanceBase.__init__(self, *args, **kargs)
|
||||
self.gitloc = self.cfg.get("git", "glance_repo")
|
||||
self.brch = self.cfg.get("git", "glance_branch")
|
||||
self.tracewriter = TraceWriter(self.tracedir, Trace.IN_TRACE)
|
||||
|
||||
def download(self):
|
||||
dirsmade = Downloader.download(self.appdir, self.gitloc, self.brch)
|
||||
# This trace isn't used yet but could be
|
||||
self.tracewriter.downloaded(self.appdir, self.gitloc)
|
||||
# This trace is used to remove the dirs created
|
||||
self.tracewriter.dir_made(*dirsmade)
|
||||
return self.tracedir
|
||||
|
||||
def install(self):
|
||||
#get all the packages for glance for the specified distro
|
||||
pkgs = get_pkg_list(self.distro, TYPE)
|
||||
pkgnames = pkgs.keys()
|
||||
pkgnames.sort()
|
||||
LOG.debug("Installing packages %s" % (", ".join(pkgnames)))
|
||||
self.packager.install_batch(pkgs)
|
||||
for name in pkgnames:
|
||||
packageinfo = pkgs.get(name)
|
||||
version = packageinfo.get("version", "")
|
||||
remove = packageinfo.get("removable", True)
|
||||
# This trace is used to remove the pkgs
|
||||
self.tracewriter.package_install(name, remove, version)
|
||||
#make a directory for the python trace file (if its not already there)
|
||||
dirsmade = mkdirslist(self.tracedir)
|
||||
# This trace is used to remove the dirs created
|
||||
self.tracewriter.dir_made(*dirsmade)
|
||||
recordwhere = Trace.touch_trace(self.tracedir, Trace.PY_TRACE)
|
||||
# This trace is used to remove the trace created
|
||||
self.tracewriter.py_install(recordwhere)
|
||||
(sysout, stderr) = execute(*PY_INSTALL, cwd=self.appdir, run_as_root=True)
|
||||
write_file(recordwhere, sysout)
|
||||
return self.tracedir
|
||||
|
||||
def configure(self):
|
||||
dirsmade = mkdirslist(self.cfgdir)
|
||||
# This trace is used to remove the dirs created
|
||||
self.tracewriter.dir_made(*dirsmade)
|
||||
for fn in CONFIGS:
|
||||
#go through each config in devstack (which is really a template)
|
||||
#and adjust that template to have real values and then go through
|
||||
#the resultant config file and perform and adjustments (directory creation...)
|
||||
#and then write that to the glance configuration directory.
|
||||
sourcefn = joinpths(Util.STACK_CONFIG_DIR, TYPE, fn)
|
||||
tgtfn = joinpths(self.cfgdir, fn)
|
||||
LOG.info("Configuring template file %s" % (sourcefn))
|
||||
contents = load_file(sourcefn)
|
||||
pmap = self._get_param_map(fn)
|
||||
LOG.info("Replacing parameters in file %s" % (sourcefn))
|
||||
LOG.debug("Replacements = %s" % (pmap))
|
||||
contents = param_replace(contents, pmap)
|
||||
LOG.debug("Applying side-effects of param replacement for template %s" % (sourcefn))
|
||||
self._config_apply(contents, fn)
|
||||
LOG.info("Writing configuration file %s" % (tgtfn))
|
||||
write_file(tgtfn, contents)
|
||||
# This trace is used to remove the files configured
|
||||
self.tracewriter.cfg_write(tgtfn)
|
||||
return self.tracedir
|
||||
|
||||
def _config_apply(self, contents, fn):
|
||||
lines = contents.splitlines()
|
||||
for line in lines:
|
||||
cleaned = line.strip()
|
||||
if(len(cleaned) == 0 or cleaned[0] == '#' or cleaned[0] == '['):
|
||||
#not useful to examine these
|
||||
continue
|
||||
pieces = cleaned.split("=", 1)
|
||||
if(len(pieces) != 2):
|
||||
continue
|
||||
key = pieces[0].strip()
|
||||
val = pieces[1].strip()
|
||||
if(len(key) == 0 or len(val) == 0):
|
||||
continue
|
||||
#now we take special actions
|
||||
if(key == 'filesystem_store_datadir'):
|
||||
# Delete existing images
|
||||
deldir(val)
|
||||
# Recreate
|
||||
dirsmade = mkdirslist(val)
|
||||
self.tracewriter.dir_made(*dirsmade)
|
||||
elif(key == 'log_file'):
|
||||
# Ensure that we can write to the log file
|
||||
dirname = os.path.dirname(val)
|
||||
if(len(dirname)):
|
||||
dirsmade = mkdirslist(dirname)
|
||||
# This trace is used to remove the dirs created
|
||||
self.tracewriter.dir_made(*dirsmade)
|
||||
# Destroy then recreate it
|
||||
unlink(val)
|
||||
touch_file(val)
|
||||
self.tracewriter.file_touched(val)
|
||||
elif(key == 'image_cache_datadir'):
|
||||
# Destroy then recreate it
|
||||
deldir(val)
|
||||
dirsmade = mkdirslist(val)
|
||||
# This trace is used to remove the dirs created
|
||||
self.tracewriter.dir_made(*dirsmade)
|
||||
elif(key == 'scrubber_datadir'):
|
||||
# Destroy then recreate it
|
||||
deldir(val)
|
||||
dirsmade = mkdirslist(val)
|
||||
# This trace is used to remove the dirs created
|
||||
self.tracewriter.dir_made(*dirsmade)
|
||||
|
||||
def _get_param_map(self, fn):
|
||||
# These be used to fill in the configuration
|
||||
# params with actual values
|
||||
mp = dict()
|
||||
mp['DEST'] = self.appdir
|
||||
mp['SYSLOG'] = self.cfg.getboolean("default", "syslog")
|
||||
mp['SERVICE_TOKEN'] = self.cfg.getpw("passwords", "service_token")
|
||||
mp['SQL_CONN'] = get_dbdsn(self.cfg, DB_NAME)
|
||||
return mp
|
45
devstack/Horizon.py
Normal file
45
devstack/Horizon.py
Normal file
@ -0,0 +1,45 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import Logger
|
||||
import Component
|
||||
|
||||
LOG = Logger.getLogger("install.horizon")
|
||||
|
||||
|
||||
class HorizonTraceWriter():
|
||||
def __init__(self, root):
|
||||
pass
|
||||
|
||||
|
||||
class HorizonTraceReader():
|
||||
def __init__(self, root):
|
||||
pass
|
||||
|
||||
|
||||
class HorizonUninstaller(Component.UninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
||||
|
||||
|
||||
class HorizonInstaller(Component.InstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
||||
|
||||
|
||||
class HorizonRuntime(Component.RuntimeComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
33
devstack/Img.py
Normal file
33
devstack/Img.py
Normal file
@ -0,0 +1,33 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
class Img():
|
||||
def download():
|
||||
pass
|
||||
|
||||
def install():
|
||||
pass
|
||||
|
||||
def remove():
|
||||
pass
|
||||
|
||||
|
||||
class ImgDB():
|
||||
def availableImages():
|
||||
pass
|
||||
|
||||
def installedImages():
|
||||
pass
|
158
devstack/Keystone.py
Normal file
158
devstack/Keystone.py
Normal file
@ -0,0 +1,158 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
||||
import Util
|
||||
from Util import (KEYSTONE, get_pkg_list, get_dbdsn,
|
||||
param_replace)
|
||||
import Logger
|
||||
import Component
|
||||
import Downloader
|
||||
import Trace
|
||||
from Trace import (TraceWriter, TraceReader)
|
||||
import Shell
|
||||
from Shell import (execute, mkdirslist, write_file,
|
||||
load_file, joinpths, touch_file,
|
||||
unlink)
|
||||
|
||||
LOG = Logger.getLogger("install.keystone")
|
||||
TYPE = KEYSTONE
|
||||
PY_INSTALL = ['python', 'setup.py', 'develop']
|
||||
ROOT_CONF = "keystone.conf"
|
||||
CONFIGS = [ROOT_CONF]
|
||||
BIN_DIR = "bin"
|
||||
DATA_SCRIPT = "keystone_data.sh"
|
||||
DB_NAME = "keystone"
|
||||
|
||||
class KeystoneBase(Component.ComponentBase):
|
||||
def __init__(self, *args, **kargs):
|
||||
Component.ComponentBase.__init__(self, TYPE, *args, **kargs)
|
||||
self.cfgdir = joinpths(self.appdir, Util.CONFIG_DIR)
|
||||
self.bindir = joinpths(self.appdir, BIN_DIR)
|
||||
|
||||
|
||||
class KeystoneUninstaller(KeystoneBase, Component.UninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
KeystoneBase.__init__(self, *args, **kargs)
|
||||
|
||||
|
||||
class KeystoneInstaller(KeystoneBase, Component.InstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
KeystoneBase.__init__(self, *args, **kargs)
|
||||
self.gitloc = self.cfg.get("git", "keystone_repo")
|
||||
self.brch = self.cfg.get("git", "keystone_branch")
|
||||
self.tracewriter = TraceWriter(self.tracedir, Trace.IN_TRACE)
|
||||
|
||||
def download(self):
|
||||
dirsmade = Downloader.download(self.appdir, self.gitloc, self.brch)
|
||||
# This trace isn't used yet but could be
|
||||
self.tracewriter.downloaded(self.appdir, self.gitloc)
|
||||
# This trace is used to remove the dirs created
|
||||
self.tracewriter.dir_made(*dirsmade)
|
||||
return self.tracedir
|
||||
|
||||
def install(self):
|
||||
pkgs = get_pkg_list(self.distro, TYPE)
|
||||
pkgnames = pkgs.keys()
|
||||
pkgnames.sort()
|
||||
LOG.debug("Installing packages %s" % (", ".join(pkgnames)))
|
||||
self.packager.install_batch(pkgs)
|
||||
for name in pkgnames:
|
||||
packageinfo = pkgs.get(name)
|
||||
version = packageinfo.get("version", "")
|
||||
remove = packageinfo.get("removable", True)
|
||||
# This trace is used to remove the pkgs
|
||||
self.tracewriter.package_install(name, remove, version)
|
||||
dirsmade = mkdirslist(self.tracedir)
|
||||
# This trace is used to remove the dirs created
|
||||
self.tracewriter.dir_made(*dirsmade)
|
||||
recordwhere = Trace.touch_trace(self.tracedir, Trace.PY_TRACE)
|
||||
# This trace is used to remove the trace created
|
||||
self.tracewriter.py_install(recordwhere)
|
||||
(sysout, stderr) = execute(*PY_INSTALL, cwd=self.appdir, run_as_root=True)
|
||||
write_file(recordwhere, sysout)
|
||||
#adjust db
|
||||
self._setup_db()
|
||||
#setup any data
|
||||
self._setup_data()
|
||||
return self.tracedir
|
||||
|
||||
def configure(self):
|
||||
dirsmade = mkdirslist(self.cfgdir)
|
||||
self.tracewriter.dir_made(*dirsmade)
|
||||
for fn in CONFIGS:
|
||||
sourcefn = joinpths(Util.STACK_CONFIG_DIR, TYPE, fn)
|
||||
tgtfn = joinpths(self.cfgdir, fn)
|
||||
LOG.info("Configuring template file %s" % (sourcefn))
|
||||
contents = load_file(sourcefn)
|
||||
pmap = self._get_param_map(fn)
|
||||
LOG.info("Replacing parameters in file %s" % (sourcefn))
|
||||
LOG.debug("Replacements = %s" % (pmap))
|
||||
contents = param_replace(contents, pmap)
|
||||
LOG.debug("Applying side-effects of param replacement for template %s" % (sourcefn))
|
||||
self._config_apply(contents, fn)
|
||||
LOG.info("Writing configuration file %s" % (tgtfn))
|
||||
write_file(tgtfn, contents)
|
||||
# This trace is used to remove the files configured
|
||||
self.tracewriter.cfg_write(tgtfn)
|
||||
return self.tracedir
|
||||
|
||||
def _setup_db(self):
|
||||
pass
|
||||
|
||||
def _setup_data(self):
|
||||
pass
|
||||
|
||||
def _config_apply(self, contents, fn):
|
||||
lines = contents.splitlines()
|
||||
for line in lines:
|
||||
cleaned = line.strip()
|
||||
if(len(cleaned) == 0 or cleaned[0] == '#' or cleaned[0] == '['):
|
||||
#not useful to examine these
|
||||
continue
|
||||
pieces = cleaned.split("=", 1)
|
||||
if(len(pieces) != 2):
|
||||
continue
|
||||
key = pieces[0].strip()
|
||||
val = pieces[1].strip()
|
||||
if(len(key) == 0 or len(val) == 0):
|
||||
continue
|
||||
#now we take special actions
|
||||
if(key == 'log_file'):
|
||||
# Ensure that we can write to the log file
|
||||
dirname = os.path.dirname(val)
|
||||
if(len(dirname)):
|
||||
dirsmade = mkdirslist(dirname)
|
||||
# This trace is used to remove the dirs created
|
||||
self.tracewriter.dir_made(*dirsmade)
|
||||
# Destroy then recreate it
|
||||
unlink(val)
|
||||
touch_file(val)
|
||||
self.tracewriter.file_touched(val)
|
||||
|
||||
def _get_param_map(self, fn):
|
||||
# These be used to fill in the configuration
|
||||
# params with actual values
|
||||
mp = dict()
|
||||
mp['DEST'] = self.appdir
|
||||
mp['SQL_CONN'] = get_dbdsn(self.cfg, DB_NAME)
|
||||
return mp
|
||||
|
||||
|
||||
class KeystoneRuntime(KeystoneBase, Component.RuntimeComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
KeystoneBase.__init__(self, *args, **kargs)
|
85
devstack/Logger.py
Normal file
85
devstack/Logger.py
Normal file
@ -0,0 +1,85 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
#requires http://pypi.python.org/pypi/termcolor
|
||||
#but the colors make it worth it :-)
|
||||
from termcolor import colored
|
||||
|
||||
#take this in from config??
|
||||
LOG_LEVEL = logging.DEBUG
|
||||
LOG_FORMAT = '%(levelname)s: @%(name)s : %(message)s'
|
||||
|
||||
|
||||
class TermFormatter(logging.Formatter):
|
||||
def __init__(self, fmt):
|
||||
logging.Formatter.__init__(self, fmt)
|
||||
|
||||
def format(self, record):
|
||||
lvl = record.levelno
|
||||
lvlname = record.levelname
|
||||
if(lvl == logging.DEBUG):
|
||||
lvlname = colored(lvlname, 'blue')
|
||||
elif(lvl == logging.INFO):
|
||||
lvlname = colored(lvlname, 'cyan')
|
||||
elif(lvl == logging.WARNING):
|
||||
lvlname = colored(lvlname, 'yellow')
|
||||
elif(lvl == logging.ERROR):
|
||||
lvlname = colored(lvlname, 'red')
|
||||
elif(lvl == logging.CRITICAL):
|
||||
lvlname = colored(lvlname, 'red')
|
||||
record.msg = colored(record.msg, attrs=['bold', 'blink'])
|
||||
record.levelname = lvlname
|
||||
return logging.Formatter.format(self, record)
|
||||
|
||||
|
||||
class TermHandler(logging.Handler):
|
||||
STREAM = sys.stdout
|
||||
DO_FLUSH = True
|
||||
NL = "\n"
|
||||
|
||||
def __init__(self):
|
||||
logging.Handler.__init__(self)
|
||||
|
||||
def emit(self, record):
|
||||
lvl = record.levelno
|
||||
msg = self.format(record)
|
||||
if(len(msg)):
|
||||
TermHandler.STREAM.write(msg + TermHandler.NL)
|
||||
if(TermHandler.DO_FLUSH):
|
||||
TermHandler.STREAM.flush()
|
||||
|
||||
|
||||
def setupLogging():
|
||||
logger = logging.getLogger()
|
||||
handler = TermHandler()
|
||||
formatter = TermFormatter(LOG_FORMAT)
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
logger.setLevel(LOG_LEVEL)
|
||||
|
||||
|
||||
def getLogger(name):
|
||||
logger = logging.getLogger(name)
|
||||
return logger
|
||||
|
||||
|
||||
#this should happen first (and once)
|
||||
INIT_LOGGING = False
|
||||
if(not INIT_LOGGING):
|
||||
setupLogging()
|
||||
INIT_LOGGING = True
|
35
devstack/Nova.py
Normal file
35
devstack/Nova.py
Normal file
@ -0,0 +1,35 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import Logger
|
||||
import Component
|
||||
|
||||
LOG = Logger.getLogger("install.nova")
|
||||
|
||||
|
||||
class NovaUninstaller(Component.UninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
||||
|
||||
|
||||
class NovaInstaller(Component.InstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
||||
|
||||
|
||||
class NovaRuntime(Component.RuntimeComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
51
devstack/Options.py
Normal file
51
devstack/Options.py
Normal file
@ -0,0 +1,51 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from optparse import OptionParser
|
||||
|
||||
import Util
|
||||
|
||||
KNOWN_COMPONENTS = set(Util.NAMES)
|
||||
KNOWN_ACTIONS = set(Util.ACTIONS)
|
||||
|
||||
|
||||
def parse():
|
||||
parser = OptionParser()
|
||||
actions = "(" + ", ".join(KNOWN_ACTIONS) + ")"
|
||||
parser.add_option("-a", "--action",
|
||||
action="store",
|
||||
type="string",
|
||||
dest="action",
|
||||
metavar="ACTION",
|
||||
help="action to perform, ie %s" % (actions))
|
||||
|
||||
parser.add_option("-d", "--directory",
|
||||
action="store",
|
||||
type="string",
|
||||
dest="dir",
|
||||
metavar="DIR",
|
||||
help="root DIR for new components or DIR with existing components (ACTION dependent)")
|
||||
|
||||
components = "(" + ", ".join(KNOWN_COMPONENTS) + ")"
|
||||
parser.add_option("-c", "--component",
|
||||
action="append",
|
||||
dest="component",
|
||||
help="stack component, ie %s" % (components))
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
output = dict()
|
||||
if(options != None):
|
||||
output = vars(options)
|
||||
return output
|
36
devstack/Packager.py
Normal file
36
devstack/Packager.py
Normal file
@ -0,0 +1,36 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
"""
|
||||
An abstraction that different packaging
|
||||
frameworks (ie apt, yum) can inherit from
|
||||
"""
|
||||
|
||||
import Logger
|
||||
import Shell
|
||||
from Shell import execute
|
||||
|
||||
LOG = Logger.getLogger("install.packager")
|
||||
|
||||
class Packager():
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def install_batch(self, pkgs):
|
||||
raise NotImplementedError()
|
||||
|
||||
def remove_batch(self, pkgs):
|
||||
raise NotImplementedError()
|
45
devstack/Quantum.py
Normal file
45
devstack/Quantum.py
Normal file
@ -0,0 +1,45 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import Logger
|
||||
import Component
|
||||
|
||||
LOG = Logger.getLogger("install.quantum")
|
||||
|
||||
|
||||
class QuantumTraceWriter():
|
||||
def __init__(self, root):
|
||||
pass
|
||||
|
||||
|
||||
class QuantumTraceReader():
|
||||
def __init__(self, root):
|
||||
pass
|
||||
|
||||
|
||||
class QuantumUninstaller(Component.UninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
||||
|
||||
|
||||
class QuantumInstaller(Component.InstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
||||
|
||||
|
||||
class QuantumRuntime(Component.RuntimeComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
120
devstack/Rabbit.py
Normal file
120
devstack/Rabbit.py
Normal file
@ -0,0 +1,120 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import Logger
|
||||
import Component
|
||||
from Component import (ComponentBase, RuntimeComponent,
|
||||
UninstallComponent, InstallComponent)
|
||||
import Util
|
||||
from Util import (RABBIT,
|
||||
get_pkg_list)
|
||||
import Trace
|
||||
from Trace import (TraceWriter, TraceReader)
|
||||
import Shell
|
||||
from Shell import (mkdirslist, execute, deldir)
|
||||
|
||||
LOG = Logger.getLogger("install.rabbit")
|
||||
TYPE = RABBIT
|
||||
START_CMD = ["/etc/init.d/rabbitmq-server", "start"]
|
||||
STOP_CMD = ["/etc/init.d/rabbitmq-server", "stop"]
|
||||
PWD_CMD = ['rabbitmqctl', 'change_password', 'guest']
|
||||
|
||||
|
||||
class RabbitUninstaller(ComponentBase, UninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
ComponentBase.__init__(self, TYPE, *args, **kargs)
|
||||
self.tracereader = TraceReader(self.tracedir, Trace.IN_TRACE)
|
||||
|
||||
def unconfigure(self):
|
||||
#nothing to unconfigure, we are just a pkg
|
||||
pass
|
||||
|
||||
def uninstall(self):
|
||||
#clean out removeable packages
|
||||
pkgsfull = self.tracereader.packages_installed()
|
||||
if(len(pkgsfull)):
|
||||
am = len(pkgsfull)
|
||||
LOG.info("Removing %s packages" % (am))
|
||||
self.packager.remove_batch(pkgsfull)
|
||||
dirsmade = self.tracereader.dirs_made()
|
||||
if(len(dirsmade)):
|
||||
am = len(dirsmade)
|
||||
LOG.info("Removing %s created directories" % (am))
|
||||
for dirname in dirsmade:
|
||||
deldir(dirname)
|
||||
LOG.info("Removed %s" % (dirname))
|
||||
|
||||
|
||||
class RabbitInstaller(ComponentBase, InstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
ComponentBase.__init__(self, TYPE, *args, **kargs)
|
||||
self.tracewriter = TraceWriter(self.tracedir, Trace.IN_TRACE)
|
||||
|
||||
def download(self):
|
||||
#nothing to download, we are just a pkg
|
||||
pass
|
||||
|
||||
def configure(self):
|
||||
#nothing to configure, we are just a pkg
|
||||
pass
|
||||
|
||||
def _setup_pw(self):
|
||||
passwd = self.cfg.getpw("passwords", "rabbit")
|
||||
cmd = PWD_CMD + [passwd]
|
||||
execute(*cmd, run_as_root=True)
|
||||
|
||||
def install(self):
|
||||
#just install the pkg
|
||||
pkgs = get_pkg_list(self.os, TYPE)
|
||||
pkgnames = pkgs.keys()
|
||||
pkgnames.sort()
|
||||
LOG.debug("Installing packages %s" % (", ".join(pkgnames)))
|
||||
self.packager.install_batch(pkgs)
|
||||
for name in pkgnames:
|
||||
packageinfo = pkgs.get(name)
|
||||
version = packageinfo.get("version", "")
|
||||
remove = packageinfo.get("removable", True)
|
||||
# This trace is used to remove the pkgs
|
||||
self.tracewriter.package_install(name, remove, version)
|
||||
dirsmade = mkdirslist(self.tracedir)
|
||||
# This trace is used to remove the dirs created
|
||||
self.tracewriter.dir_made(*dirsmade)
|
||||
self._setup_pw()
|
||||
# TODO - stop it (since it usually autostarts)
|
||||
# so that we control the start/stop, not it
|
||||
return self.tracedir
|
||||
|
||||
|
||||
class RabbitRuntime(ComponentBase, RuntimeComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
ComponentBase.__init__(self, TYPE, *args, **kargs)
|
||||
self.tracereader = TraceReader(self.tracedir, Trace.IN_TRACE)
|
||||
|
||||
def start(self):
|
||||
pkgsinstalled = self.tracereader.packages_installed()
|
||||
if(len(pkgsinstalled) == 0):
|
||||
msg = "Can not start %s since it was not installed" % (TYPE)
|
||||
raise StartException(msg)
|
||||
execute(*START_CMD, run_as_root=True)
|
||||
return None
|
||||
|
||||
def stop(self):
|
||||
pkgsinstalled = self.tracereader.packages_installed()
|
||||
if(len(pkgsinstalled) == 0):
|
||||
msg = "Can not stop %s since it was not installed" % (TYPE)
|
||||
raise StopException(msg)
|
||||
execute(*STOP_CMD, run_as_root=True)
|
||||
return None
|
34
devstack/Runner.py
Normal file
34
devstack/Runner.py
Normal file
@ -0,0 +1,34 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
"""
|
||||
An abstraction that allows different methods
|
||||
of starting and stopping python applications
|
||||
"""
|
||||
|
||||
#trace actions shared
|
||||
RUN_TYPE = "RUN"
|
||||
|
||||
|
||||
class Runner():
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def start(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def stop(self, pkgs):
|
||||
raise NotImplementedError()
|
196
devstack/Shell.py
Normal file
196
devstack/Shell.py
Normal file
@ -0,0 +1,196 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import subprocess
|
||||
import shlex
|
||||
import getpass
|
||||
import sys
|
||||
import os.path
|
||||
import os
|
||||
import shutil
|
||||
import json
|
||||
|
||||
import Exceptions
|
||||
from Exceptions import ProcessExecutionError, FileException
|
||||
import Logger
|
||||
|
||||
ROOT_HELPER = ["sudo"]
|
||||
MKPW_CMD = ["openssl", 'rand', '-hex']
|
||||
|
||||
LOG = Logger.getLogger("install.shell")
|
||||
|
||||
|
||||
def execute(*cmd, **kwargs):
|
||||
process_input = kwargs.pop('process_input', None)
|
||||
check_exit_code = kwargs.pop('check_exit_code', [0])
|
||||
cwd = kwargs.pop('cwd', None)
|
||||
ignore_exit_code = False
|
||||
if isinstance(check_exit_code, bool):
|
||||
ignore_exit_code = not check_exit_code
|
||||
check_exit_code = [0]
|
||||
elif isinstance(check_exit_code, int):
|
||||
check_exit_code = [check_exit_code]
|
||||
|
||||
run_as_root = kwargs.pop('run_as_root', False)
|
||||
shell = kwargs.pop('shell', False)
|
||||
|
||||
if run_as_root:
|
||||
cmd = ROOT_HELPER + list(cmd)
|
||||
|
||||
cmd = map(str, cmd)
|
||||
|
||||
LOG.debug(('Running cmd: %s') % (' '.join(cmd)))
|
||||
if(process_input != None):
|
||||
LOG.debug(('With stdin: %s') % (process_input))
|
||||
|
||||
|
||||
_PIPE = subprocess.PIPE # pylint: disable=E1101
|
||||
obj = subprocess.Popen(cmd,
|
||||
stdin=_PIPE,
|
||||
stdout=_PIPE,
|
||||
stderr=_PIPE,
|
||||
close_fds=True,
|
||||
cwd=cwd,
|
||||
shell=shell)
|
||||
|
||||
result = None
|
||||
if process_input is not None:
|
||||
result = obj.communicate(process_input)
|
||||
else:
|
||||
result = obj.communicate()
|
||||
|
||||
obj.stdin.close() # pylint: disable=E1101
|
||||
_returncode = obj.returncode # pylint: disable=E1101
|
||||
LOG.debug(('Cmd result had return code %s') % _returncode)
|
||||
if not ignore_exit_code \
|
||||
and _returncode not in check_exit_code:
|
||||
(stdout, stderr) = result
|
||||
raise ProcessExecutionError(
|
||||
exit_code=_returncode,
|
||||
stdout=stdout,
|
||||
stderr=stderr,
|
||||
cmd=' '.join(cmd))
|
||||
else:
|
||||
return result
|
||||
|
||||
|
||||
def isfile(fn):
|
||||
return os.path.isfile(fn)
|
||||
|
||||
|
||||
def joinpths(*pths):
|
||||
return os.path.join(*pths)
|
||||
|
||||
|
||||
def password(prompt=None, genlen=8):
|
||||
if(prompt):
|
||||
rd = getpass.getpass(prompt)
|
||||
else:
|
||||
rd = getpass.getpass()
|
||||
if(len(rd) == 0):
|
||||
LOG.debug("Generating you a password of length %s" % (genlen))
|
||||
cmd = MKPW_CMD + [genlen]
|
||||
(stdout, stderr) = execute(*cmd)
|
||||
return stdout.strip()
|
||||
else:
|
||||
return rd
|
||||
|
||||
|
||||
def mkdirslist(pth):
|
||||
dirsmade = list()
|
||||
if(os.path.isdir(pth)):
|
||||
#already there...
|
||||
return dirsmade
|
||||
dirspossible = set()
|
||||
dirspossible.add(pth)
|
||||
while(True):
|
||||
splitup = os.path.split(pth)
|
||||
pth = splitup[0]
|
||||
base = splitup[1]
|
||||
dirspossible.add(pth)
|
||||
if(len(base) == 0):
|
||||
break
|
||||
dirstobe = list(dirspossible)
|
||||
dirstobe.sort()
|
||||
for pth in dirstobe:
|
||||
if(not os.path.isdir(pth)):
|
||||
os.mkdir(pth)
|
||||
dirsmade.append(pth)
|
||||
return dirsmade
|
||||
|
||||
|
||||
def load_json(fn):
|
||||
data = load_file(fn)
|
||||
return json.loads(data)
|
||||
|
||||
|
||||
def append_file(fn, text, flush=True):
|
||||
with open(fn, "a") as f:
|
||||
f.write(text)
|
||||
if(flush):
|
||||
f.flush()
|
||||
|
||||
|
||||
def write_file(fn, text, flush=True):
|
||||
with open(fn, "w") as f:
|
||||
f.write(text)
|
||||
if(flush):
|
||||
f.flush()
|
||||
|
||||
|
||||
def touch_file(fn, diethere=True):
|
||||
if(not os.path.exists(fn)):
|
||||
with open(fn, "w") as f:
|
||||
f.truncate(0)
|
||||
else:
|
||||
if(diethere):
|
||||
msg = "Can not touch file %s since it already exists" % (fn)
|
||||
raise FileException(msg)
|
||||
|
||||
|
||||
def load_file(fn):
|
||||
data = ""
|
||||
with open(fn, "r") as f:
|
||||
data = f.read()
|
||||
return data
|
||||
|
||||
|
||||
def mkdir(pth, recurse=True):
|
||||
if(not os.path.isdir(pth)):
|
||||
if(recurse):
|
||||
os.makedirs(pth)
|
||||
else:
|
||||
os.mkdir(pth)
|
||||
|
||||
|
||||
def deldir(pth, force=True):
|
||||
if(os.path.isdir(pth)):
|
||||
if(force):
|
||||
shutil.rmtree(pth)
|
||||
else:
|
||||
os.removedirs(pth)
|
||||
|
||||
|
||||
def prompt(prompt):
|
||||
rd = raw_input(prompt)
|
||||
return rd
|
||||
|
||||
|
||||
def unlink(pth, ignore=True):
|
||||
try:
|
||||
os.unlink(pth)
|
||||
except OSError as (errono, emsg):
|
||||
if(not ignore):
|
||||
raise
|
35
devstack/Swift.py
Normal file
35
devstack/Swift.py
Normal file
@ -0,0 +1,35 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import Logger
|
||||
import Component
|
||||
|
||||
LOG = Logger.getLogger("install.swift")
|
||||
|
||||
|
||||
class SwiftUninstaller(Component.UninstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
||||
|
||||
|
||||
class SwiftInstaller(Component.InstallComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
||||
|
||||
|
||||
class SwiftRuntime(Component.RuntimeComponent):
|
||||
def __init__(self, *args, **kargs):
|
||||
pass
|
272
devstack/Trace.py
Normal file
272
devstack/Trace.py
Normal file
@ -0,0 +1,272 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os.path
|
||||
import json
|
||||
|
||||
import Util
|
||||
from Util import (rcf8222date)
|
||||
|
||||
import Shell
|
||||
from Shell import (touch_file, append_file, joinpths, load_file, mkdirslist)
|
||||
|
||||
TRACE_FMT = "%s - %s\n"
|
||||
TRACE_EXT = ".trace"
|
||||
|
||||
#common trace actions
|
||||
CFG_WRITING_FILE = "CFG_WRITING_FILE"
|
||||
PKG_INSTALL = "PKG_INSTALL"
|
||||
PYTHON_INSTALL = "PYTHON_INSTALL"
|
||||
DIR_MADE = "DIR_MADE"
|
||||
FILE_TOUCHED = "FILE_TOUCHED"
|
||||
DOWNLOADED = "DOWNLOADED"
|
||||
AP_STARTED = "AP_STARTED"
|
||||
|
||||
#trace file types
|
||||
PY_TRACE = "python"
|
||||
IN_TRACE = "install"
|
||||
START_TRACE = "start"
|
||||
|
||||
#used to note version of trace
|
||||
TRACE_VERSION = "TRACE_VERSION"
|
||||
TRACE_VER = 0x1
|
||||
|
||||
|
||||
class Trace():
|
||||
def __init__(self, tracefn):
|
||||
self.tracefn = tracefn
|
||||
|
||||
def fn(self):
|
||||
return self.tracefn
|
||||
|
||||
def trace(self, cmd, action=None):
|
||||
if(action == None):
|
||||
action = rcf8222date()
|
||||
line = TRACE_FMT % (cmd, action)
|
||||
append_file(self.tracefn, line)
|
||||
|
||||
|
||||
class TraceWriter():
|
||||
def __init__(self, root, name):
|
||||
self.tracer = None
|
||||
self.root = root
|
||||
self.name = name
|
||||
self.started = False
|
||||
|
||||
def _start(self):
|
||||
if(self.started):
|
||||
return
|
||||
else:
|
||||
dirs = mkdirslist(self.root)
|
||||
fn = touch_trace(self.root, self.name)
|
||||
self.tracer = Trace(fn)
|
||||
cmd = TRACE_VERSION
|
||||
action = str(TRACE_VER)
|
||||
self.tracer.trace(cmd, action)
|
||||
cmd = DIR_MADE
|
||||
for d in dirs:
|
||||
action = d
|
||||
self.tracer.trace(cmd, action)
|
||||
self.started = True
|
||||
|
||||
def py_install(self, where):
|
||||
self._start()
|
||||
cmd = PYTHON_INSTALL
|
||||
action = where
|
||||
self.tracer.trace(cmd, action)
|
||||
|
||||
def cfg_write(self, cfgfile):
|
||||
self._start()
|
||||
cmd = CFG_WRITING_FILE
|
||||
action = cfgfile
|
||||
self.tracer.trace(cmd, action)
|
||||
|
||||
def downloaded(self, tgt, fromwhere):
|
||||
self._start()
|
||||
cmd = DOWNLOADED
|
||||
action = dict()
|
||||
action['target'] = tgt
|
||||
action['from'] = fromwhere
|
||||
store = json.dumps(action)
|
||||
self.tracer.trace(cmd, store)
|
||||
|
||||
def dir_made(self, *dirs):
|
||||
self._start()
|
||||
cmd = DIR_MADE
|
||||
for d in dirs:
|
||||
action = d
|
||||
self.tracer.trace(cmd, action)
|
||||
|
||||
def file_touched(self, fn):
|
||||
self._start()
|
||||
cmd = FILE_TOUCHED
|
||||
action = fn
|
||||
self.tracer.trace(cmd, action)
|
||||
|
||||
def package_install(self, name, removeable, version):
|
||||
self._start()
|
||||
pkgmeta = dict()
|
||||
pkgmeta['name'] = name
|
||||
pkgmeta['removable'] = removeable
|
||||
pkgmeta['version'] = version
|
||||
tracedata = json.dumps(pkgmeta)
|
||||
cmd = PKG_INSTALL
|
||||
action = tracedata
|
||||
self.tracer.trace(cmd, action)
|
||||
|
||||
def started_info(self, name, info_fn):
|
||||
self._start()
|
||||
cmd = AP_STARTED
|
||||
out = dict()
|
||||
out['name'] = name
|
||||
out['trace_fn'] = info_fn
|
||||
action = json.dumps(out)
|
||||
self.tracer.trace(cmd, action)
|
||||
|
||||
|
||||
class TraceReader():
|
||||
def __init__(self, root, name):
|
||||
self.root = root
|
||||
self.name = name
|
||||
self.trace_fn = trace_fn(root, name)
|
||||
|
||||
def _readpy(self):
|
||||
lines = self._read()
|
||||
pyfn = None
|
||||
pylines = list()
|
||||
for (cmd, action) in lines:
|
||||
if(cmd == PYTHON_INSTALL and len(action)):
|
||||
pyfn = action
|
||||
break
|
||||
if(pyfn != None):
|
||||
lines = load_file(pyfn).splitlines()
|
||||
pylines = lines
|
||||
return pylines
|
||||
|
||||
def _read(self):
|
||||
return parse_name(self.root, self.name)
|
||||
|
||||
def py_listing(self):
|
||||
return self._readpy()
|
||||
|
||||
def files_touched(self):
|
||||
lines = self._read()
|
||||
files = list()
|
||||
for (cmd, action) in lines:
|
||||
if(cmd == FILE_TOUCHED and len(action)):
|
||||
files.append(action)
|
||||
#ensure no dups
|
||||
files = list(set(files))
|
||||
files.sort()
|
||||
return files
|
||||
|
||||
def dirs_made(self):
|
||||
lines = self._read()
|
||||
dirs = list()
|
||||
for (cmd, action) in lines:
|
||||
if(cmd == DIR_MADE and len(action)):
|
||||
dirs.append(action)
|
||||
#ensure not dups
|
||||
dirs = list(set(dirs))
|
||||
#ensure in ok order (ie /tmp is before /)
|
||||
dirs.sort()
|
||||
dirs.reverse()
|
||||
return dirs
|
||||
|
||||
def apps_started(self):
|
||||
lines = self._read()
|
||||
files = list()
|
||||
for (cmd, action) in lines:
|
||||
if(cmd == AP_STARTED and len(action)):
|
||||
jdec = json.loads(action)
|
||||
if(type(jdec) is dict):
|
||||
files.append(jdec)
|
||||
return files
|
||||
|
||||
def files_configured(self):
|
||||
lines = self._read()
|
||||
files = list()
|
||||
for (cmd, action) in lines:
|
||||
if(cmd == CFG_WRITING_FILE and len(action)):
|
||||
files.append(action)
|
||||
#ensure not dups
|
||||
files = list(set(files))
|
||||
files.sort()
|
||||
return files
|
||||
|
||||
def packages_installed(self):
|
||||
lines = self._read()
|
||||
pkgsinstalled = dict()
|
||||
actions = list()
|
||||
for (cmd, action) in lines:
|
||||
if(cmd == PKG_INSTALL and len(action)):
|
||||
actions.append(action)
|
||||
for action in actions:
|
||||
pv = json.loads(action)
|
||||
if(type(pv) is dict):
|
||||
name = pv.get("name", "")
|
||||
remove = pv.get("removable", True)
|
||||
version = pv.get("version", "")
|
||||
if(remove and len(name)):
|
||||
if(len(version)):
|
||||
pkgsinstalled[name] = {"version": version}
|
||||
else:
|
||||
pkgsinstalled[name] = {}
|
||||
return pkgsinstalled
|
||||
|
||||
|
||||
def trace_fn(rootdir, name):
|
||||
fullname = name + TRACE_EXT
|
||||
tracefn = joinpths(rootdir, fullname)
|
||||
return tracefn
|
||||
|
||||
|
||||
def touch_trace(rootdir, name):
|
||||
tracefn = trace_fn(rootdir, name)
|
||||
touch_file(tracefn)
|
||||
return tracefn
|
||||
|
||||
|
||||
def split_line(line):
|
||||
pieces = line.split("-", 1)
|
||||
if(len(pieces) == 2):
|
||||
cmd = pieces[0].rstrip()
|
||||
action = pieces[1].lstrip()
|
||||
return (cmd, action)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def read(rootdir, name):
|
||||
pth = trace_fn(rootdir, name)
|
||||
contents = load_file(pth)
|
||||
lines = contents.splitlines()
|
||||
return lines
|
||||
|
||||
|
||||
def parse_fn(fn):
|
||||
contents = load_file(fn)
|
||||
lines = contents.splitlines()
|
||||
accum = list()
|
||||
for line in lines:
|
||||
ep = split_line(line)
|
||||
if(ep == None):
|
||||
continue
|
||||
accum.append(tuple(ep))
|
||||
return accum
|
||||
|
||||
|
||||
def parse_name(rootdir, name):
|
||||
return parse_fn(trace_fn(rootdir, name))
|
294
devstack/Util.py
Normal file
294
devstack/Util.py
Normal file
@ -0,0 +1,294 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import Exceptions
|
||||
from Exceptions import (BadRegexException,
|
||||
NoReplacementException,
|
||||
FileException)
|
||||
import Logger
|
||||
import Shell
|
||||
from Shell import (joinpths, load_json)
|
||||
|
||||
from time import (localtime, strftime)
|
||||
from termcolor import colored
|
||||
|
||||
import subprocess
|
||||
import platform
|
||||
import re
|
||||
import os
|
||||
|
||||
#constant goodies
|
||||
VERSION = 0x2
|
||||
|
||||
#these also have meaning outside python
|
||||
#ie in the pkg listings so update there also!
|
||||
UBUNTU12 = "ubuntu-oneiric"
|
||||
RHEL6 = "rhel-6"
|
||||
|
||||
#GIT master
|
||||
MASTER_BRANCH = "master"
|
||||
|
||||
#other constants
|
||||
DB_DSN = '%s://%s:%s@%s/%s'
|
||||
|
||||
#component name mappings
|
||||
NOVA = "nova"
|
||||
GLANCE = "glance"
|
||||
QUANTUM = "quantum"
|
||||
SWIFT = "swift"
|
||||
HORIZON = "horizon"
|
||||
KEYSTONE = "keystone"
|
||||
DB = "db"
|
||||
RABBIT = "rabbit"
|
||||
|
||||
NAMES = [NOVA, GLANCE, QUANTUM,
|
||||
SWIFT, HORIZON, KEYSTONE,
|
||||
DB, RABBIT]
|
||||
|
||||
#ordering of install (lower priority means earlier)
|
||||
NAMES_PRIORITY = {
|
||||
DB: 1,
|
||||
RABBIT: 1,
|
||||
KEYSTONE: 2,
|
||||
GLANCE: 3,
|
||||
QUANTUM: 4,
|
||||
NOVA: 5,
|
||||
SWIFT: 6,
|
||||
HORIZON: 7,
|
||||
}
|
||||
|
||||
#when a component is asked for it may
|
||||
#need another component, that dependency
|
||||
#map is listed here...
|
||||
COMPONENT_DEPENDENCIES = {
|
||||
DB: [],
|
||||
RABBIT: [],
|
||||
GLANCE: [KEYSTONE, DB],
|
||||
KEYSTONE: [DB],
|
||||
NOVA: [KEYSTONE, GLANCE, DB, RABBIT],
|
||||
SWIFT: [],
|
||||
HORIZON: [],
|
||||
QUANTUM: [],
|
||||
}
|
||||
|
||||
#program
|
||||
#actions
|
||||
INSTALL = "install"
|
||||
UNINSTALL = "uninstall"
|
||||
START = "start"
|
||||
STOP = "stop"
|
||||
|
||||
ACTIONS = [INSTALL, UNINSTALL, START, STOP]
|
||||
|
||||
#this is used to map an action to a useful string for
|
||||
#the welcome display...
|
||||
WELCOME_MAP = {
|
||||
INSTALL: "Installer",
|
||||
UNINSTALL: "Uninstaller",
|
||||
START: "Runner",
|
||||
STOP: "Stopper",
|
||||
}
|
||||
|
||||
#where we should get the config file...
|
||||
STACK_CONFIG_DIR = "conf"
|
||||
CFG_LOC = joinpths(STACK_CONFIG_DIR, "stack.ini")
|
||||
|
||||
#this regex is how we match python platform output to
|
||||
#a known constant
|
||||
KNOWN_OS = {
|
||||
UBUNTU12: '/Ubuntu(.*)oneiric/i',
|
||||
RHEL6: '/redhat-6\.(\d+)/i',
|
||||
}
|
||||
|
||||
#the pkg files that each component
|
||||
#needs
|
||||
PKG_MAP = {
|
||||
NOVA:
|
||||
[
|
||||
joinpths(STACK_CONFIG_DIR, "pkgs", "nova.pkg"),
|
||||
joinpths(STACK_CONFIG_DIR, "pkgs", "general.pkg"),
|
||||
],
|
||||
GLANCE:
|
||||
[
|
||||
joinpths(STACK_CONFIG_DIR, "pkgs", "general.pkg"),
|
||||
joinpths(STACK_CONFIG_DIR, "pkgs", 'glance.pkg'),
|
||||
],
|
||||
KEYSTONE:
|
||||
[
|
||||
joinpths(STACK_CONFIG_DIR, "pkgs", "general.pkg"),
|
||||
joinpths(STACK_CONFIG_DIR, "pkgs", 'keystone.pkg'),
|
||||
],
|
||||
HORIZON:
|
||||
[
|
||||
joinpths(STACK_CONFIG_DIR, "pkgs", "general.pkg"),
|
||||
joinpths(STACK_CONFIG_DIR, "pkgs", 'horizon.pkg'),
|
||||
],
|
||||
SWIFT:
|
||||
[
|
||||
joinpths(STACK_CONFIG_DIR, "pkgs", "general.pkg"),
|
||||
joinpths(STACK_CONFIG_DIR, "pkgs", 'swift.pkg'),
|
||||
],
|
||||
DB:
|
||||
[
|
||||
joinpths(STACK_CONFIG_DIR, "pkgs", 'db.pkg'),
|
||||
],
|
||||
RABBIT:
|
||||
[
|
||||
joinpths(STACK_CONFIG_DIR, "pkgs", 'rabbitmq.pkg'),
|
||||
],
|
||||
}
|
||||
|
||||
#subdirs of a components dir
|
||||
TRACE_DIR = "traces"
|
||||
APP_DIR = "app"
|
||||
CONFIG_DIR = "config"
|
||||
|
||||
#our ability to create regexes
|
||||
#which is more like php, which is nicer
|
||||
#for modifiers...
|
||||
REGEX_MATCHER = re.compile("^/(.*?)/([a-z]*)$")
|
||||
|
||||
LOG = Logger.getLogger("install.util")
|
||||
|
||||
|
||||
def fetch_deps(component, add=False):
|
||||
if(add):
|
||||
deps = list([component])
|
||||
else:
|
||||
deps = list()
|
||||
cdeps = COMPONENT_DEPENDENCIES.get(component)
|
||||
if(cdeps and len(cdeps)):
|
||||
for d in cdeps:
|
||||
deps = deps + fetch_deps(d, True)
|
||||
return deps
|
||||
|
||||
|
||||
def component_pths(root, compnent_type):
|
||||
component_root = joinpths(root, compnent_type)
|
||||
tracedir = joinpths(component_root, TRACE_DIR)
|
||||
appdir = joinpths(component_root, APP_DIR)
|
||||
cfgdir = joinpths(component_root, CONFIG_DIR)
|
||||
out = dict()
|
||||
out['root_dir'] = component_root
|
||||
out['trace_dir'] = tracedir
|
||||
out['app_dir'] = appdir
|
||||
out['config_dir'] = cfgdir
|
||||
return out
|
||||
|
||||
|
||||
def get_interfaces():
|
||||
import netifaces
|
||||
interfaces = dict()
|
||||
for intfc in netifaces.interfaces():
|
||||
interfaces[intfc] = netifaces.ifaddresses(intfc)
|
||||
return interfaces
|
||||
|
||||
|
||||
def create_regex(format):
|
||||
mtch = REGEX_MATCHER.match(format)
|
||||
if(not mtch):
|
||||
raise BadRegexException("Badly formatted pre-regex: " + format)
|
||||
else:
|
||||
toberegex = mtch.group(1)
|
||||
options = mtch.group(2).lower()
|
||||
flags = 0
|
||||
if(options.find("i") != -1):
|
||||
flags = flags | re.IGNORECASE
|
||||
if(options.find("m") != -1):
|
||||
flags = flags | re.MULTILINE
|
||||
if(options.find("u") != -1):
|
||||
flags = flags | re.UNICODE
|
||||
return re.compile(toberegex, flags)
|
||||
|
||||
|
||||
def get_dbdsn(cfg, dbname):
|
||||
user = cfg.get("db", "sql_user")
|
||||
host = cfg.get("db", "sql_host")
|
||||
dbtype = cfg.get("db", "type")
|
||||
pw = cfg.getpw("passwords", "sql")
|
||||
return DB_DSN % (dbtype, user, pw, host, dbname)
|
||||
|
||||
|
||||
def determine_os():
|
||||
os = None
|
||||
plt = platform.platform()
|
||||
for aos, pat in KNOWN_OS.items():
|
||||
reg = create_regex(pat)
|
||||
if(reg.search(plt)):
|
||||
os = aos
|
||||
break
|
||||
return (os, plt)
|
||||
|
||||
|
||||
def get_pkg_list(distro, component):
|
||||
LOG.info("Getting packages for distro %s and component %s." % (distro, component))
|
||||
all_pkgs = dict()
|
||||
fns = PKG_MAP.get(component)
|
||||
if(fns == None):
|
||||
#guess none needed
|
||||
return all_pkgs
|
||||
#load + merge them
|
||||
for fn in fns:
|
||||
js = load_json(fn)
|
||||
if(type(js) is dict):
|
||||
distromp = js.get(distro)
|
||||
if(distromp != None and type(distromp) is dict):
|
||||
all_pkgs = dict(all_pkgs.items() + distromp.items())
|
||||
return all_pkgs
|
||||
|
||||
|
||||
def joinlinesep(*pieces):
|
||||
return os.linesep.join(*pieces)
|
||||
|
||||
def param_replace(text, replacements):
|
||||
if(len(replacements) == 0 or len(text) == 0):
|
||||
return text
|
||||
|
||||
def replacer(m):
|
||||
org = m.group()
|
||||
name = m.group(1)
|
||||
v = replacements.get(name)
|
||||
if(v == None):
|
||||
msg = "No replacement found for parameter %s" % (org)
|
||||
raise NoReplacementException(msg)
|
||||
return str(v)
|
||||
|
||||
ntext = re.sub("%([\\w\\d]+?)%", replacer, text)
|
||||
return ntext
|
||||
|
||||
|
||||
def welcome(program_action):
|
||||
formatted_action = WELCOME_MAP.get(program_action)
|
||||
lower = "!%s v%s!" % (formatted_action.upper(), VERSION)
|
||||
welcome = r'''
|
||||
___ ____ _____ _ _ ____ _____ _ ____ _ __
|
||||
/ _ \| _ \| ____| \ | / ___|_ _|/ \ / ___| |/ /
|
||||
| | | | |_) | _| | \| \___ \ | | / _ \| | | ' /
|
||||
| |_| | __/| |___| |\ |___) || |/ ___ \ |___| . \
|
||||
\___/|_| |_____|_| \_|____/ |_/_/ \_\____|_|\_\
|
||||
|
||||
'''
|
||||
welcome = " " + welcome.strip()
|
||||
lowerc = " " * 21 + colored(lower, 'blue')
|
||||
msg = welcome + "\n" + lowerc
|
||||
print(msg)
|
||||
|
||||
|
||||
def rcf8222date():
|
||||
return strftime("%a, %d %b %Y %H:%M:%S", localtime())
|
||||
|
||||
|
||||
def fsSafeDate():
|
||||
return strftime("%m_%d_%G-%H-%M-%S", localtime())
|
14
devstack/__init__.py
Normal file
14
devstack/__init__.py
Normal file
@ -0,0 +1,14 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
60
devstack/packaging/Apt.py
Normal file
60
devstack/packaging/Apt.py
Normal file
@ -0,0 +1,60 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import os
|
||||
|
||||
import Packager
|
||||
import Util
|
||||
from Util import param_replace
|
||||
import Shell
|
||||
from Shell import execute
|
||||
|
||||
APT_GET = ['apt-get']
|
||||
APT_REMOVE = ["purge", "-y"] # should we use remove or purge?
|
||||
APT_INSTALL = ["install", "-y"]
|
||||
|
||||
#make sure its non-interactive
|
||||
os.putenv('DEBIAN_FRONTEND', 'noninteractive')
|
||||
|
||||
|
||||
class AptPackager(Packager.Packager):
|
||||
def __init__(self):
|
||||
Packager.Packager.__init__(self)
|
||||
|
||||
def _form_cmd(self, name, version):
|
||||
cmd = name
|
||||
if(version and len(version)):
|
||||
cmd = cmd + "=" + version
|
||||
return cmd
|
||||
|
||||
def _do_cmd(self, base_cmd, pkgs):
|
||||
pkgnames = pkgs.keys()
|
||||
pkgnames.sort()
|
||||
cmds = []
|
||||
for name in pkgnames:
|
||||
version = None
|
||||
info = pkgs.get(name)
|
||||
if(info):
|
||||
version = info.get("version")
|
||||
torun = self._form_cmd(name, version)
|
||||
cmds.append(torun)
|
||||
if(len(cmds)):
|
||||
cmd = APT_GET + base_cmd + cmds
|
||||
execute(*cmd, run_as_root=True)
|
||||
|
||||
def remove_batch(self, pkgs):
|
||||
self._do_cmd(APT_REMOVE, pkgs)
|
||||
|
||||
def install_batch(self, pkgs, params=None):
|
||||
self._do_cmd(APT_INSTALL, pkgs)
|
21
devstack/packaging/Yum.py
Normal file
21
devstack/packaging/Yum.py
Normal file
@ -0,0 +1,21 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import Packager
|
||||
|
||||
|
||||
class YumPackager(Packager.Packager):
|
||||
def __init__(self):
|
||||
Packager.Packager.__init__(self)
|
14
devstack/packaging/__init__.py
Normal file
14
devstack/packaging/__init__.py
Normal file
@ -0,0 +1,14 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
143
devstack/runners/Foreground.py
Normal file
143
devstack/runners/Foreground.py
Normal file
@ -0,0 +1,143 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import resource
|
||||
import signal
|
||||
import errno
|
||||
|
||||
import Runner
|
||||
import Util
|
||||
import Exceptions
|
||||
from Exceptions import (StartException, StopException)
|
||||
import Logger
|
||||
import Shell
|
||||
from Shell import (unlink, mkdir, joinpths, write_file,
|
||||
load_file, isfile)
|
||||
import Trace
|
||||
|
||||
# Maximum for the number of available file descriptors (when not found)
|
||||
MAXFD = 2048
|
||||
MAX_KILL_TRY = 4
|
||||
|
||||
LOG = Logger.getLogger("install.runners.foreground")
|
||||
|
||||
#trace constants
|
||||
RUN = Runner.RUN_TYPE
|
||||
RUN_TYPE = "FORK"
|
||||
PID_FN = "PID_FN"
|
||||
STDOUT_FN = "STDOUT_FN"
|
||||
STDERR_FN = "STDERR_FN"
|
||||
NAME = "NAME"
|
||||
|
||||
|
||||
class ForegroundRunner(Runner.Runner):
|
||||
def __init__(self):
|
||||
Runner.Runner.__init__(self)
|
||||
|
||||
def stop(self, name, *args, **kargs):
|
||||
rootdir = kargs.get("trace_dir")
|
||||
pidfile = joinpths(rootdir, name + ".pid")
|
||||
stderr = joinpths(rootdir, name + ".stderr")
|
||||
stdout = joinpths(rootdir, name + ".stdout")
|
||||
tfname = Trace.trace_fn(rootdir, name)
|
||||
if(isfile(pidfile) and isfile(tfname)):
|
||||
pid = int(load_file(pidfile).strip())
|
||||
killed = False
|
||||
lastmsg = ""
|
||||
attempts = 1
|
||||
for attempt in range(0, MAX_KILL_TRY):
|
||||
try:
|
||||
os.kill(pid, signal.SIGKILL)
|
||||
attempts += 1
|
||||
except OSError as (ec, msg):
|
||||
if(ec == errno.ESRCH):
|
||||
killed = True
|
||||
break
|
||||
lastmsg = msg
|
||||
#trash the files
|
||||
if(killed):
|
||||
LOG.info("Killed pid %s in %s attempts" % (str(pid), str(attempts)))
|
||||
LOG.info("Removing pid file %s" % (pidfile))
|
||||
unlink(pidfile)
|
||||
LOG.info("Removing stderr file %s" % (stderr))
|
||||
unlink(stderr)
|
||||
LOG.info("Removing stdout file %s" % (stdout))
|
||||
unlink(stdout)
|
||||
LOG.info("Removing %s trace file %s" % (name, tfname))
|
||||
unlink(tfname)
|
||||
else:
|
||||
msg = "Could not stop program named %s after %s attempts - [%s]" % (name, MAX_KILL_TRY, lastmsg)
|
||||
raise StopException(msg)
|
||||
else:
|
||||
msg = "No pid file could be found to terminate at %s" % (pidfile)
|
||||
raise StopException(msg)
|
||||
|
||||
def start(self, name, program, *args, **kargs):
|
||||
tracedir = kargs.get("trace_dir")
|
||||
appdir = kargs.get("app_dir")
|
||||
pidfile = joinpths(tracedir, name + ".pid")
|
||||
stderr = joinpths(tracedir, name + ".stderr")
|
||||
stdout = joinpths(tracedir, name + ".stdout")
|
||||
tracefn = Trace.trace_fn(tracedir, name)
|
||||
tracefn = Trace.touch_trace(tracedir, name)
|
||||
runtrace = Trace.Trace(tracefn)
|
||||
runtrace.trace(RUN, RUN_TYPE)
|
||||
runtrace.trace(PID_FN, pidfile)
|
||||
runtrace.trace(STDERR_FN, stderr)
|
||||
runtrace.trace(STDOUT_FN, stdout)
|
||||
#fork to get daemon out
|
||||
pid = os.fork()
|
||||
if(pid == 0):
|
||||
os.setsid()
|
||||
pid = os.fork()
|
||||
#fork to get daemon out - this time under init control
|
||||
#and now fully detached (no shell possible)
|
||||
if(pid == 0):
|
||||
#move to where application should be
|
||||
os.chdir(appdir)
|
||||
#close other fds
|
||||
limits = resource.getrlimit(resource.RLIMIT_NOFILE)
|
||||
mkfd = limits[1]
|
||||
if(mkfd == resource.RLIM_INFINITY):
|
||||
mkfd = MAXFD
|
||||
for fd in range(0, mkfd):
|
||||
try:
|
||||
os.close(fd)
|
||||
except OSError:
|
||||
#not open, thats ok
|
||||
pass
|
||||
#now adjust stderr and stdout
|
||||
stdoh = open(stdout, "w")
|
||||
stdeh = open(stderr, "w")
|
||||
os.dup2(stdoh.fileno(), sys.stdout.fileno())
|
||||
os.dup2(stdeh.fileno(), sys.stderr.fileno())
|
||||
#now exec...
|
||||
#the arguments to the child process should
|
||||
#start with the name of the command being run
|
||||
actualargs = [program] + list(args)
|
||||
os.execlp(program, *actualargs)
|
||||
else:
|
||||
#write out the child pid
|
||||
contents = str(pid) + "\n"
|
||||
write_file(pidfile, contents)
|
||||
#not exit or sys.exit, this is recommended
|
||||
#since it will do the right cleanups that we want
|
||||
#not calling any atexit functions, which would
|
||||
#be bad right now
|
||||
os._exit(0)
|
||||
else:
|
||||
return tracefn
|
21
devstack/runners/Screen.py
Normal file
21
devstack/runners/Screen.py
Normal file
@ -0,0 +1,21 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import Runner
|
||||
|
||||
|
||||
class Screen(Runner.Runner):
|
||||
def __init__(self):
|
||||
Runner.Runner.__init__(self)
|
14
devstack/runners/__init__.py
Normal file
14
devstack/runners/__init__.py
Normal file
@ -0,0 +1,14 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
263
stack
Executable file
263
stack
Executable file
@ -0,0 +1,263 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import operator
|
||||
|
||||
#TODO is this needed?
|
||||
sys.path.append("devstack")
|
||||
|
||||
import Logger
|
||||
import Options
|
||||
import Util
|
||||
from Util import (
|
||||
welcome,
|
||||
rcf8222date,
|
||||
fsSafeDate,
|
||||
determine_os,
|
||||
get_pkg_list
|
||||
)
|
||||
import Shell
|
||||
from Shell import (mkdir, joinpths)
|
||||
import Config
|
||||
import Glance
|
||||
import Horizon
|
||||
import Keystone
|
||||
import Nova
|
||||
import Quantum
|
||||
import Config
|
||||
import Swift
|
||||
import Db
|
||||
import Rabbit
|
||||
import Trace
|
||||
|
||||
LOG = Logger.getLogger("install")
|
||||
|
||||
# This determines what classes to use to install/uninstall/...
|
||||
ACTION_CLASSES = {
|
||||
Util.INSTALL: {
|
||||
Util.NOVA: Nova.NovaInstaller,
|
||||
Util.GLANCE: Glance.GlanceInstaller,
|
||||
Util.QUANTUM: Quantum.QuantumInstaller,
|
||||
Util.SWIFT: Swift.SwiftInstaller,
|
||||
Util.HORIZON: Horizon.HorizonInstaller,
|
||||
Util.KEYSTONE: Keystone.KeystoneInstaller,
|
||||
Util.DB: Db.DBInstaller,
|
||||
Util.RABBIT: Rabbit.RabbitInstaller,
|
||||
},
|
||||
Util.UNINSTALL: {
|
||||
Util.NOVA: Nova.NovaUninstaller,
|
||||
Util.GLANCE: Glance.GlanceUninstaller,
|
||||
Util.QUANTUM: Quantum.QuantumUninstaller,
|
||||
Util.SWIFT: Swift.SwiftUninstaller,
|
||||
Util.HORIZON: Horizon.HorizonUninstaller,
|
||||
Util.KEYSTONE: Keystone.KeystoneUninstaller,
|
||||
Util.DB: Db.DBUninstaller,
|
||||
Util.RABBIT: Rabbit.RabbitUninstaller,
|
||||
},
|
||||
Util.START: {
|
||||
Util.NOVA: Nova.NovaRuntime,
|
||||
Util.GLANCE: Glance.GlanceRuntime,
|
||||
Util.QUANTUM: Quantum.QuantumRuntime,
|
||||
Util.SWIFT: Swift.SwiftRuntime,
|
||||
Util.HORIZON: Horizon.HorizonRuntime,
|
||||
Util.KEYSTONE: Keystone.KeystoneRuntime,
|
||||
Util.DB: Db.DBRuntime,
|
||||
Util.RABBIT: Rabbit.RabbitRuntime,
|
||||
},
|
||||
Util.STOP: {
|
||||
Util.NOVA: Nova.NovaRuntime,
|
||||
Util.GLANCE: Glance.GlanceRuntime,
|
||||
Util.QUANTUM: Quantum.QuantumRuntime,
|
||||
Util.SWIFT: Swift.SwiftRuntime,
|
||||
Util.HORIZON: Horizon.HorizonRuntime,
|
||||
Util.KEYSTONE: Keystone.KeystoneRuntime,
|
||||
Util.DB: Db.DBRuntime,
|
||||
Util.RABBIT: Rabbit.RabbitRuntime,
|
||||
},
|
||||
}
|
||||
|
||||
# Actions which need dependent actions to occur
|
||||
DEP_ACTIONS_NEEDED = set([Util.START, Util.STOP, Util.INSTALL])
|
||||
|
||||
|
||||
def get_pkg_manager(distro):
|
||||
klass = None
|
||||
if(distro == Util.UBUNTU12):
|
||||
#late import required
|
||||
#TODO better way to do this?
|
||||
from packaging import Apt
|
||||
klass = Apt.AptPackager
|
||||
elif(distro == Util.RHEL6):
|
||||
#late import required
|
||||
#TODO better way to do this?
|
||||
from packaging import Yum
|
||||
klass = Yum.YumPackager
|
||||
return klass()
|
||||
|
||||
|
||||
def get_config():
|
||||
LOG.info("Loading config from %s" % (Util.CFG_LOC))
|
||||
cfg = Config.EnvConfigParser()
|
||||
cfg.read(Util.CFG_LOC)
|
||||
return cfg
|
||||
|
||||
|
||||
def stop(components, distro, rootdir):
|
||||
pkg_manager = get_pkg_manager(distro)
|
||||
cfg = get_config()
|
||||
LOG.info("Will stop [%s] from %s" % (", ".join(components), rootdir))
|
||||
klass_lookup = ACTION_CLASSES.get(Util.START)
|
||||
for c in components:
|
||||
klass = klass_lookup.get(c)
|
||||
instance = klass(components=components, distro=distro, pkg=pkg_manager, cfg=cfg, root=rootdir)
|
||||
LOG.info("Stopping %s." % (c))
|
||||
instance.stop()
|
||||
LOG.info("Finished stop of %s" % (c))
|
||||
return None
|
||||
|
||||
|
||||
def start(components, distro, rootdir):
|
||||
pkg_manager = get_pkg_manager(distro)
|
||||
cfg = get_config()
|
||||
LOG.info("Will start [%s] from %s" % (", ".join(components), rootdir))
|
||||
klass_lookup = ACTION_CLASSES.get(Util.START)
|
||||
locations = []
|
||||
for c in components:
|
||||
klass = klass_lookup.get(c)
|
||||
instance = klass(components=components, distro=distro, pkg=pkg_manager, cfg=cfg, root=rootdir)
|
||||
LOG.info("Starting %s." % (c))
|
||||
trace_locs = instance.start() or []
|
||||
LOG.info("Finished start of %s - check [%s] for traces of what happened." % (c, ", ".join(trace_locs)))
|
||||
locations = locations + trace_locs
|
||||
return locations
|
||||
|
||||
|
||||
def install(components, distro, rootdir):
|
||||
pkg_manager = get_pkg_manager(distro)
|
||||
cfg = get_config()
|
||||
mkdir(rootdir)
|
||||
LOG.info("Will install [%s] and store in %s." % (", ".join(components), rootdir))
|
||||
klass_lookup = ACTION_CLASSES.get(Util.INSTALL)
|
||||
traces = []
|
||||
for c in components:
|
||||
klass = klass_lookup.get(c)
|
||||
instance = klass(components=components, distro=distro, pkg=pkg_manager, cfg=cfg, root=rootdir)
|
||||
LOG.info("Downloading %s." % (c))
|
||||
instance.download()
|
||||
LOG.info("Configuring %s." % (c))
|
||||
instance.configure()
|
||||
LOG.info("Installing %s." % (c))
|
||||
trace = instance.install()
|
||||
LOG.info("Finished install of %s - check %s for traces of what happened." % (c, trace))
|
||||
traces.append(trace)
|
||||
return traces
|
||||
|
||||
|
||||
def uninstall(components, distro, uninstalldir):
|
||||
pkg_manager = get_pkg_manager(distro)
|
||||
cfg = get_config()
|
||||
LOG.info("Will uninstall [%s] with traces from directory %s." % (", ".join(components), uninstalldir))
|
||||
klass_lookup = ACTION_CLASSES.get(Util.UNINSTALL)
|
||||
for c in components:
|
||||
klass = klass_lookup.get(c)
|
||||
instance = klass(components=components, distro=distro, pkg=pkg_manager, cfg=cfg, root=uninstalldir)
|
||||
LOG.info("Unconfiguring %s." % (c))
|
||||
instance.unconfigure()
|
||||
LOG.info("Uninstalling %s." % (c))
|
||||
instance.uninstall()
|
||||
return None
|
||||
|
||||
|
||||
#what functions to activate for each action
|
||||
FUNC_MAP = {
|
||||
Util.INSTALL: install,
|
||||
Util.UNINSTALL: uninstall,
|
||||
Util.START: start,
|
||||
Util.STOP: stop
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
me = __file__
|
||||
args = Options.parse()
|
||||
components = args.get("component") or []
|
||||
if(len(components) == 0):
|
||||
#assume them all??
|
||||
components = list(Util.NAMES)
|
||||
components = set([x.lower() for x in components])
|
||||
applicable = set(Util.NAMES).intersection(components)
|
||||
if(len(applicable) == 0):
|
||||
LOG.error("No valid components specified!")
|
||||
LOG.info("Perhaps you should try %s --help" % (me))
|
||||
return 1
|
||||
action = args.get("action") or ""
|
||||
action = action.strip()
|
||||
action = action.lower()
|
||||
if(not (action in Util.ACTIONS)):
|
||||
LOG.error("No valid action specified!")
|
||||
LOG.info("Perhaps you should try %s --help" % (me))
|
||||
return 1
|
||||
rootdir = args.get("dir") or ""
|
||||
if(len(rootdir) == 0):
|
||||
LOG.error("No valid root directory specified!")
|
||||
LOG.info("Perhaps you should try %s --help" % (me))
|
||||
return 1
|
||||
#check if implemented yet
|
||||
if(not action in ACTION_CLASSES or not action in FUNC_MAP):
|
||||
LOG.error("Action %s not implemented yet!" % (action))
|
||||
return 1
|
||||
#ensure os is known
|
||||
(install_os, plt) = determine_os()
|
||||
if(install_os == None):
|
||||
LOG.error("Unsupported operating system/distro: %s" % (plt))
|
||||
return 1
|
||||
if(os.path.isdir(rootdir) and action == Util.INSTALL):
|
||||
LOG.error("Root directory [%s] already exists! Please remove it!" % (rootdir))
|
||||
return 1
|
||||
#start it
|
||||
welcome(action)
|
||||
if(action in DEP_ACTIONS_NEEDED):
|
||||
# need to figure out deps for components (if any)
|
||||
deps = list()
|
||||
for c in applicable:
|
||||
cdeps = list(set(Util.fetch_deps(c)))
|
||||
if(len(cdeps)):
|
||||
LOG.info("Having to %s [%s] since they are dependencies for %s." % (action, ", ".join(cdeps), c))
|
||||
deps = deps + cdeps
|
||||
deps = deps + [c]
|
||||
applicable = set(deps)
|
||||
#get the right component order (by priority)
|
||||
mporder = dict()
|
||||
for c in applicable:
|
||||
mporder[c] = Util.NAMES_PRIORITY.get(c)
|
||||
#sort by priority value
|
||||
priororder = sorted(mporder.iteritems(), key=operator.itemgetter(1))
|
||||
componentorder = [x[0] for x in priororder]
|
||||
funcAction = FUNC_MAP.get(action)
|
||||
LOG.info("Starting action [%s] on %s for operating system/distro [%s]" % (action, rcf8222date(), install_os))
|
||||
resultList = funcAction(componentorder, install_os, rootdir)
|
||||
LOG.info("Finished action [%s] on %s" % (action, rcf8222date()))
|
||||
if(resultList):
|
||||
msg = "Check [%s] for traces of what happened." % (", ".join(resultList))
|
||||
LOG.info(msg)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
rc = main()
|
||||
sys.exit(rc)
|
170
utils/pkgfinder.pl
Executable file
170
utils/pkgfinder.pl
Executable file
@ -0,0 +1,170 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use FileHandle;
|
||||
use Term::ANSIColor qw(:constants);
|
||||
|
||||
|
||||
sub printinfo
|
||||
{
|
||||
print BOLD, BLUE, "INFO: "."", RESET;
|
||||
println("@_");
|
||||
}
|
||||
|
||||
sub printerror
|
||||
{
|
||||
print BOLD, RED, "ERROR: @_"."\n", RESET;
|
||||
}
|
||||
|
||||
sub run
|
||||
{
|
||||
my ($prog, $die) = @_;
|
||||
#printinfo("Runing command: $prog");
|
||||
my $res = qx/$prog/;
|
||||
my $ok = 0;
|
||||
my $rc = $? >> 8;
|
||||
if($rc == 0)
|
||||
{
|
||||
$ok = 1;
|
||||
}
|
||||
if($ok == 0 && $die == 1)
|
||||
{
|
||||
printerror("Failed running $prog");
|
||||
exit(1);
|
||||
}
|
||||
$res = trim($res);
|
||||
my $out = {};
|
||||
$out->{'status'} = $rc;
|
||||
$out->{'output'} = $res;
|
||||
return $out;
|
||||
}
|
||||
|
||||
sub println
|
||||
{
|
||||
my $arg = shift;
|
||||
if(!defined($arg))
|
||||
{
|
||||
$arg = '';
|
||||
}
|
||||
return print($arg."\n");
|
||||
}
|
||||
|
||||
sub trim
|
||||
{
|
||||
my $string = shift;
|
||||
$string =~ s/^\s+//;
|
||||
$string =~ s/\s+$//;
|
||||
return $string;
|
||||
}
|
||||
|
||||
my $argc = scalar(@ARGV);
|
||||
if($argc == 0)
|
||||
{
|
||||
println($0. " pkglist");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
my $fn = $ARGV[0];
|
||||
my $fh = new FileHandle($fn, "r") || die("Could not open $fn");;
|
||||
my @lines = <$fh>;
|
||||
$fh->close();
|
||||
|
||||
my @all = ();
|
||||
my $ks = {};
|
||||
|
||||
for my $line (@lines)
|
||||
{
|
||||
$line = trim($line);
|
||||
if(length($line) == 0)
|
||||
{
|
||||
next;
|
||||
}
|
||||
my @pieces = split /\s+/, $line;
|
||||
for my $piece (@pieces)
|
||||
{
|
||||
$piece = trim($piece);
|
||||
if(length($piece) == 0)
|
||||
{
|
||||
next;
|
||||
}
|
||||
if(defined($ks->{$piece}))
|
||||
{
|
||||
next;
|
||||
}
|
||||
push(@all, $piece);
|
||||
$ks->{$piece} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@all = sort(@all);
|
||||
printinfo("Finding info about packages:");
|
||||
println(join(", ", @all)."");
|
||||
|
||||
my $info = {};
|
||||
for my $pkg (@all)
|
||||
{
|
||||
printinfo("Finding information about $pkg");
|
||||
my $cmd = "apt-cache showpkg $pkg";
|
||||
my $out = run($cmd, 1)->{'output'};
|
||||
my $version = undef;
|
||||
if($out =~ /Versions:\s+([\S]+)\s+/msi)
|
||||
{
|
||||
$version = $1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printerror("No version found for $pkg");
|
||||
exit(1);
|
||||
}
|
||||
$cmd = "apt-cache depends $pkg";
|
||||
$out = run($cmd, 1)->{'output'};
|
||||
my @tmplines = split /\n|\r/, $out;
|
||||
my @deps = ();
|
||||
for my $aline (@tmplines)
|
||||
{
|
||||
if($aline =~ /\s+Depends:\s*(\S+)\s*/i)
|
||||
{
|
||||
my $dep = trim($1);
|
||||
if(length($dep) > 0)
|
||||
{
|
||||
if($dep =~ /[<>]/)
|
||||
{
|
||||
#not sure why we get these...
|
||||
next;
|
||||
}
|
||||
push(@deps, $dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
my $d = {};
|
||||
$d->{'deps'} = \@deps;
|
||||
$d->{'version'} = $version;
|
||||
$info->{$pkg} = $d;
|
||||
}
|
||||
|
||||
for my $pkg (@all)
|
||||
{
|
||||
my $data = $info->{$pkg};
|
||||
my $version = $data->{version};
|
||||
print STDERR ("+Package name: $pkg\n");
|
||||
print STDERR ("+Package version: $version\n");
|
||||
my @deps = @{$data->{deps}};
|
||||
@deps = sort(@deps);
|
||||
my $tmpk = {};
|
||||
print STDERR ("+Dependencies:\n");
|
||||
for my $dep (@deps)
|
||||
{
|
||||
if(defined($tmpk->{$dep}))
|
||||
{
|
||||
next;
|
||||
}
|
||||
print STDERR ("\t"."$dep\n");
|
||||
$tmpk->{$dep} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
|
Loading…
Reference in New Issue
Block a user