Initial commit for puppet-ec2api

Change-Id: Ied75d3c234eae5533bd6393b4ca2259fbaefa9e4
This commit is contained in:
Marcos Fermin Lobo 2016-02-04 10:04:48 +01:00
parent ae25d3d74c
commit 1192cea6ce
30 changed files with 1582 additions and 0 deletions

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
pkg/
Gemfile.lock
vendor/
spec/fixtures/
.vagrant/
.bundle/
coverage/
.idea/
*.swp
*.iml
openstack/

40
Gemfile Normal file
View File

@ -0,0 +1,40 @@
source ENV['GEM_SOURCE'] || "https://rubygems.org"
group :development, :test do
gem 'puppetlabs_spec_helper', :require => 'false'
gem 'rspec-puppet', '~> 2.2.0', :require => 'false'
gem 'rspec-puppet-facts', :require => 'false'
gem 'metadata-json-lint', :require => 'false'
gem 'puppet-lint-param-docs', :require => 'false'
gem 'puppet-lint-absolute_classname-check', :require => 'false'
gem 'puppet-lint-absolute_template_path', :require => 'false'
gem 'puppet-lint-trailing_newline-check', :require => 'false'
gem 'puppet-lint-unquoted_string-check', :require => 'false'
gem 'puppet-lint-leading_zero-check', :require => 'false'
gem 'puppet-lint-variable_contains_upcase', :require => 'false'
gem 'puppet-lint-numericvariable', :require => 'false'
gem 'json', :require => 'false'
gem 'puppet-openstack_spec_helper',
:git => 'https://git.openstack.org/openstack/puppet-openstack_spec_helper',
:require => false
end
group :system_tests do
gem 'beaker-rspec', :require => 'false'
gem 'beaker-puppet_install_helper', :require => 'false'
gem 'r10k', :require => 'false'
end
if facterversion = ENV['FACTER_GEM_VERSION']
gem 'facter', facterversion, :require => false
else
gem 'facter', :require => false
end
if puppetversion = ENV['PUPPET_GEM_VERSION']
gem 'puppet', puppetversion, :require => false
else
gem 'puppet', :require => false
end
# vim:ft=ruby

13
LICENSE Normal file
View File

@ -0,0 +1,13 @@
Copyright 2015 OpenStack Foundation
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.

33
README.md Normal file
View File

@ -0,0 +1,33 @@
ec2api
=======
#### Table of Contents
1. [Overview - What is the ec2api module?](#overview)
2. [Module Description - What does the module do?](#module-description)
3. [Development - Guide for contributing to the module](#development)
4. [Contributors](#contributors)
Overview
--------
The puppet-ec2api is the puppet module for module [OpenStack EC2 API](https://github.com/openstack/ec2-api) project.
Please note that this is WIP and this puppet module is not ready for production environments yet.
Module Description
------------------
The ec2api module is a thorough attempt to make Puppet capable of managing the entirety of OpenStack EC2 API project. This includes manifests to provision region specific endpoint and database connections. Types are shipped as part of the ec2api module to assist in manipulation of configuration files.
Development
-----------
Developer documentation for the entire puppet-openstack project.
* https://wiki.openstack.org/wiki/Puppet#Developer_documentation
Contributors
------------
* https://github.com/openstack/puppet-ec2api/graphs/contributors

1
Rakefile Normal file
View File

@ -0,0 +1 @@
require 'puppet-openstack_spec_helper/rake_tasks'

View File

@ -0,0 +1,27 @@
Puppet::Type.type(:ec2api_api_paste_ini).provide(
:ini_setting,
:parent => Puppet::Type.type(:ini_setting).provider(:ruby)
) do
def section
resource[:name].split('/', 2).first
end
def setting
resource[:name].split('/', 2).last
end
def separator
'='
end
def self.file_path
'/etc/ec2api/api-paste.ini'
end
# added for backwards compatibility with older versions of inifile
def file_path
self.class.file_path
end
end

View File

@ -0,0 +1,22 @@
Puppet::Type.type(:ec2api_config).provide(
:ini_setting,
:parent => Puppet::Type.type(:ni_setting).provider(:ruby)
) do
def section
resource[:name].split('/', 2).first
end
def setting
resource[:name].split('/', 2).last
end
def separator
'='
end
def self.file_path
'/etc/ec2api/ec2api.conf'
end
end

View File

@ -0,0 +1,9 @@
Puppet::Type.newtype(:ec2api_api_paste_ini) do
ensurable
newparam(:name, :namevar => true) do
desc 'Section/setting name to manage from /etc/ec2api/api-paste.ini'
newvalues(/\S+\/\S+/)
end
end

View File

@ -0,0 +1,12 @@
Puppet::Type.newtype(:ec2api_config) do
ensurable do
defaultvalues
defaultto :present
end
newparam(:name, :namevar => true) do
desc 'Section/setting name to manage from ec2api.conf'
newvalues(/\S+\/\S+/)
end
end

298
manifests/api.pp Normal file
View File

@ -0,0 +1,298 @@
# == Class: ec2api::api
#
# EC2 API class to configure the API service via puppet.
#
# === Parameters
#
# [*debug*]
# Print debugging output (set logging level to DEBUG instead of default
# WARNING level). Defaults to false
#
# [*verbose*]
# Print more verbose output (set logging level to INFO instead of default
# WARNING level). Defaults to false
#
# [*admin_user*]
# The user does not need admin credentials into the project
# Admin use. Defaults to undef
#
# [*admin_password*]
# Admin password. Defaults to undef
#
# [*admin_tenant_name*]
# Admin tenant name. Defaults to undef
#
# [*api_paste_config*]
# File name for the paste.deploy config for ec2api (string
# value). Defaults to 'api-paste.ini'
#
# [*log_file*]
# (optional) File where logs should be stored.
# If set to boolean false, it will not log to any file.
# Defaults to '/var/log/ec2api/ec2api.log'
#
# [*ca_file*]
# (optional) CA certificate file to use to verify connecting clients
# Defaults to false, not set
#
# [*cert_file*]
# (optinal) Certificate file to use when starting API server securely
# Defaults to false, not set
#
# [*key_file*]
# (optional) Private key file to use when starting API server securely
# Defaults to false, not set
#
# [*keystone_url*]
# URL to get token from ec2 request. (string value).
# Defaults to 'http://localhost:5000/v2.0'#
#
# [*keystone_ec2_tokens_url*]
# URL to get token from ec2 request.(string value).
# Defaults to '$keystone_url/ec2tokens'
#
class ec2api::api (
$manage_service = true,
$enabled = true,
$debug = false,
$verbose = false,
$admin_user = undef,
$admin_password = undef,
$admin_tenant_name = undef,
$fatal_exception_format_errors = false,
$ec2api_listen = '0.0.0.0',
$ec2api_listen_port = 8788,
$ec2api_use_ssl = false,
$ec2api_workers = undef,
$metadata_listen = '0.0.0.0',
$metadata_listen_port = 8789,
$metadata_use_ssl = false,
$metadata_workers = undef,
$service_down_time = 60,
$api_paste_config = 'api-paste.ini',
$log_dir = '/var/log/ec2api',
$use_ssl = false,
$wsgi_ssl_ca_file = undef,
$wsgi_ssl_cert_file = undef,
$wsgi_ssl_key_file = undef,
$database_use_tpool = false,
$database_connection = 'sqlite:////var/lib/ec2api/ec2api.sqlite',
$keystone_url = 'http://localhost:5000/v2.0',
$keystone_ec2_tokens_url = 'http://localhost:5000/v2.0/ec2tokens',
$ec2_timestamp_expiry = 300,
$api_rate_limit = false,
$use_forwarded_for = false,
$internal_service_availability_zone = internal,
$my_ip = '10.0.0.1',
$ec2_host = $my_ip,
$ec2_port = 8788,
$ec2_scheme = 'http',
$ec2_path = '/',
$region_list = undef,
$full_vpc_support = true,
$network_device_mtu = 1500,
$cert_topic = 'cert',
$image_decryption_dir = '/tmp',
$s3_host = '10.0.0.1',
$s3_use_ssl = false,
$s3_affix_tenant = false,
$ec2_private_dns_show_ip = false,
$external_network = undef,
# [keystone_authtoken]
$auth_admin_prefix = undef,
$auth_host = '127.0.0.1',
$auth_port = 35357,
$auth_protocol = 'https',
$auth_uri = 'http://localhost:5000/',
$identity_uri = 'http://localhost:35357/',
$auth_version = 'v2.0',
$delay_auth_decision = false,
$http_connect_timeout = undef,
$http_request_max_retries = 3,
$admin_token = undef,
$keystone_admin_user = 'ec2api',
$keystone_admin_tenant_name = 'services',
$keystone_admin_password = undef,
$keystone_certfile = undef,
$keystone_keyfile = undef,
$keystone_cafile = undef,
$insecure = false,
$signing_dir = undef,
$memcached_servers = undef,
$token_cache_time = 300,
$revocation_cache_time = 10,
$memcache_security_strategy = undef,
$memcache_secret_key = undef,
$include_service_catalog = true,
$enforce_token_bind = permissive,
$check_revocations_for_cached = false,
$hash_algorithms = 'md5',
# [metadata]
$nova_metadata_ip = '127.0.0.1',
$nova_metadata_port = 8775,
$nova_metadata_protocol = 'http',
$nova_metadata_insecure = false,
$auth_ca_cert = undef,
$nova_client_cert = undef,
$nova_client_priv_key = undef,
$metadata_proxy_shared_secret = undef
) inherits ec2api {
Package[$ec2api::params::package_name] -> Ec2api_config<||>
Package[$ec2api::params::package_name] -> Ec2api_api_paste_ini<||>
if $use_ssl {
if !$wsgi_ssl_cert_file {
fail("The wsgi_ssl_cert_file parameter is required when use_ssl is \
set to true")
}
if !$wsgi_ssl_key_file {
fail("The wsgi_ssl_key_file parameter is required when use_ssl is \
set to true")
}
}
# Set values to ec2api.conf file
ec2api_config {
'DEFAULT/debug': value => $debug;
'DEFAULT/verbose': value => $verbose;
'DEFAULT/admin_user': value => $admin_user;
'DEFAULT/admin_password':
value => $admin_password;
'DEFAULT/admin_tenant_name': value => $admin_tenant_name;
'DEFAULT/fatal_exception_format_errors':
value => $fatal_exception_format_errors;
'DEFAULT/ec2api_listen': value => $ec2api_listen;
'DEFAULT/ec2api_listen_port': value => $ec2api_listen_port;
'DEFAULT/ec2api_use_ssl': value => $ec2api_use_ssl;
'DEFAULT/ec2api_workers': value => $ec2api_workers;
'DEFAULT/metadata_listen': value => $metadata_listen;
'DEFAULT/metadata_listen_port': value => $metadata_listen_port;
'DEFAULT/metadata_use_ssl': value => $metadata_use_ssl;
'DEFAULT/metadata_workers': value => $metadata_workers;
'DEFAULT/service_down_time': value => $service_down_time;
'DEFAULT/api_paste_config': value => $api_paste_config;
'database/use_tpool': value => $database_use_tpool;
'database/connection': value => $database_connection;
'DEFAULT/keystone_url': value => $keystone_url;
'DEFAULT/keystone_ec2_tokens_url':
value => $keystone_ec2_tokens_url;
'DEFAULT/ec2_timestamp_expiry':
value => $ec2_timestamp_expiry;
'DEFAULT/api_rate_limit': value => $api_rate_limit;
'DEFAULT/use_forwarded_for': value => $use_forwarded_for;
'DEFAULT/internal_service_availability_zone':
value => $internal_service_availability_zone;
'DEFAULT/my_ip': value => $my_ip;
#'DEFAULT/ec2_host': value => $ec2_host;
'DEFAULT/ec2_port': value => $ec2_port;
'DEFAULT/ec2_scheme': value => $ec2_scheme;
'DEFAULT/ec2_path': value => $ec2_path;
'DEFAULT/region_list': value => $region_list;
'DEFAULT/full_vpc_support': value => $full_vpc_support;
'DEFAULT/network_device_mtu': value => $network_device_mtu;
'DEFAULT/cert_topic': value => $cert_topic;
'DEFAULT/image_decryption_dir':
value => $image_decryption_dir;
'DEFAULT/s3_host': value => $s3_host;
'DEFAULT/s3_use_ssl': value => $s3_use_ssl;
'DEFAULT/s3_affix_tenant': value => $s3_affix_tenant;
'DEFAULT/ec2_private_dns_show_ip':
value => $ec2_private_dns_show_ip;
'DEFAULT/external_network': value => $external_network;
'keystone_authtoken/auth_admin_prefix': value => $auth_admin_prefix;
'keystone_authtoken/auth_host': value => $auth_host;
'keystone_authtoken/auth_port': value => $auth_port;
'keystone_authtoken/auth_protocol': value => $auth_protocol;
'keystone_authtoken/auth_uri': value => $auth_uri;
'keystone_authtoken/identity_uri': value => $identity_uri;
'keystone_authtoken/auth_version': value => $auth_version;
'keystone_authtoken/delay_auth_decision': value => $delay_auth_decision;
'keystone_authtoken/http_connect_timeout':
value => $http_connect_timeout;
'keystone_authtoken/http_request_max_retries':
value => $http_request_max_retries;
'keystone_authtoken/admin_token': value =>$admin_token;
'keystone_authtoken/admin_user': value => $keystone_admin_user;
'keystone_authtoken/admin_tenant':
value => $keystone_admin_tenant_name;
'keystone_authtoken/admin_password':
value => $keystone_admin_password;
'keystone_authtoken/certfile': value => $keystone_certfile;
'keystone_authtoken/keyfile': value => $keystone_keyfile;
'keystone_authtoken/cafile': value => $keystone_cafile;
'keystone_authtoken/insecure': value => $insecure;
'keystone_authtoken/signing_dir': value => $signing_dir;
'keystone_authtoken/memcached_servers': value => $memcached_servers;
'keystone_authtoken/token_cache_time': value => $token_cache_time;
'keystone_authtoken/revocation_cache_time':
value => $revocation_cache_time;
'keystone_authtoken/memcache_security_strategy':
value => $memcache_security_strategy;
'keystone_authtoken/memcache_secret_key':
value => $memcache_secret_key;
'keystone_authtoken/include_service_catalog':
value => $include_service_catalog;
'keystone_authtoken/enforce_token_bind': value => $enforce_token_bind;
'keystone_authtoken/check_revocations_for_cached':
value => $check_revocations_for_cached;
'keystone_authtoken/hash_algorithms': value => $hash_algorithms;
'metadata/nova_metadata_ip':
value => $nova_metadata_ip;
'metadata/nova_metadata_port':
value => $nova_metadata_port;
'metadata/nova_metadata_protocol':
value => $nova_metadata_protocol;
'metadata/nova_metadata_insecure':
value => $nova_metadata_insecure;
'metadata/auth_ca_cert':
value => $auth_ca_cert;
'metadata/nova_client_cert':
value => $nova_client_cert;
'metadata/nova_client_priv_key':
value => $nova_client_priv_key;
'metadata/metadata_proxy_shared_secret':
value => $metadata_proxy_shared_secret;
}
# SSL options
if $use_ssl {
ec2api_config {
'DEFAULT/ssl_ca_file': value => $wsgi_ssl_ca_file;
'DEFAULT/ssl_cert_file': value => $wsgi_ssl_cert_file;
'DEFAULT/ssl_key_file': value => $wsgi_ssl_key_file;
}
if $wsgi_ssl_ca_file {
ec2api_config {
'DEFAULT/ssl_ca_file' : value => $wsgi_ssl_ca_file,
}
} else {
ec2api_config {
'DEFAULT/ssl_ca_file' : ensure => absent,
}
}
} else {
ec2api_config {
'DEFAULT/ssl_cert_file' : ensure => absent;
'DEFAULT/ssl_key_file' : ensure => absent;
'DEFAULT/ssl_ca_file' : ensure => absent;
}
}
if $manage_service {
if $enabled {
$service_ensure = 'running'
} else {
$service_ensure = 'stopped'
}
}
service { 'ec2api-api-service':
ensure => $service_ensure,
name => $::ec2api::params::api_service_name,
enable => $enabled,
hasstatus => true,
hasrestart => true,
}
}

39
manifests/config.pp Normal file
View File

@ -0,0 +1,39 @@
# == Class: ec2api::config
#
# This class is used to manage arbitrary ec2api configurations.
#
# === Parameters
#
# [*ec2api_config*]
# (optional) Allow configuration of arbitrary ec2api configurations.
# The value is an hash of ec2api_config resources. Example:
# { 'DEFAULT/foo' => { value => 'fooValue'},
# 'DEFAULT/bar' => { value => 'barValue'}
# }
# In yaml format, Example:
# ec2api_config:
# DEFAULT/foo:
# value: fooValue
# DEFAULT/bar:
# value: barValue
#
# [**ec2api_config**]
# (optional) Allow configuration of ec2api.conf configurations.
#
# [**api_paste_ini_config**]
# (optional) Allow configuration of /etc/ec2api/api-paste.ini configurations.
#
# NOTE: The configuration MUST NOT be already handled by this module
# or Puppet catalog compilation will fail with duplicate resources.
#
class ec2api::config (
$ec2api_config = {},
$api_paste_ini_config = {},
) {
validate_hash($ec2api_config)
validate_hash($api_paste_ini_config)
create_resources('ec2api_config', $ec2api_config)
create_resources('ec2api_api_paste_ini', $api_paste_ini_config)
}

70
manifests/db/mysql.pp Normal file
View File

@ -0,0 +1,70 @@
# The ec2api::db::mysql class implements mysql backend for ec2api
#
# This class can be used to create tables, users and grant
# privelege for a mysql ec2api database.
#
# == parameters
#
# [*password*]
# (Mandatory) Password to connect to the database.
# Defaults to 'false'.
#
# [*dbname*]
# (Optional) Name of the database.
# Defaults to 'ec2api'.
#
# [*user*]
# (Optional) User to connect to the database.
# Defaults to 'ec2api'.
#
# [*host*]
# (Optional) The default source host user is allowed to connect from.
# Defaults to '127.0.0.1'
#
# [*allowed_hosts*]
# (Optional) Other hosts the user is allowed to connect from.
# Defaults to 'undef'.
#
# [*charset*]
# (Optional) The database charset.
# Defaults to 'utf8'
#
# [*collate*]
# (Optional) The database collate.
# Only used with mysql modules >= 2.2.
# Defaults to 'utf8_general_ci'
#
# == Dependencies
# Class['mysql::server']
#
# == Examples
#
# == Authors
#
# == Copyright
#
class ec2api::db::mysql(
$password,
$dbname = 'ec2api',
$user = 'ec2api',
$host = '127.0.0.1',
$charset = 'utf8',
$collate = 'utf8_general_ci',
$allowed_hosts = undef
) {
validate_string($password)
::openstacklib::db::mysql { 'ec2api':
user => $user,
password_hash => mysql_password($password),
dbname => $dbname,
host => $host,
charset => $charset,
collate => $collate,
allowed_hosts => $allowed_hosts,
}
::Openstacklib::Db::Mysql['ec2api'] ~>
Exec<| title == 'ec2-api-manage db_sync' |>
}

View File

@ -0,0 +1,56 @@
# == Class: ec2api::db::postgresql
#
# Class that configures postgresql for ec2api
# Requires the Puppetlabs postgresql module.
#
# === Parameters
#
# [*password*]
# (Required) Password to connect to the database.
#
# [*dbname*]
# (Optional) Name of the database.
# Defaults to 'ec2api'.
#
# [*user*]
# (Optional) User to connect to the database.
# Defaults to 'ec2api'.
#
# [*encoding*]
# (Optional) The charset to use for the database.
# Default to undef.
#
# [*privileges*]
# (Optional) Privileges given to the database user.
# Default to 'ALL'
#
# == Dependencies
#
# == Examples
#
# == Authors
#
# == Copyright
#
class ec2api::db::postgresql(
$password,
$dbname = 'ec2api',
$user = 'ec2api',
$encoding = undef,
$privileges = 'ALL',
) {
Class['ec2api::db::postgresql'] -> Service<| title == 'ec2api' |>
::openstacklib::db::postgresql { 'ec2api':
password_hash => postgresql_password($user, $password),
dbname => $dbname,
user => $user,
encoding => $encoding,
privileges => $privileges,
}
::Openstacklib::Db::Postgresql['ec2api'] ~>
Exec<| title == 'ec2-api-manage db_sync' |>
}

14
manifests/db/sync.pp Normal file
View File

@ -0,0 +1,14 @@
#
# Class to execute "ec2api-manage db_sync
#
class ec2api::db::sync {
exec { 'ec2api-manage db_sync':
path => '/usr/bin',
user => 'ec2api',
refreshonly => true,
subscribe => [Package['ec2api'], Ec2api_config['database/connection']],
require => User['ec2api'],
}
Exec['ec2-api-manage db_sync'] ~> Service<| title == 'ec2api' |>
}

33
manifests/init.pp Normal file
View File

@ -0,0 +1,33 @@
# == Class: ec2api
#
# Main EC2 API class to configure the service via puppet.
#
class ec2api {
include ec2api::params
# Install the package
package { 'ec2api':
ensure => present,
name => $ec2api::params::package_name,
}
# Chanage onwer, group and permissions to config files
file { $ec2api::params::ec2api_config:
ensure => present,
owner => 'ec2api',
group => 'ec2api',
mode => '0644',
require => Package['ec2api'],
}
file { $ec2api::params::ec2api_api_paste_ini:
ensure => present,
owner => 'ec2api',
group => 'ec2api',
mode => '0644',
require => Package['ec2api'],
}
}

118
manifests/keystone/auth.pp Normal file
View File

@ -0,0 +1,118 @@
# == Class: ec2api::keystone::auth
#
# Configures ec2api user, service and endpoint in Keystone.
#
# === Parameters
#
# [*password*]
# (required) Password for ec2api user.
#
# [*auth_name*]
# Username for ec2api service. Defaults to 'ec2api'.
#
# [*email*]
# Email for ec2api user. Defaults to 'ec2api@localhost'.
#
# [*tenant*]
# Tenant for ec2api user. Defaults to 'services'.
#
# [*configure_endpoint*]
# Should ec2api endpoint be configured? Defaults to 'true'.
#
# [*configure_user*]
# (Optional) Should the service user be configured?
# Defaults to 'true'.
#
# [*configure_user_role*]
# (Optional) Should the admin role be configured for the service user?
# Defaults to 'true'.
#
# [*service_type*]
# Type of service. Defaults to 'FIXME'.
#
# [*public_protocol*]
# Protocol for public endpoint. Defaults to 'http'.
#
# [*public_address*]
# Public address for endpoint. Defaults to '127.0.0.1'.
#
# [*admin_protocol*]
# Protocol for admin endpoint. Defaults to 'http'.
#
# [*admin_address*]
# Admin address for endpoint. Defaults to '127.0.0.1'.
#
# [*internal_protocol*]
# Protocol for internal endpoint. Defaults to 'http'.
#
# [*internal_address*]
# Internal address for endpoint. Defaults to '127.0.0.1'.
#
# [*port*]
# Port for endpoint. Defaults to 'FIXME'.
#
# [*public_port*]
# Port for public endpoint. Defaults to $port.
#
# [*region*]
# Region for endpoint. Defaults to 'RegionOne'.
#
# [*service_name*]
# (optional) Name of the service.
# Defaults to the value of auth_name.
#
#
class ec2api::keystone::auth (
$password,
$auth_name = 'ec2api',
$email = 'ec2api@localhost',
$tenant = 'services',
$configure_endpoint = true,
$configure_user = true,
$configure_user_role = true,
$service_name = undef,
$service_type = 'FIXME',
$public_protocol = 'http',
$public_address = '127.0.0.1',
$admin_protocol = 'http',
$admin_address = '127.0.0.1',
$internal_protocol = 'http',
$internal_address = '127.0.0.1',
$port = 'FIXME',
$public_port = undef,
$region = 'RegionOne'
) {
$real_service_name = pick($service_name, $auth_name)
if $configure_user_role {
Keystone_user_role["${auth_name}@${tenant}"] ~>
Service <| name == 'ec2api-server' |>
}
Keystone_endpoint["${region}/${real_service_name}"] ~>
Service <| name == 'ec2api-server' |>
if ! $public_port {
$real_public_port = $port
} else {
$real_public_port = $public_port
}
keystone::resource::service_identity { 'ec2api':
configure_user => $configure_user,
configure_user_role => $configure_user_role,
configure_endpoint => $configure_endpoint,
service_name => $real_service_name,
service_type => $service_type,
service_description => 'ec2api FIXME Service',
region => $region,
auth_name => $auth_name,
password => $password,
email => $email,
tenant => $tenant,
public_url => "${public_protocol}://${public_address}:${real_public_port}/",
internal_url => "${internal_protocol}://${internal_address}:${port}/",
admin_url => "${admin_protocol}://${admin_address}:${port}/",
}
}

211
manifests/logging.pp Normal file
View File

@ -0,0 +1,211 @@
# Class ec2api::logging
#
# ec2api extended logging configuration
#
# == parameters
#
# [*logging_context_format_string*]
# (optional) Format string to use for log messages with context.
# Defaults to undef.
# Example: '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s\
# [%(request_id)s %(user_identity)s] %(instance)s%(message)s'
#
# [*logging_default_format_string*]
# (optional) Format string to use for log messages without context.
# Defaults to undef.
# Example: '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s\
# [-] %(instance)s%(message)s'
#
# [*logging_debug_format_suffix*]
# (optional) Formatted data to append to log format when level is DEBUG.
# Defaults to undef.
# Example: '%(funcName)s %(pathname)s:%(lineno)d'
#
# [*logging_exception_prefix*]
# (optional) Prefix each line of exception output with this format.
# Defaults to undef.
# Example: '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s'
#
# [*log_config_append*]
# The name of an additional logging configuration file.
# Defaults to undef.
# See https://docs.python.org/2/howto/logging.html
#
# [*default_log_levels*]
# (optional) Hash of logger (keys) and level (values) pairs.
# Defaults to undef.
# Example:
# { 'amqp' => 'WARN', 'amqplib' => 'WARN', 'boto' => 'WARN',
# 'qpid' => 'WARN', 'sqlalchemy' => 'WARN', 'suds' => 'INFO',
# 'oslo.messaging' => 'INFO', 'iso8601' => 'WARN',
# 'requests.packages.urllib3.connectionpool' => 'WARN',
# 'urllib3.connectionpool' => 'WARN',
# 'websocket' => 'WARN', 'ec2apimiddleware' => 'WARN',
# 'routes.middleware' => 'WARN', stevedore => 'WARN' }
#
# [*publish_errors*]
# (optional) Publish error events (boolean value).
# Defaults to undef (false if unconfigured).
#
# [*fatal_deprecations*]
# (optional) Make deprecations fatal (boolean value)
# Defaults to undef (false if unconfigured).
#
# [*instance_format*]
# (optional) If an instance is passed with the log message, format it
# like this (string value).
# Defaults to undef.
# Example: '[instance: %(uuid)s] '
#
# [*instance_uuid_format*]
# (optional) If an instance UUID is passed with the log message, format
# it like this (string value).
# Defaults to undef.
# Example: instance_uuid_format='[instance: %(uuid)s] '
# [*log_date_format*]
# (optional) Format string for %%(asctime)s in log records.
# Defaults to undef.
# Example: 'Y-%m-%d %H:%M:%S'
class ec2api::logging(
$logging_context_format_string = undef,
$logging_default_format_string = undef,
$logging_debug_format_suffix = undef,
$logging_exception_prefix = undef,
$log_config_append = undef,
$default_log_levels = undef,
$publish_errors = undef,
$fatal_deprecations = undef,
$instance_format = undef,
$instance_uuid_format = undef,
$log_date_format = undef,
) {
if $logging_context_format_string {
ec2api_config {
'DEFAULT/logging_context_format_string' :
value => $logging_context_format_string;
}
}
else {
ec2api_config {
'DEFAULT/logging_context_format_string' : ensure => absent;
}
}
if $logging_default_format_string {
ec2api_config {
'DEFAULT/logging_default_format_string' :
value => $logging_default_format_string;
}
}
else {
ec2api_config {
'DEFAULT/logging_default_format_string' : ensure => absent;
}
}
if $logging_debug_format_suffix {
ec2api_config {
'DEFAULT/logging_debug_format_suffix' :
value => $logging_debug_format_suffix;
}
}
else {
ec2api_config {
'DEFAULT/logging_debug_format_suffix' : ensure => absent;
}
}
if $logging_exception_prefix {
ec2api_config {
'DEFAULT/logging_exception_prefix' : value => $logging_exception_prefix;
}
}
else {
ec2api_config {
'DEFAULT/logging_exception_prefix' : ensure => absent;
}
}
if $log_config_append {
ec2api_config {
'DEFAULT/log_config_append' : value => $log_config_append;
}
}
else {
ec2api_config {
'DEFAULT/log_config_append' : ensure => absent;
}
}
if $default_log_levels {
ec2api_config {
'DEFAULT/default_log_levels' :
value => join(sort(join_keys_to_values($default_log_levels, '=')), ',');
}
}
else {
ec2api_config {
'DEFAULT/default_log_levels' : ensure => absent;
}
}
if $publish_errors {
ec2api_config {
'DEFAULT/publish_errors' : value => $publish_errors;
}
}
else {
ec2api_config {
'DEFAULT/publish_errors' : ensure => absent;
}
}
if $fatal_deprecations {
ec2api_config {
'DEFAULT/fatal_deprecations' : value => $fatal_deprecations;
}
}
else {
ec2api_config {
'DEFAULT/fatal_deprecations' : ensure => absent;
}
}
if $instance_format {
ec2api_config {
'DEFAULT/instance_format' : value => $instance_format;
}
}
else {
ec2api_config {
'DEFAULT/instance_format' : ensure => absent;
}
}
if $instance_uuid_format {
ec2api_config {
'DEFAULT/instance_uuid_format' : value => $instance_uuid_format;
}
}
else {
ec2api_config {
'DEFAULT/instance_uuid_format' : ensure => absent;
}
}
if $log_date_format {
ec2api_config {
'DEFAULT/log_date_format' : value => $log_date_format;
}
}
else {
ec2api_config {
'DEFAULT/log_date_format' : ensure => absent;
}
}
}

32
manifests/metadata.pp Normal file
View File

@ -0,0 +1,32 @@
# === Parameters
#
#
class ec2api::metadata (
$manage_service = true,
$enabled = true,
$nova_metadata_ip = '127.0.0.1',
$nova_metadata_port = 8775,
$nova_metadata_protocol = 'http',
$nova_metadata_insecure = false,
$auth_ca_cert = unset,
$nova_client_cert = unset,
$nova_client_priv_key = unset,
$metadata_proxy_shared_secret = unset,
) inherits ec2api {
if $manage_service {
if $enabled {
$service_ensure = 'running'
} else {
$service_ensure = 'stopped'
}
}
service { 'openstack-ec2-api-metadata':
ensure => $service_ensure,
name => $::ec2api::params::metadata_service_name,
enable => $enabled,
hasstatus => true,
hasrestart => true,
}
}

12
manifests/params.pp Normal file
View File

@ -0,0 +1,12 @@
# == Class: ec2api::params
#
# These parameters need to be accessed from several locations and
# should be considered to be constant
class ec2api::params {
$package_name = 'openstack-ec2-api'
$api_service_name = 'openstack-ec2-api'
$ec2api_config = '/etc/ec2api/ec2api.conf'
$ec2api_api_paste_ini = '/etc/ec2api/api-paste.ini'
$s3_service_name = 'openstack-ec2-api-s3'
$metadata_service_name = 'openstack-ec2-api-metadata'
}

34
manifests/s3.pp Normal file
View File

@ -0,0 +1,34 @@
# === Parameters
#
#
class ec2api::s3 (
$manage_service = true,
$enabled = true,
$buckets_path = undef,
$s3_listen = '0.0.0.0',
$s3_listen_port = 3334,
) inherits ec2api {
# Configuration
ec2api_config {
'DEFAULT/buckets_path': value => $buckets_path;
'DEFAULT/s3_listen': value => $s3_listen;
'DEFAULT/s3_listen_port': value => $s3_listen_port;
}
if $manage_service {
if $enabled {
$service_ensure = 'running'
} else {
$service_ensure = 'stopped'
}
}
service { 'openstack-ec2-api-s3':
ensure => $service_ensure,
name => $::ec2api::params::s3_service_name,
enable => $enabled,
hasstatus => true,
hasrestart => true,
}
}

34
metadata.json Normal file
View File

@ -0,0 +1,34 @@
{
"name": "puppet-ec2api",
"version": "0.0.1",
"author": "OpenStack Contributors",
"summary": "Puppet module for OpenStack Ec2api",
"license": "Apache-2.0",
"source": "git://github.com/openstack/puppet-ec2api.git",
"project_page": "https://launchpad.net/puppet-ec2api",
"issues_url": "https://bugs.launchpad.net/puppet-ec2api",
"description": "Installs and configures OpenStack Ec2api.",
"operatingsystem_support": [
{
"operatingsystem": "Debian",
"operatingsystemrelease": ["8"]
},
{
"operatingsystem": "Fedora",
"operatingsystemrelease": ["21","22"]
},
{
"operatingsystem": "RedHat",
"operatingsystemrelease": ["7"]
},
{
"operatingsystem": "Ubuntu",
"operatingsystemrelease": ["14.04"]
}
],
"dependencies": [
{ "name": "puppetlabs/inifile", "version_requirement": ">=1.0.0 <2.0.0" },
{ "name": "puppetlabs/stdlib", "version_requirement": ">= 4.0.0 <5.0.0" },
{ "name": "stackforge/openstacklib", "version_requirement": ">=5.0.0 <6.0.0" }
]
}

View File

@ -0,0 +1,62 @@
require 'spec_helper'
describe 'ec2api::db::mysql' do
let :pre_condition do
[
'include mysql::server',
'include ec2api::db::sync'
]
end
let :facts do
{ :osfamily => 'Debian' }
end
let :params do
{
'password' => 'pwd',
}
end
describe 'with only required params' do
it { is_expected.to contain_openstacklib__db__mysql('ec2api').with(
'user' => 'ec2api',
'password_hash' => '*0000000',
'dbname' => 'ec2api',
'host' => '127.0.0.1',
'charset' => 'utf8',
:collate => 'utf8_general_ci',
)}
end
describe "overriding allowed_hosts param to array" do
let :params do
{
:password => 'pwd',
:allowed_hosts => ['127.0.0.1','%']
}
end
end
describe "overriding allowed_hosts param to string" do
let :params do
{
:password => 'pwd',
:allowed_hosts => '192.168.1.1'
}
end
end
describe "overriding allowed_hosts param equals to host param " do
let :params do
{
:password => 'pwd',
:allowed_hosts => '127.0.0.1'
}
end
end
end

View File

@ -0,0 +1,58 @@
require 'spec_helper'
describe 'ec2api::db::postgresql' do
let :req_params do
{ :password => 'pw' }
end
let :pre_condition do
'include postgresql::server'
end
context 'on a RedHat osfamily' do
let :facts do
{
:osfamily => 'RedHat',
:operatingsystemrelease => '7.0',
:concat_basedir => '/var/lib/puppet/concat'
}
end
context 'with only required parameters' do
let :params do
req_params
end
it { is_expected.to contain_postgresql__server__db('ec2api').with(
:user => 'ec2api',
:password => 'pwd'
)}
end
end
context 'on a Debian osfamily' do
let :facts do
{
:operatingsystemrelease => '7.8',
:operatingsystem => 'Debian',
:osfamily => 'Debian',
:concat_basedir => '/var/lib/puppet/concat'
}
end
context 'with only required parameters' do
let :params do
req_params
end
it { is_expected.to contain_postgresql__server__db('ec2api').with(
:user => 'ec2api',
:password => 'pwd'
)}
end
end
end

View File

@ -0,0 +1,127 @@
#
# Unit tests for ec2api::keystone::auth
#
require 'spec_helper'
describe 'ec2api::keystone::auth' do
let :facts do
{ :osfamily => 'Debian' }
end
describe 'with default class parameters' do
let :params do
{ :password => 'pwd',
:tenant => 'services' }
end
it { is_expected.to contain_keystone_user('ec2api').with(
:ensure => 'present',
:password => 'pwd',
:tenant => 'services'
) }
it { is_expected.to contain_keystone_user_role('ec2api@services').with(
:ensure => 'present',
:roles => ['admin']
)}
it { is_expected.to contain_keystone_service('ec2api').with(
:ensure => 'present',
:type => 'ec2',
:description => 'ec2api Service'
) }
it { is_expected.to contain_keystone_endpoint('RegionOne/ec2api').with(
:ensure => 'present',
:public_url => "http://127.0.0.1:8788/",
:admin_url => "http://127.0.0.1:8788/",
:internal_url => "http://127.0.0.1:8788/"
) }
end
describe 'when overriding public_protocol, public_port and public address' do
let :params do
{ :password => 'pwd',
:public_protocol => 'https',
:public_port => '80',
:public_address => '10.10.10.10',
:port => '81',
:internal_address => '10.10.10.11',
:admin_address => '10.10.10.12' }
end
it { is_expected.to contain_keystone_endpoint('RegionOne/ec2api').with(
:ensure => 'present',
:public_url => "https://10.10.10.10:80/",
:internal_url => "http://10.10.10.11:81/",
:admin_url => "http://10.10.10.12:81/"
) }
end
describe 'when overriding auth name' do
let :params do
{ :password => 'foo',
:auth_name => 'ec2apiy' }
end
it { is_expected.to contain_keystone_user('ec2apiy') }
it { is_expected.to contain_keystone_user_role('ec2apiy@services') }
it { is_expected.to contain_keystone_service('ec2apiy') }
it { is_expected.to contain_keystone_endpoint('RegionOne/ec2apiy') }
end
describe 'when overriding service name' do
let :params do
{ :service_name => 'ec2api_service',
:auth_name => 'ec2api',
:password => 'pwd' }
end
it { is_expected.to contain_keystone_user('ec2api') }
it { is_expected.to contain_keystone_user_role('ec2api@services') }
it { is_expected.to contain_keystone_service('ec2api_service') }
it { is_expected.to contain_keystone_endpoint('RegionOne/ec2api_service') }
end
describe 'when disabling user configuration' do
let :params do
{
:password => 'ec2api_password',
:configure_user => false
}
end
it { is_expected.not_to contain_keystone_user('ec2api') }
it { is_expected.to contain_keystone_user_role('ec2api@services') }
it { is_expected.to contain_keystone_service('ec2api').with(
:ensure => 'present',
:type => 'ec2',
:description => 'ec2api Service'
) }
end
describe 'when disabling user and user role configuration' do
let :params do
{
:password => 'ec2api_password',
:configure_user => false,
:configure_user_role => false
}
end
it { is_expected.not_to contain_keystone_user('ec2api') }
it { is_expected.not_to contain_keystone_user_role('ec2api@services') }
it { is_expected.to contain_keystone_service('ec2api').with(
:ensure => 'present',
:type => 'ec2',
:description => 'ec2api Service'
) }
end
end

View File

@ -0,0 +1,107 @@
require 'spec_helper'
describe 'ec2api::logging' do
let :params do
{
}
end
let :log_params do
{
:logging_context_format_string => '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s',
:logging_default_format_string => '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s',
:logging_debug_format_suffix => '%(funcName)s %(pathname)s:%(lineno)d',
:logging_exception_prefix => '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s',
:log_config_append => '/etc/ec2api/logging.conf',
:publish_errors => true,
:default_log_levels => {
'amqp' => 'WARN', 'amqplib' => 'WARN', 'boto' => 'WARN',
'qpid' => 'WARN', 'sqlalchemy' => 'WARN', 'suds' => 'INFO',
'iso8601' => 'WARN',
'requests.packages.urllib3.connectionpool' => 'WARN' },
:fatal_deprecations => true,
:instance_format => '[instance: %(uuid)s] ',
:instance_uuid_format => '[instance: %(uuid)s] ',
:log_date_format => '%Y-%m-%d %H:%M:%S',
}
end
shared_examples_for 'ec2api-logging' do
context 'with extended logging options' do
before { params.merge!( log_params ) }
it_configures 'logging params set'
end
context 'without extended logging options' do
it_configures 'logging params unset'
end
end
shared_examples_for 'logging params set' do
it 'enables logging params' do
is_expected.to contain_ec2api_config('DEFAULT/logging_context_format_string').with_value(
'%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s')
is_expected.to contain_ec2api_config('DEFAULT/logging_default_format_string').with_value(
'%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s')
is_expected.to contain_ec2api_config('DEFAULT/logging_debug_format_suffix').with_value(
'%(funcName)s %(pathname)s:%(lineno)d')
is_expected.to contain_ec2api_config('DEFAULT/logging_exception_prefix').with_value(
'%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s')
is_expected.to contain_ec2api_config('DEFAULT/log_config_append').with_value(
'/etc/ec2api/logging.conf')
is_expected.to contain_ec2api_config('DEFAULT/publish_errors').with_value(
true)
is_expected.to contain_ec2api_config('DEFAULT/default_log_levels').with_value(
'amqp=WARN,amqplib=WARN,boto=WARN,iso8601=WARN,qpid=WARN,requests.packages.urllib3.connectionpool=WARN,sqlalchemy=WARN,suds=INFO')
is_expected.to contain_ec2api_config('DEFAULT/fatal_deprecations').with_value(
true)
is_expected.to contain_ec2api_config('DEFAULT/instance_format').with_value(
'[instance: %(uuid)s] ')
is_expected.to contain_ec2api_config('DEFAULT/instance_uuid_format').with_value(
'[instance: %(uuid)s] ')
is_expected.to contain_ec2api_config('DEFAULT/log_date_format').with_value(
'%Y-%m-%d %H:%M:%S')
end
end
shared_examples_for 'logging params unset' do
[ :logging_context_format_string, :logging_default_format_string,
:logging_debug_format_suffix, :logging_exception_prefix,
:log_config_append, :publish_errors,
:default_log_levels, :fatal_deprecations,
:instance_format, :instance_uuid_format,
:log_date_format, ].each { |param|
it { is_expected.to contain_ec2api_config("DEFAULT/#{param}").with_ensure('absent') }
}
end
context 'on Debian platforms' do
let :facts do
{ :osfamily => 'Debian' }
end
it_configures 'ec2api-logging'
end
context 'on RedHat platforms' do
let :facts do
{ :osfamily => 'RedHat' }
end
it_configures 'ec2api-logging'
end
end

5
spec/shared_examples.rb Normal file
View File

@ -0,0 +1,5 @@
shared_examples_for "a Puppet::Error" do |description|
it "with message matching #{description.inspect}" do
expect { is_expected.to have_class_count(1) }.to raise_error(Puppet::Error, description)
end
end

View File

@ -0,0 +1,37 @@
# these tests are a little concerning b/c they are hacking around the
# modulepath, so these tests will not catch issues that may eventually arise
# related to loading these plugins.
# I could not, for the life of me, figure out how to programatcally set the modulepath
$LOAD_PATH.push(
File.join(
File.dirname(__FILE__),
'..',
'..',
'..',
'fixtures',
'modules',
'inifile',
'lib')
)
require 'spec_helper'
provider_class = Puppet::Type.type(:ec2api_config).provider(:ini_setting)
describe provider_class do
it 'should default to the default setting when no other one is specified' do
resource = Puppet::Type::Ec2api_config.new(
{:name => 'DEFAULT/foo', :value => 'bar'}
)
provider = provider_class.new(resource)
expect(provider.section).to eq('DEFAULT')
expect(provider.setting).to eq('foo')
end
it 'should allow setting to be set explicitly' do
resource = Puppet::Type::Ec2api_config.new(
{:name => 'dude/foo', :value => 'bar'}
)
provider = provider_class.new(resource)
expect(provider.section).to eq('dude')
expect(provider.setting).to eq('foo')
end
end

View File

@ -0,0 +1,52 @@
require 'puppet'
require 'puppet/type/ec2api_config'
describe 'Puppet::Type.type(:ec2api_config)' do
before :each do
@ec2api_config = Puppet::Type.type(:ec2api_config).new(:name => 'DEFAULT/foo', :value => 'bar')
end
it 'should require a name' do
expect {
Puppet::Type.type(:ec2api_config).new({})
}.to raise_error(Puppet::Error, 'Title or name must be provided')
end
it 'should not expect a name with whitespace' do
expect {
Puppet::Type.type(:ec2api_config).new(:name => 'f oo')
}.to raise_error(Puppet::Error, /Parameter name failed/)
end
it 'should fail when there is no section' do
expect {
Puppet::Type.type(:ec2api_config).new(:name => 'foo')
}.to raise_error(Puppet::Error, /Parameter name failed/)
end
it 'should not require a value when ensure is absent' do
Puppet::Type.type(:ec2api_config).new(:name => 'DEFAULT/foo', :ensure => :absent)
end
it 'should accept a valid value' do
@ec2api_config[:value] = 'bar'
expect(@ec2api_config[:value]).to eq('bar')
end
it 'should not accept a value with whitespace' do
@ec2api_config[:value] = 'b ar'
expect(@ec2api_config[:value]).to eq('b ar')
end
it 'should accept valid ensure values' do
@ec2api_config[:ensure] = :present
expect(@ec2api_config[:ensure]).to eq(:present)
@ec2api_config[:ensure] = :absent
expect(@ec2api_config[:ensure]).to eq(:absent)
end
it 'should not accept invalid ensure values' do
expect {
@ec2api_config[:ensure] = :latest
}.to raise_error(Puppet::Error, /Invalid value/)
end
end

3
templates/example.erb Normal file
View File

@ -0,0 +1,3 @@
<% if @myvar %>
myvar has <%= @myvar %> value
<% end %>

12
tests/init.pp Normal file
View File

@ -0,0 +1,12 @@
# The baseline for module testing used by Puppet Labs is that each manifest
# should have a corresponding test manifest that declares that class or defined
# type.
#
# Tests are then run by using puppet apply --noop (to check for compilation
# errors and view a log of events) or by fully applying the test in a virtual
# environment (to compare the resulting system state to the desired state).
#
# Learn more about module testing here:
# http://docs.puppetlabs.com/guides/tests_smoke.html
#
include ::ec2api