Import plugin's code
Change-Id: Ic93c9f6f322d443ec60f8e39231b71b967267e3a
This commit is contained in:
parent
1fafa482b5
commit
87d4536613
|
@ -0,0 +1,176 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
DNS Update Plugin for Fuel
|
||||
=======================
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
DNS Update plugin for Fuel extends Mirantis OpenStack functionality by adding
|
||||
support for configurable dns servers in murano virtual machines via notifications.
|
||||
|
||||
Compatible Fuel versions
|
||||
--------------
|
||||
|
||||
9.0
|
||||
|
||||
User Guide
|
||||
-------------
|
||||
|
||||
1. Create an environment.
|
||||
2. Enable the plugin on the Settings/Other tab of the Fuel web UI and fill in form
|
||||
fields:
|
||||
3. Deploy the environment.
|
||||
|
||||
DNS Update plugin installation
|
||||
---------------------------
|
||||
|
||||
To install DNS Update plugin, follow these steps:
|
||||
|
||||
1. Download the plugin from
|
||||
[Fuel Plugins Catalog](https://software.mirantis.com/fuel-plugins)
|
||||
|
||||
2. Copy the plugin on already installed Fuel Master node; ssh can be used for
|
||||
that. If you do not have the Fuel Master node yet, see
|
||||
[Quick Start Guide](https://software.mirantis.com/quick-start/):
|
||||
|
||||
# scp dns-update-1.0-1.0.0-0.noarch.rpm root@<Fuel_master_ip>:/tmp
|
||||
|
||||
3. Log into the Fuel Master node. Install the plugin:
|
||||
|
||||
# cd /tmp
|
||||
# fuel plugins --install fuel-plugin-dns-update-1.0-1.0.0-0.noarch.rpm
|
||||
|
||||
4. Check if the plugin was installed successfully:
|
||||
|
||||
# fuel plugins
|
||||
id | name | version | package_version
|
||||
---|------------------------|---------|----------------
|
||||
1 | fuel-plugin-dns-update | 1.0.1 | 4.0.0
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
| Requirement | Version/Comment |
|
||||
|:---------------------------------|:----------------|
|
||||
| Mirantis OpenStack compatibility | 9.0 |
|
|
@ -0,0 +1,2 @@
|
|||
include dns_update::controller
|
||||
notice('MODULAR: fuel-plugin-dns-update/controller.pp')
|
|
@ -0,0 +1,2 @@
|
|||
include dns_update::mysql
|
||||
notice('MODULAR: fuel-plugin-dns-update/mysql.pp')
|
|
@ -0,0 +1,2 @@
|
|||
include dns_update::neutron
|
||||
notice('MODULAR: fuel-plugin-dns-update/neutron.pp')
|
|
@ -0,0 +1,2 @@
|
|||
include dns_update::nova
|
||||
notice('MODULAR: fuel-plugin-dns-update/nova.pp')
|
|
@ -0,0 +1,2 @@
|
|||
include dns_update::pacemaker
|
||||
notice('MODULAR: fuel-plugin-dns-update/pacemaker.pp')
|
|
@ -0,0 +1,2 @@
|
|||
include dns_update::service
|
||||
notice('MODULAR: fuel-plugin-dns-update/service.pp')
|
|
@ -0,0 +1,10 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: os_dns_updater
|
||||
Version: 0.0.2
|
||||
Summary: listen to nova RabbitMQ events and update dns records
|
||||
Home-page: UNKNOWN
|
||||
Author: Sberbank Technology
|
||||
Author-email: UNKNOWN
|
||||
License: UNKNOWN
|
||||
Description: service to register virtual machines in dns
|
||||
Platform: UNKNOWN
|
|
@ -0,0 +1 @@
|
|||
# openstack-dns-updater
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
#define db schema
|
||||
|
||||
from sqlalchemy import MetaData, create_engine
|
||||
from sqlalchemy import Table, Column, ForeignKey
|
||||
from sqlalchemy import String, Integer, DateTime, Text
|
||||
|
||||
from os_dns_updater.utils.cfg import DNS_CONF
|
||||
|
||||
dbcred = DNS_CONF["db_user"]+":"+DNS_CONF["db_password"]
|
||||
dbaddr = "mysql://"+dbcred+"@localhost/"+DNS_CONF["db_name"]
|
||||
dbengine = create_engine(dbaddr)
|
||||
dbmeta = MetaData()
|
||||
|
||||
#create empty db manually or fuel plugin
|
||||
|
||||
def init_tables():
|
||||
db_instance = Table("instance", dbmeta,
|
||||
Column("id", Integer, primary_key=True),
|
||||
Column("ip", String(20)),
|
||||
Column("name", String(90)),
|
||||
Column("uuid", String(40)),
|
||||
Column("state", String(90)),
|
||||
Column("dns_domain", String(90)),
|
||||
Column("created_at", DateTime),
|
||||
Column("updated_at", DateTime),
|
||||
Column("deleted_at", DateTime)
|
||||
)
|
||||
db_event = Table("event", dbmeta,
|
||||
#will be used for synchronization
|
||||
Column("id", Integer, primary_key=True),
|
||||
Column("fk_instance_id", Integer, ForeignKey("instance.id")),
|
||||
Column("type", String(24)),#enum
|
||||
Column("description", String(90)),
|
||||
Column("date", DateTime)
|
||||
)
|
||||
dbmeta.drop_all(dbengine)
|
||||
dbmeta.create_all(dbengine)
|
||||
|
||||
init_tables()
|
|
@ -0,0 +1,164 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
#
|
||||
# dnsupdater-failover OCF RA. Does nothing but wait a few seconds, can be
|
||||
# configured to fail occassionally.
|
||||
#
|
||||
# Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Bree
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of version 2 of the GNU General Public License as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it would be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# Further, this software is distributed without any warranty that it is
|
||||
# free of the rightful claim of any third person regarding infringement
|
||||
# or the like. Any license provided herein, whether implied or
|
||||
# otherwise, applies only to this software file. Patent licenses, if
|
||||
# any, provided herein do not apply to combinations of this program with
|
||||
# other software, or any other product whatsoever.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
#
|
||||
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
|
||||
#######################################################################
|
||||
|
||||
meta_data() {
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="dnsupdater-failover" version="0.9">
|
||||
<version>1.0</version>
|
||||
<longdesc lang="en">
|
||||
Failover ocf script for sbrf dns-updater
|
||||
</longdesc>
|
||||
<shortdesc lang="en">ocf for dnsupdater</shortdesc>
|
||||
<parameters>
|
||||
<parameter name="state" unique="1">
|
||||
<longdesc lang="en">
|
||||
Location to store the resource state in.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">State file</shortdesc>
|
||||
<content type="string" default="${HA_RSCTMP}/dnsupdater-failover-${OCF_RESOURCE_INSTANCE}.state" />
|
||||
</parameter>
|
||||
<parameter name="fake" unique="0">
|
||||
<longdesc lang="en">
|
||||
Fake attribute that can be changed to cause a reload
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Fake attribute that can be changed to cause a reload</shortdesc>
|
||||
<content type="string" default="dnsupdater-failover" />
|
||||
</parameter>
|
||||
</parameters>
|
||||
<actions>
|
||||
<action name="start" timeout="20" />
|
||||
<action name="stop" timeout="20" />
|
||||
<action name="monitor" timeout="20" interval="10" depth="0" />
|
||||
<action name="reload" timeout="20" />
|
||||
<action name="migrate_to" timeout="20" />
|
||||
<action name="migrate_from" timeout="20" />
|
||||
<action name="meta-data" timeout="5" />
|
||||
<action name="validate-all" timeout="20" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
dnsupdaterfailover_usage() {
|
||||
cat <<END
|
||||
usage: $0 {start|stop|monitor|migrate_to|migrate_from|validate-all|meta-data}
|
||||
Expects to have a fully populated OCF RA-compliant environment set.
|
||||
END
|
||||
}
|
||||
|
||||
dnsupdaterfailover_start() {
|
||||
dnsupdater-failover_monitor
|
||||
/usr/bin/python /usr/lib/python2.7/dist-packages/os_dns_updater/openstack-dns-updater.py
|
||||
if [ $? = $OCF_SUCCESS ]; then
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
touch ${OCF_RESKEY_state}
|
||||
}
|
||||
|
||||
dnsupdaterfailover_stop() {
|
||||
dnsupdater-failover_monitor
|
||||
if [ $? = $OCF_SUCCESS ]; then
|
||||
rm ${OCF_RESKEY_state}
|
||||
fi
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
dnsupdaterfailover_monitor() {
|
||||
# Monitor _MUST!_ differentiate correctly between running
|
||||
# (SUCCESS), failed (ERROR) or _cleanly_ stopped (NOT RUNNING).
|
||||
# That is THREE states, not just yes/no.
|
||||
|
||||
if [ -f ${OCF_RESKEY_state} ]; then
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
if false ; then
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
if ! ocf_is_probe && [ "$__OCF_ACTION" = "monitor" ]; then
|
||||
# set exit string only when NOT_RUNNING occurs during an actual monitor operation.
|
||||
ocf_exit_reason "No process state file found"
|
||||
fi
|
||||
return $OCF_NOT_RUNNING
|
||||
}
|
||||
|
||||
dnsupdaterfailover_validate() {
|
||||
# Is the state directory writable?
|
||||
state_dir=`dirname "$OCF_RESKEY_state"`
|
||||
touch "$state_dir/$$"
|
||||
if [ $? != 0 ]; then
|
||||
ocf_exit_reason "State file \"$OCF_RESKEY_state\" is not writable"
|
||||
return $OCF_ERR_ARGS
|
||||
fi
|
||||
rm "$state_dir/$$"
|
||||
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
: ${OCF_RESKEY_state=${HA_RSCTMP}/dnsupdater-failover-${OCF_RESOURCE_INSTANCE}.state}
|
||||
: ${OCF_RESKEY_fake="dnsupdaterfailover"}
|
||||
|
||||
case $__OCF_ACTION in
|
||||
meta-data) meta_data
|
||||
exit $OCF_SUCCESS
|
||||
;;
|
||||
start) dnsupdaterfailover_start;;
|
||||
stop) dnsupdaterfailover_stop;;
|
||||
monitor) dnsupdaterfailover_monitor;;
|
||||
migrate_to) ocf_log info "Migrating ${OCF_RESOURCE_INSTANCE} to ${OCF_RESKEY_CRM_meta_migrate_target}."
|
||||
dnsupdaterfailover_stop
|
||||
;;
|
||||
migrate_from) ocf_log info "Migrating ${OCF_RESOURCE_INSTANCE} from ${OCF_RESKEY_CRM_meta_migrate_source}."
|
||||
dnsupdaterfailover_start
|
||||
;;
|
||||
reload) ocf_log info "Reloading ${OCF_RESOURCE_INSTANCE} ..."
|
||||
;;
|
||||
validate-all) dnsupdaterfailover_validate;;
|
||||
usage|help) dnsupdaterfailover_usage
|
||||
exit $OCF_SUCCESS
|
||||
;;
|
||||
*) dnsupdaterfailover_usage
|
||||
exit $OCF_ERR_UNIMPLEMENTED
|
||||
;;
|
||||
esac
|
||||
rc=$?
|
||||
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
|
||||
exit $rc
|
|
@ -0,0 +1,29 @@
|
|||
[DEFAULT]
|
||||
debug=False
|
||||
#networks=
|
||||
#region=
|
||||
|
||||
## AMQP configuration parameters
|
||||
#exchanges=nova,neutron
|
||||
#routing_key=notifications.info
|
||||
#queue_name=dns_updater-test
|
||||
#amqp_hosts=
|
||||
#failover_strategy=round-robin
|
||||
#amqp_user=nova
|
||||
#amqp_password=
|
||||
#event_create=compute.instance.create.end
|
||||
#event_delete=compute.instance.delete.start
|
||||
|
||||
## DNS configuration parameters
|
||||
#nameserver=127.0.0.1
|
||||
#domain=vm.example.net
|
||||
#ttl=1
|
||||
#dns_keyfile='/etc/os_dns_updater/example.key'
|
||||
|
||||
##db created at setup
|
||||
#db_name=
|
||||
#db_user=
|
||||
#db_password=
|
||||
|
||||
#maxcounter=4095
|
||||
#insttime=120
|
|
@ -0,0 +1,224 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
#
|
||||
# DnsUpdater OCF RA. Does nothing but wait a few seconds, can be
|
||||
# configured to fail occassionally.
|
||||
#
|
||||
# Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Brée
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of version 2 of the GNU General Public License as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it would be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# Further, this software is distributed without any warranty that it is
|
||||
# free of the rightful claim of any third person regarding infringement
|
||||
# or the like. Any license provided herein, whether implied or
|
||||
# otherwise, applies only to this software file. Patent licenses, if
|
||||
# any, provided herein do not apply to combinations of this program with
|
||||
# other software, or any other product whatsoever.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
#
|
||||
|
||||
#######################################################################
|
||||
# Initialization:
|
||||
|
||||
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
||||
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
||||
: ${OCF_FUEL_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/fuel}
|
||||
. ${OCF_FUEL_FUNCTIONS_DIR}/ocf-fuel-funcs
|
||||
|
||||
#######################################################################
|
||||
|
||||
# Fill in some defaults if no values are specified
|
||||
|
||||
OCF_RESKEY_binary_default="openstack-dns-updater.py"
|
||||
#OCF_RESKEY_config_default="/etc/aodh/aodh.conf"
|
||||
#OCF_RESKEY_user_default="aodh"
|
||||
OCF_RESKEY_pid_default="${HA_RSCTMP}/${__SCRIPT_NAME}/${__SCRIPT_NAME}.pid"
|
||||
|
||||
: ${HA_LOGTAG="ocf-dns-updater"}
|
||||
: ${HA_LOGFACILITY="daemon"}
|
||||
: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
|
||||
#: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
|
||||
#: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}}
|
||||
: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
|
||||
|
||||
#######################################################################
|
||||
|
||||
usage() {
|
||||
cat <<UEND
|
||||
usage: $0 (start|stop|status)
|
||||
|
||||
$0 manages an OpenStack DnsUpdater Service process as an HA resource
|
||||
|
||||
The 'start' operation starts the service.
|
||||
The 'stop' operation stops the service.
|
||||
The 'status' operation reports whether the service is running
|
||||
|
||||
UEND
|
||||
}
|
||||
|
||||
meta_data() {
|
||||
cat <<END
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="DnsUpdater">
|
||||
<version>1.0</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
sample dnsupdater resource
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Example stateless resource agent</shortdesc>
|
||||
<parameters>
|
||||
<parameter name="pid" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
The pid file to use for this OpenStack Aodh Evaluator Service (aodh-evaluator) instance
|
||||
</longdesc>
|
||||
<shortdesc lang="en">OpenStack Aodh Evaluator Service (aodh-evaluator) pid file</shortdesc>
|
||||
<content type="string" default="${OCF_RESKEY_pid_default}" />
|
||||
</parameter>
|
||||
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20" />
|
||||
<action name="stop" timeout="20" />
|
||||
<action name="status" timeout="20" />
|
||||
</actions>
|
||||
</resource-agent>
|
||||
END
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
dnsupdater_validate() {
|
||||
local rc
|
||||
|
||||
return ${OCF_SUCCESS}
|
||||
}
|
||||
|
||||
dnsupdater_status() {
|
||||
local pid
|
||||
local rc
|
||||
|
||||
# check and make PID file dir
|
||||
local PID_DIR="$( dirname ${OCF_RESKEY_pid} )"
|
||||
if [ ! -d "${PID_DIR}" ] ; then
|
||||
ocf_log debug "Create pid file dir: ${PID_DIR}"
|
||||
mkdir -p "${PID_DIR}"
|
||||
chmod 755 "${PID_DIR}"
|
||||
fi
|
||||
|
||||
if [ ! -f $OCF_RESKEY_pid ]; then
|
||||
ocf_log info "DnsUpdater is not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
else
|
||||
pid=`cat $OCF_RESKEY_pid`
|
||||
fi
|
||||
|
||||
if [ -n "${pid}" ]; then
|
||||
ocf_run -warn kill -s 0 $pid
|
||||
rc=$?
|
||||
else
|
||||
ocf_log err "PID file ${OCF_RESKEY_pid} is empty!"
|
||||
return $OCF_ERR_GENERIC
|
||||
fi
|
||||
|
||||
if [ $rc -eq 0 ]; then
|
||||
return $OCF_SUCCESS
|
||||
else
|
||||
ocf_log info "Old PID file found, but DnsUpdater not running"
|
||||
return $OCF_NOT_RUNNING
|
||||
fi
|
||||
}
|
||||
|
||||
dnsupdater_monitor() {
|
||||
local rc
|
||||
local pid
|
||||
|
||||
dnsupdater_status
|
||||
rc=$?
|
||||
|
||||
# If status returned anything but success, return that immediately
|
||||
if [ $rc -ne $OCF_SUCCESS ]; then
|
||||
return $rc
|
||||
fi
|
||||
|
||||
ocf_log debug "OpenStack DnsUpdater monitor succeeded"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
dnsupdater_start() {
|
||||
dnsupdater_status
|
||||
rc=$?
|
||||
if [ $rc -eq $OCF_SUCCESS ]; then
|
||||
ocf_log info "OpenStack DnsUpdater is already running"
|
||||
return $OCF_SUCCESS
|
||||
fi
|
||||
|
||||
/usr/bin/python /usr/lib/python2.7/dist-packages/os_dns_updater/openstack-dns-updater.py >> /dev/null 2>&1 & echo $! > $OCF_RESKEY_pid
|
||||
ocf_log debug "Create pid file: ${OCF_RESKEY_pid} with content $(cat ${OCF_RESKEY_pid})"
|
||||
# Spin waiting for the server to come up.
|
||||
while true; do
|
||||
dnsupdater_monitor
|
||||
rc=$?
|
||||
[ $rc -eq $OCF_SUCCESS ] && break
|
||||
if [ $rc -ne $OCF_NOT_RUNNING ]; then
|
||||
ocf_log err "OpenStack DnsUpdater start failed"
|
||||
exit $OCF_ERR_GENERIC
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
ocf_log info "OpenStack DnsUpdater started"
|
||||
return $OCF_SUCCESS
|
||||
}
|
||||
|
||||
dnsupdater_stop() {
|
||||
local rc
|
||||
local shutdown_timeout=15
|
||||
if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then
|
||||
shutdown_timeout=$(( ($OCF_RESKEY_CRM_meta_timeout/1000) ))
|
||||
fi
|
||||
|
||||
dnsupdater_status
|
||||
rc="${?}"
|
||||
if [ "${rc}" -eq "${OCF_NOT_RUNNING}" ]; then
|
||||
ocf_log info "OpenStack DnsUpdater (${OCF_RESKEY_binary}) already stopped"
|
||||
return "${OCF_SUCCESS}"
|
||||
fi
|
||||
|
||||
proc_stop "${OCF_RESKEY_pid}" "${OCF_RESKEY_binary}" $shutdown_timeout
|
||||
return "${?}"
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
case "$1" in
|
||||
meta-data) meta_data
|
||||
exit $OCF_SUCCESS;;
|
||||
usage|help) usage
|
||||
exit $OCF_SUCCESS;;
|
||||
esac
|
||||
|
||||
# Anything except meta-data and help must pass validation
|
||||
dnsupdater_validate || exit $?
|
||||
|
||||
# What kind of method was invoked?
|
||||
case "$1" in
|
||||
start) dnsupdater_start;;
|
||||
stop) dnsupdater_stop;;
|
||||
status) dnsupdater_status;;
|
||||
monitor) dnsupdater_monitor;;
|
||||
validate-all) ;;
|
||||
*) usage
|
||||
exit $OCF_ERR_UNIMPLEMENTED;;
|
||||
esac
|
|
@ -0,0 +1,79 @@
|
|||
#! /bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: skeleton
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Example initscript
|
||||
# Description: This file should be used to construct scripts to be
|
||||
# placed in /etc/init.d.
|
||||
### END INIT INFO
|
||||
|
||||
# Do NOT "set -e"
|
||||
|
||||
# PATH should only include /usr/* if it runs after the mountnfs.sh script
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||
DIR=/usr/lib/python2.7/dist-packages/os_dns_updater
|
||||
DESC="Description of the service"
|
||||
DAEMON_NAME=openstack-dns-updater
|
||||
DAEMON="/usr/bin/python $DIR/openstack-dns-updater.py"
|
||||
DAEMON_ARGS=""
|
||||
PIDFILE=/var/run/$DAEMON_NAME.pid
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
# Function that starts the daemon/service
|
||||
#
|
||||
do_start()
|
||||
{
|
||||
logger "DEBUG: entered start function"
|
||||
log_daemon_msg "Starting openstack-dns-updater"
|
||||
start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --startas $DAEMON
|
||||
ret=$?
|
||||
logger "DEBUG: return code: $ret"
|
||||
logger "DEBUG: vars: pidfile - $PIDFILE daemon - $DAEMON"
|
||||
log_end_msg $?
|
||||
}
|
||||
|
||||
do_stop()
|
||||
{
|
||||
#AP_RET=1 - running
|
||||
#AP_RET=0 - not running
|
||||
if [ -f $PIDFILE ];
|
||||
then
|
||||
AP_RET=1
|
||||
else
|
||||
AP_RET=0
|
||||
fi
|
||||
|
||||
if [ $AP_RET = 0 ];
|
||||
then
|
||||
log_daemon_msg "Openstack-dns-updater daemon is already stopped"
|
||||
exit 0
|
||||
elif [ $AP_RET = 1 ];
|
||||
then
|
||||
log_daemon_msg "Stopping openstack-dns-updater"
|
||||
start-stop-daemon --stop --signal 2 --pidfile $PIDFILE --retry 10
|
||||
rm -f $PIDFILE
|
||||
log_end_msg $?
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start|stop)
|
||||
do_${1}
|
||||
;;
|
||||
restart|reload|force-reload)
|
||||
do_stop
|
||||
do_start
|
||||
;;
|
||||
status)
|
||||
status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit 3
|
||||
;;
|
||||
*)
|
||||
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
|
||||
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
|
@ -0,0 +1,19 @@
|
|||
# openstack-dns-updater.upstart - run DNS updater script
|
||||
|
||||
description "OpenStack DNS Updater"
|
||||
|
||||
start on runlevel [2345]
|
||||
stop on runlevel [!2345]
|
||||
|
||||
respawn
|
||||
respawn limit 10 5
|
||||
umask 022
|
||||
|
||||
# The following is not needed when using /usr/bin/python
|
||||
# expect fork
|
||||
|
||||
# /var/log/upstart/openstack-dns-updater.log should be empty
|
||||
# Logs to /var/log/nova/dns-updater.log
|
||||
console log
|
||||
|
||||
exec /usr/bin/python /usr/lib/python2.7/dist-packages/os_dns_updater/openstack-dns-updater.py
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python
|
||||
# module to clear db every hour_of_day
|
||||
import time, datetime
|
||||
from os_dns_updater.utils import db_lib
|
||||
from os_dns_updater.utils.cfg import DNS_CONF
|
||||
from os_dns_updater.utils.cfg import LOG_FILE
|
||||
|
||||
import logging as log
|
||||
|
||||
log_level = log.DEBUG if (DNS_CONF["debug"] == "True") else log.INFO
|
||||
log.basicConfig(filename=LOG_FILE, level=log_level,
|
||||
format="%(levelname)s %(asctime)s %(message)s")
|
||||
|
||||
while 1:
|
||||
hour_of_day = datetime.datetime.timetuple(datetime.datetime.now())[3]
|
||||
if hour_of_day == 21:
|
||||
db_lib.check_and_clear()
|
||||
time.sleep(3599)
|
|
@ -0,0 +1,157 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# module to work with rabbitmq (main)
|
||||
|
||||
#TODO!!! delete old records on time
|
||||
from kombu import BrokerConnection
|
||||
from kombu import Exchange
|
||||
from kombu import Queue
|
||||
from kombu.mixins import ConsumerMixin
|
||||
|
||||
from os_dns_updater.utils import dns_lib
|
||||
from os_dns_updater.utils import db_lib
|
||||
from os_dns_updater.utils.cfg import LOG_FILE, DNS_CONF
|
||||
|
||||
import json
|
||||
import logging as log
|
||||
|
||||
log_level = log.DEBUG if (DNS_CONF["debug"] == "True") else log.INFO
|
||||
log.basicConfig(filename=LOG_FILE, level=log_level,
|
||||
format="%(levelname)s %(name)s %(asctime)s %(message)s")
|
||||
|
||||
class DnsUpdater(ConsumerMixin):
|
||||
|
||||
def __init__(self, connection):
|
||||
log.debug("service started with configuration:")
|
||||
log.debug(str(json.dumps(DNS_CONF,indent=4,separators=(",",":"))))
|
||||
log.debug("initialize rabbit")
|
||||
self.connection = connection
|
||||
return
|
||||
|
||||
|
||||
def get_consumers(self, consumer, channel):
|
||||
consumers = []
|
||||
exchanges = DNS_CONF["exchanges"]
|
||||
exchanges = exchanges.split(",")
|
||||
for exch in exchanges:
|
||||
exchange = Exchange(exch, type="topic", durable=False)
|
||||
queue = Queue(DNS_CONF["queue_name"], exchange,
|
||||
routing_key=DNS_CONF["routing_key"],
|
||||
durable=False, auto_delete=True, no_ack=True)
|
||||
consumers.append(consumer(queue, callbacks=[self.on_message]))
|
||||
return consumers
|
||||
|
||||
def on_message(self, body, message):
|
||||
try:
|
||||
res = self._handle_message(body)
|
||||
except Exception as e:
|
||||
log.error(repr(e))
|
||||
|
||||
|
||||
def _handle_message(self, body):
|
||||
events = [DNS_CONF["event_create"],DNS_CONF["event_delete"]]
|
||||
v_key='oslo.message'
|
||||
if isinstance(body,dict):
|
||||
if v_key in body:
|
||||
log.debug("received message in v2 format")
|
||||
rdict=dict(body)
|
||||
jbody = rdict.get(v_key)
|
||||
if isinstance(jbody,str) or isinstance(jbody,unicode):
|
||||
msgbody = json.loads(jbody)
|
||||
else:
|
||||
msgbody = dict(jbody)
|
||||
else:
|
||||
log.debug("received message in v1 format")
|
||||
msgbody = dict(body)
|
||||
log.debug(str(json.dumps(msgbody,indent=4,separators=(",",":"))))
|
||||
else:
|
||||
log.warning("incorrect data type in oslo message: {}".format(type(body)))
|
||||
return False
|
||||
if ('event_type' in msgbody) and ('payload' in msgbody):
|
||||
event_type = msgbody["event_type"]
|
||||
payload = msgbody["payload"]
|
||||
else:
|
||||
log.warning("unexpected message: {}".format(msgbody))
|
||||
return False
|
||||
if event_type in events:
|
||||
if "metadata" in payload:
|
||||
if "use_dns" in payload["metadata"]:
|
||||
use_dns = (payload["metadata"]["use_dns"] == "yes")
|
||||
else:
|
||||
log.debug("no dns metadata for event {}".format(event_type))
|
||||
return False
|
||||
else:
|
||||
log.debug("No metadata for event {}".format(event_type))
|
||||
return False
|
||||
else:
|
||||
log.debug("event type ignored: {}".format(event_type))
|
||||
return False
|
||||
if use_dns:
|
||||
nova_hostname = payload["hostname"]
|
||||
nova_os_id = payload["instance_id"]
|
||||
if event_type == DNS_CONF["event_create"]:
|
||||
if not len(payload["fixed_ips"]):
|
||||
log.warning("instance with no network")
|
||||
return False
|
||||
#always use first interface (todo change this)
|
||||
nova_ip = payload["fixed_ips"][0]["address"]
|
||||
netname = payload["fixed_ips"][0]["label"]
|
||||
if netname not in DNS_CONF["networks"]:
|
||||
log.warning("dns will not be used for {}".format(netname))
|
||||
return False
|
||||
if "message" in payload:
|
||||
if payload["message"] == "Success":
|
||||
log.debug("Instance successfully created")
|
||||
else:
|
||||
log.warning("Error creating instance")
|
||||
return False
|
||||
else:
|
||||
log.warning("unknown instance state")
|
||||
lookup_addr = dns_lib.lookup_hostname(nova_hostname)
|
||||
if lookup_addr == nova_ip:
|
||||
log.warning("Instance already has address : {}".format(nova_ip))
|
||||
log.warning("Nothing to do for instance {}".format(nova_hostname))
|
||||
elif lookup_addr is not None:
|
||||
log.error("Instance has different address: {}".format(lookup_addr))
|
||||
log.error("Refused to add instance: {}".format(nova_hostname))
|
||||
return False
|
||||
dns_lib.add_hostname(nova_hostname, nova_ip)
|
||||
assigned_addr = dns_lib.lookup_hostname(nova_hostname)
|
||||
if assigned_addr is None:
|
||||
log.error("Dns server denied request for instance: {}".format(nova_hostname))
|
||||
return False
|
||||
else:
|
||||
log.info("Instance added to dns: {} {}".format(nova_hostname, assigned_addr))
|
||||
#db_lib.create_instance(nova_hostname, nova_ip, nova_os_id)
|
||||
if event_type == DNS_CONF["event_delete"]:
|
||||
lookup_addr = dns_lib.lookup_hostname(nova_hostname)
|
||||
if lookup_addr is not None:
|
||||
dns_lib.del_hostname(nova_hostname)
|
||||
#db_lib.delete_instance(nova_hostname, nova_os_id)
|
||||
else:
|
||||
log.warning("instance {} not found in dns".format(nova_hostname))
|
||||
log.warning("nothing to do")
|
||||
return False
|
||||
log.info("event of type {} processed".format(event_type))
|
||||
return True
|
||||
else:
|
||||
log.debug("Instance will not use dns for {}".format(event_type))
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
amqp_hosts = DNS_CONF["amqp_hosts"].split(",")
|
||||
BROKER_LIST = []
|
||||
amqp_user = DNS_CONF["amqp_user"]
|
||||
amqp_password = DNS_CONF["amqp_password"]
|
||||
fs = DNS_CONF["failover_strategy"]
|
||||
for amqp_host in amqp_hosts:
|
||||
broker_uri = "amqp://{}:{}@{}//".format(amqp_user,amqp_password,amqp_host)
|
||||
BROKER_LIST.append(broker_uri)
|
||||
log.info("Connecting to broker {}".format(BROKER_LIST))
|
||||
with BrokerConnection(BROKER_LIST, failover_strategy=fs ) as connection:
|
||||
try:
|
||||
DnsUpdater(connection).run()
|
||||
except Exception, e:
|
||||
log.error(repr(e))
|
||||
|
||||
#TODO use oslo for config, log, db(?), messaging(?)
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from ConfigParser import SafeConfigParser
|
||||
|
||||
LOG_FILE = "/var/log/dns-updater.log"
|
||||
CONF_PATH = "/etc/os_dns_updater/dns-updater.conf"
|
||||
|
||||
conflist = [
|
||||
"debug",
|
||||
"db_name",
|
||||
"db_user",
|
||||
"db_password",
|
||||
"exchanges",
|
||||
"queue_name",
|
||||
"routing_key",
|
||||
"event_create",
|
||||
"event_delete",
|
||||
"amqp_user",
|
||||
"amqp_password",
|
||||
"amqp_hosts",
|
||||
"failover_strategy",
|
||||
"domain",
|
||||
"networks",
|
||||
"region",
|
||||
"dns_keyfile",
|
||||
"nameserver",
|
||||
"ttl",
|
||||
"maxcounter",
|
||||
"insttime"
|
||||
]
|
||||
|
||||
def _parse_config(confname, conflist):
|
||||
config = SafeConfigParser()
|
||||
try:
|
||||
config.read(confname)
|
||||
except Exception as e:
|
||||
pass
|
||||
cf = {}
|
||||
for item in conflist:
|
||||
try:
|
||||
value = config.get("DEFAULT", item)
|
||||
except Exception as e:
|
||||
value = None
|
||||
cf[item] = value
|
||||
return cf
|
||||
|
||||
DNS_CONF = _parse_config(CONF_PATH,conflist)
|
||||
#TODO use neutron port update events
|
|
@ -0,0 +1,215 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# module to work with db
|
||||
|
||||
from sqlalchemy import MetaData, create_engine
|
||||
from sqlalchemy import Column
|
||||
from sqlalchemy import String, Integer, DateTime
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
from os_dns_updater.utils.cfg import DNS_CONF
|
||||
from os_dns_updater.utils.cfg import LOG_FILE
|
||||
|
||||
import re
|
||||
import time
|
||||
import datetime
|
||||
import dateutil.relativedelta as timedelta
|
||||
import hashlib
|
||||
import logging as log
|
||||
|
||||
log_level = log.DEBUG if (DNS_CONF["debug"] == "True") else log.INFO
|
||||
log.basicConfig(filename=LOG_FILE, level=log_level,
|
||||
format="%(levelname)s %(asctime)s %(message)s")
|
||||
|
||||
MAX_INST = int(DNS_CONF["maxcounter"]) # max number of instances of type in tenant
|
||||
if not MAX_INST:
|
||||
MAX_INST = 4095
|
||||
DBTTL = int(DNS_CONF["insttime"]) #time to store old data in db (state!=added)
|
||||
if not DBTTL:
|
||||
DBTTL = 90
|
||||
|
||||
dbcred = DNS_CONF["db_user"]+":"+DNS_CONF["db_password"]
|
||||
dbaddr = "mysql://"+dbcred+"@localhost/"+DNS_CONF["db_name"]
|
||||
dbengine = create_engine(dbaddr, pool_recycle=120)
|
||||
dbmeta = MetaData()
|
||||
Base = declarative_base()
|
||||
|
||||
class Instance(Base):
|
||||
__tablename__ = "instance"
|
||||
id = Column(Integer, primary_key=True)
|
||||
ip = Column(String(20))
|
||||
name = Column(String(90))
|
||||
dns_domain = Column(String(90))
|
||||
uuid = Column(String(40))
|
||||
state = Column(String(40))
|
||||
created_at = Column(DateTime)
|
||||
updated_at = Column(DateTime)
|
||||
deleted_at = Column(DateTime)
|
||||
|
||||
def __init__(self, name, uuid, ip):
|
||||
self.ip = ip
|
||||
self.name = name
|
||||
self.uuid = uuid
|
||||
self.created_at = datetime.datetime.now()
|
||||
|
||||
#class Event(Base):
|
||||
# __tablename__ = "event"
|
||||
# id = Column(Integer, primary_key=True)
|
||||
# def __init__(self):
|
||||
# pass
|
||||
|
||||
Base.metadata.create_all(dbengine)
|
||||
|
||||
def check_and_clear():
|
||||
Session = scoped_session(sessionmaker(bind=dbengine))
|
||||
dbsession = Session()
|
||||
log.info("db check_and_clear started with options {} {}".format(MAX_INST,DBTTL))
|
||||
oldtime = datetime.datetime.today() - timedelta.relativedelta(days=DBTTL)
|
||||
log.info("looking for unregistered records older than {}".format(oldtime))
|
||||
inst = dbsession.query(Instance).filter(
|
||||
Instance.state != 'added',
|
||||
Instance.created_at <= oldtime
|
||||
).delete()
|
||||
try:
|
||||
dbsession.commit()
|
||||
log.info("{} records removed from db".format(len(inst)))
|
||||
except Exception as e:
|
||||
log.error(repr(e))
|
||||
dbsession.rollback()
|
||||
dbsession.bind.dispose()
|
||||
Session.remove()
|
||||
|
||||
def create_instance(iname, ip, uuid):
|
||||
Session = scoped_session(sessionmaker(bind=dbengine))
|
||||
dbsession = Session()
|
||||
inst = dbsession.query(Instance).filter(
|
||||
Instance.name == iname,
|
||||
Instance.state != 'added').first()
|
||||
if not inst:
|
||||
log.warning("instance {} was not found in db".format(iname))
|
||||
new_inst = Instance(iname, uuid, ip)
|
||||
dbsession.add(new_inst)
|
||||
new_inst.state = 'added'
|
||||
new_inst.dns_domain = DNS_CONF["domain"]
|
||||
else:
|
||||
inst.state = 'added'
|
||||
inst.dns_domain = DNS_CONF["domain"]
|
||||
inst.uuid = uuid
|
||||
inst.ip = ip
|
||||
inst.updated_at = datetime.datetime.now()
|
||||
try:
|
||||
dbsession.commit()
|
||||
except Exception as e:
|
||||
log.error(repr(e))
|
||||
dbsession.rollback()
|
||||
dbsession.bind.dispose()
|
||||
Session.remove()
|
||||
|
||||
|
||||
def delete_instance(iname, uuid):
|
||||
Session = scoped_session(sessionmaker(bind=dbengine))
|
||||
dbsession = Session()
|
||||
inst = dbsession.query(Instance).filter(Instance.name == iname).first()
|
||||
if not inst:
|
||||
log.warning("instance {} was not found in db".format(iname))
|
||||
else:
|
||||
inst.state = 'deleted'
|
||||
inst.deleted_at = datetime.datetime.now()
|
||||
try:
|
||||
dbsession.commit()
|
||||
except Exception as e:
|
||||
log.error(repr(e))
|
||||
dbsession.rollback()
|
||||
dbsession.bind.dispose()
|
||||
Session.remove()
|
||||
|
||||
def generate_name(fqn, pname, dname):
|
||||
fqn = str(fqn)
|
||||
log.info("generating instance name for: {} {} {}".format(fqn,pname,dname))
|
||||
app = fqn.rsplit('.',1)[-1]
|
||||
app = app[:3]
|
||||
name = pname.split('-')[0]
|
||||
name = name[:9]
|
||||
pat = re.compile(r'^\D\d+')
|
||||
if pat.search(name) is None:
|
||||
name = 'None'
|
||||
log.warning("incorrect project name {}".format(pname))
|
||||
patt = "{}-{}-{}".format(DNS_CONF['region'],name,app)
|
||||
try:
|
||||
instnumber = num_from_patt(patt)
|
||||
except:
|
||||
instnumber = rstr(5)
|
||||
res = "{}-{}".format(patt,instnumber)
|
||||
return res
|
||||
|
||||
def num_from_patt(patt):
|
||||
patt1 = patt + '%'
|
||||
Session = scoped_session(sessionmaker(bind=dbengine))
|
||||
dbsession = Session()
|
||||
instances = dbsession.query(Instance).filter(
|
||||
Instance.name.like(patt1)).all()
|
||||
nums = []
|
||||
if not instances:
|
||||
log.debug("new instance of type {}".format(patt))
|
||||
res = 1
|
||||
else:
|
||||
res = 0
|
||||
for inst in instances:
|
||||
log.debug("found instance {}".format(inst.name))
|
||||
d = inst.name
|
||||
d = d.split('-')[3]
|
||||
d = int(d,16)
|
||||
nums.append(d)
|
||||
if not len(nums):
|
||||
res = 1
|
||||
else:
|
||||
rlist = list(set(range(1,MAX_INST)) - set(nums))
|
||||
res = rlist[0]
|
||||
log.debug("found new number: {}".format(res))
|
||||
res = str(hex(res))[2:]
|
||||
if len(res) == 1:
|
||||
res = '00'+res
|
||||
if len(res) == 2:
|
||||
res = '0'+res
|
||||
|
||||
new_inst = Instance("{}-{}".format(patt,res), '', '')
|
||||
dbsession.add(new_inst)
|
||||
new_inst.state = 'reserved'
|
||||
new_inst.dns_domain = DNS_CONF["domain"]
|
||||
try:
|
||||
dbsession.commit()
|
||||
except Exception as e:
|
||||
dbsession.rollback()
|
||||
dbsession.bind.dispose()
|
||||
Session.remove()
|
||||
return res
|
||||
|
||||
|
||||
def rstr(i):
|
||||
#random string of length i
|
||||
h = hashlib.sha1()
|
||||
h.update(str(time.time()*10000))
|
||||
rs = h.hexdigest()[:i]
|
||||
return rs
|
||||
|
||||
#unused right now:
|
||||
|
||||
def instance_exists(iname):
|
||||
Session = scoped_session(sessionmaker(bind=dbengine))
|
||||
dbsession = Session()
|
||||
inst = dbsession.query(Instance).filter(
|
||||
Instance.name==iname,
|
||||
Instance.state!='deleted',
|
||||
Instance.dns_domain==DNS_CONF['domain']).first()
|
||||
if not inst:
|
||||
log.debug("instance {} was not found in db".format(iname))
|
||||
res = False
|
||||
else:
|
||||
res = True
|
||||
dbsession.bind.dispose()
|
||||
Session.remove()
|
||||
return res
|
||||
|
||||
def update_instance():
|
||||
pass
|
|
@ -0,0 +1,78 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# module to work with dns
|
||||
|
||||
import dns.resolver
|
||||
import dns.reversename
|
||||
import dns.query
|
||||
import dns.zone
|
||||
import dns.exception
|
||||
import dns.name
|
||||
from subprocess import Popen, PIPE
|
||||
import logging as log
|
||||
|
||||
from os_dns_updater.utils.cfg import LOG_FILE
|
||||
from os_dns_updater.utils.cfg import DNS_CONF
|
||||
|
||||
log_level = log.DEBUG if (DNS_CONF["debug"] == "True") else log.INFO
|
||||
log.basicConfig(filename=LOG_FILE, level=log_level,
|
||||
format="%(levelname)s %(asctime)s %(message)s")
|
||||
|
||||
|
||||
NSUPDATE_ADD = "\
|
||||
server {nameserver}\n\
|
||||
update add {hostname} {ttl} A {hostaddr}\n\
|
||||
send"
|
||||
|
||||
NSUPDATE_DEL = "\
|
||||
server {nameserver}\n\
|
||||
update delete {hostname} A\n\
|
||||
send"
|
||||
|
||||
def dns_zone_to_text(dnsconf=DNS_CONF):
|
||||
z = dns.zone.from_xfr(dns.query.xfr(dnsconf["nameserver"],dnsconf["domain"]))
|
||||
names = z.nodes.keys()
|
||||
names.sort()
|
||||
res = []
|
||||
for n in names:
|
||||
res.append(z[n].to_text(n))
|
||||
log.info("dns zone loaded{}".format(res))
|
||||
return res
|
||||
|
||||
def lookup_hostname(name,dnsconf=DNS_CONF):
|
||||
try:
|
||||
resolv = dns.resolver.Resolver(configure=False)
|
||||
log.debug("initialize resolver")
|
||||
resolv.nameservers.append(dnsconf["nameserver"])
|
||||
resolv.domain = dns.name.from_text(dnsconf["domain"])
|
||||
resolv.search.append(dns.name.from_text(dnsconf["domain"]))
|
||||
log.debug("resolver {} {}".format(dnsconf["nameserver"],dnsconf["domain"]))
|
||||
try:
|
||||
answer = resolv.query(name)
|
||||
addr = answer.rrset[0]
|
||||
log.info("lookup host {} at {}".format(name, addr))
|
||||
except dns.exception.DNSException as e:#handle nxdomain - not an error
|
||||
log.info("instance not found: {}".format(repr(e)))
|
||||
addr = None
|
||||
except dns.exception.DNSException as e:
|
||||
log.error(repr(e))
|
||||
addr = None
|
||||
return addr
|
||||
|
||||
def dns_update(hostname, script, hostaddr=""):
|
||||
hostname = hostname + "." + DNS_CONF["domain"]
|
||||
p = Popen(["/usr/bin/nsupdate", "-k", DNS_CONF["dns_keyfile"]], stdin=PIPE)
|
||||
inp = script.format(
|
||||
nameserver=DNS_CONF["nameserver"],
|
||||
hostname=hostname, ttl=DNS_CONF["ttl"], hostaddr=hostaddr)
|
||||
p.communicate(input=inp)
|
||||
|
||||
def add_hostname(name, ip):
|
||||
log.info("adding to dns {} {}".format(name, ip))
|
||||
dns_update(name, NSUPDATE_ADD, ip)
|
||||
|
||||
def del_hostname(name):
|
||||
log.info("deleting from dns {}".format(name))
|
||||
dns_update(name, NSUPDATE_DEL)
|
||||
|
||||
#TODO always use dnspython do not use subprocess
|
|
@ -0,0 +1,4 @@
|
|||
requests>=2.0.0
|
||||
dnspython>=1.12.0
|
||||
kombu>=3.0.2
|
||||
SQLAlchemy>=1.0.12
|
|
@ -0,0 +1,14 @@
|
|||
[metadata]
|
||||
name = os_dns_updater
|
||||
description = service to register virtual machines in dns
|
||||
summary = listen to nova RabbitMQ events and update dns records
|
||||
author = Sberbank Technology
|
||||
|
||||
[files]
|
||||
packages = os_dns_updater
|
||||
|
||||
[global]
|
||||
setup-hooks = pbr.hooks.setup_hook
|
||||
|
||||
[pbr]
|
||||
warnerrors = True
|
|
@ -0,0 +1,5 @@
|
|||
import setuptools
|
||||
|
||||
# all other params will be taken from setup.cfg
|
||||
setuptools.setup(packages=setuptools.find_packages(),
|
||||
setup_requires=['pbr>=1.8'], pbr=True)
|
|
@ -0,0 +1,107 @@
|
|||
class dns_update::controller {
|
||||
$plugin_hash = hiera('fuel-plugin-dns-update')
|
||||
$amqp_hosts = hiera('amqp_hosts')
|
||||
$net1 = $plugin_hash['net1']
|
||||
$net2 = $plugin_hash['net2']
|
||||
$dns_key_hash=$plugin_hash['dns_key']
|
||||
$dns_key=$dns_key_hash['content']
|
||||
$rabbit_hash = hiera_hash('rabbit')
|
||||
$amqp_user = $rabbit_hash['user']
|
||||
$amqp_password = $rabbit_hash['password']
|
||||
$node_hash = hiera('node')
|
||||
$node_net = $node_hash['network_roles']
|
||||
$node_management = $node_net['management']
|
||||
$dnsupdate_mysql_exist = inline_template("<% if File.exist?('/tmp/dnsupdate-mysql.lock') -%>true<% end -%>")
|
||||
|
||||
if $management_vip == $service_endpoint { #in case of local keystone
|
||||
$region='RegionOne'
|
||||
}
|
||||
else { #in case of detach keystone
|
||||
$region=hiera(region)
|
||||
}
|
||||
|
||||
Exec { path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' }
|
||||
|
||||
file {'os_dns_updater':
|
||||
path => '/tmp/os_dns_updater',
|
||||
source => 'puppet:///modules/dns_update/',
|
||||
recurse => 'true',
|
||||
}
|
||||
|
||||
package {'python-pip':
|
||||
ensure => 'installed',
|
||||
}
|
||||
|
||||
package {'python-dnspython':
|
||||
ensure => 'installed',
|
||||
}
|
||||
|
||||
package {'python-pymysql':
|
||||
ensure => 'installed'
|
||||
}
|
||||
package {'pycrypto':
|
||||
ensure => 'installed',
|
||||
provider => 'pip',
|
||||
}
|
||||
file {'/etc/os_dns_updater':
|
||||
ensure => 'directory',
|
||||
}
|
||||
if $dnsupdate_mysql_exist != 'true' {
|
||||
exec {"install dns_updater":
|
||||
command => "pip install -e /tmp/os_dns_updater/",
|
||||
require => File['os_dns_updater'],
|
||||
}
|
||||
}
|
||||
file {'openstack-dns-updater.conf':
|
||||
path => '/etc/os_dns_updater/dns-updater.conf',
|
||||
source => 'puppet:///modules/dns_update/etc/dns-updater.conf',
|
||||
require => File['/etc/os_dns_updater'],
|
||||
}
|
||||
file {'example.key':
|
||||
path => '/etc/os_dns_updater/exaple.key',
|
||||
content => $dns_key,
|
||||
require => File['/etc/os_dns_updater'],
|
||||
}
|
||||
file_line { "vm networks configuration":
|
||||
path => "/etc/os_dns_updater/dns-updater.conf",
|
||||
line => "networks=$net1,$net2",
|
||||
match => "networks=.*",
|
||||
require => File['openstack-dns-updater.conf'],
|
||||
}
|
||||
file_line { "region configuration":
|
||||
path => "/etc/os_dns_updater/dns-updater.conf",
|
||||
line => "region=$region",
|
||||
match => "region=.*",
|
||||
require => File['openstack-dns-updater.conf'],
|
||||
}
|
||||
file_line { "amqp host configuration":
|
||||
path => "/etc/os_dns_updater/dns-updater.conf",
|
||||
line => "amqp_hosts=$amqp_hosts",
|
||||
match => "amqp_hosts=.*",
|
||||
require => File['openstack-dns-updater.conf'],
|
||||
}
|
||||
file_line { "amqp password configuration":
|
||||
path => "/etc/os_dns_updater/dns-updater.conf",
|
||||
line => "amqp_password=$amqp_password",
|
||||
match => "amqp_password=.*",
|
||||
require => File['openstack-dns-updater.conf'],
|
||||
}
|
||||
file_line { "amqp user configuration":
|
||||
path => "/etc/os_dns_updater/dns-updater.conf",
|
||||
line => "amqp_user=$amqp_user",
|
||||
match => "amqp_user=.*",
|
||||
require => File['openstack-dns-updater.conf'],
|
||||
}
|
||||
|
||||
file {'added module to dist-packages':
|
||||
path => '/usr/lib/python2.7/dist-packages/os_dns_updater',
|
||||
source => '/tmp/os_dns_updater/os_dns_updater',
|
||||
recurse => 'true',
|
||||
}
|
||||
File['os_dns_updater']->
|
||||
Package['python-pip']->
|
||||
Package['python-pymysql']->
|
||||
Package['pycrypto']->
|
||||
File['/etc/os_dns_updater']
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
class dns_update {}
|
|
@ -0,0 +1,25 @@
|
|||
class dns_update::mysql {
|
||||
$mysql_hash = hiera_hash('mysql')
|
||||
$mysql_pass = $mysql_hash['root_password']
|
||||
Exec { path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' }
|
||||
$dnsupdate_mysql_exist = inline_template("<% if File.exist?('/tmp/dnsupdate-mysql.lock') -%>true<% end -%>")
|
||||
|
||||
if $dnsupdate_mysql_exist != 'true' {
|
||||
exec {"create dns_updater database":
|
||||
command => "mysql --host=localhost --user=root --password=$mysql_pass -e 'create database dnsupdate;'",
|
||||
} ->
|
||||
exec {"create dns_updater user":
|
||||
command => "mysql --host=localhost --user=root --password=$mysql_pass -e 'create user \"dnsupdate\"@\"%\" identified by \"ai2o3nvsjS3cvm\";'",
|
||||
} ->
|
||||
exec {"grant privileges to dns_updater user":
|
||||
command => "mysql --host=localhost --user=root --password=$mysql_pass -e 'grant all privileges on dnsupdate.* to \"dnsupdate\"@\"%\";'",
|
||||
} ->
|
||||
exec {"create tables":
|
||||
command => "python /tmp/os_dns_updater/db_setup.py",
|
||||
} ->
|
||||
file {"/tmp/dnsupdate-mysql.lock":
|
||||
path => "/tmp/dnsupdate-mysql.lock",
|
||||
ensure => "file",
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
class dns_update::neutron {
|
||||
|
||||
Exec { path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' }
|
||||
$neutron_adv_con=hiera('neutron_advanced_configuration')
|
||||
$ha=$neutron_adv_con['dhcp_agent_ha']
|
||||
$neutron_dhcp_exist = inline_template("<% if File.exist?('/etc/init.d/neutron-dhcp-agent') -%>true<% end -%>")
|
||||
|
||||
neutron_config {
|
||||
"DEFAULT/dns_domain": value => "vm.example.net";
|
||||
}
|
||||
if $neutron_dhcp_exist == "true" {
|
||||
neutron_dhcp_agent_config {
|
||||
"DEFAULT/dhcp_domain": value => "vm.example.net";
|
||||
}
|
||||
if ($ha == true) {
|
||||
exec{"neutron-dhcp-agent crm restart":
|
||||
command => "crm resource restart clone_neutron-dhcp-agent",
|
||||
}
|
||||
Neutron_config <||> ~> Exec['neutron-dhcp-agent crm restart']
|
||||
Neutron_dhcp_agent_config <||> ~> Exec['neutron-dhcp-agent crm restart']
|
||||
}
|
||||
elsif ($ha == false) {
|
||||
exec{"neutron-dhcp-agent service restart":
|
||||
command => "service neutron-dhcp-agent restart",
|
||||
}
|
||||
Neutron_config <||> ~> Exec['neutron-dhcp-agent service restart']
|
||||
Neutron_dhcp_agent_config <||> ~> Exec['neutron-dhcp-agent service restart']
|
||||
}
|
||||
}
|
||||
Neutron_config <||> ~> service { 'neutron-server': }
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
class dns_update::nova {
|
||||
|
||||
$nova_compute_exist = inline_template("<% if File.exist?('/etc/init.d/nova-compute') -%>true<% end -%>")
|
||||
$nova_api_exist = inline_template("<% if File.exist?('/etc/init.d/nova-api') -%>true<% end -%>")
|
||||
|
||||
nova_config {
|
||||
"DEFAULT/dhcp_domain": value => "vm.example.net";
|
||||
}
|
||||
|
||||
if $nova_compute_exist == "true"
|
||||
{
|
||||
Nova_config <||> ~> service { 'nova-compute': }
|
||||
}
|
||||
|
||||
if $nova_api_exist == "true"
|
||||
{
|
||||
Nova_config <||> ~> service { 'nova-api': }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
class dns_update::pacemaker {
|
||||
Exec { path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' }
|
||||
$operations = {
|
||||
'monitor' => {'interval' => '5s', 'timeout' => '30s' },
|
||||
'start' => {'interval' => '0s', timeout => '30s' },
|
||||
'stop' => {'interval' => '0s', timeout => '30s' }
|
||||
}
|
||||
|
||||
file {'DnsUpdater':
|
||||
path => '/usr/lib/ocf/resource.d/fuel/DnsUpdater',
|
||||
source => '/tmp/os_dns_updater/ocf/DnsUpdater',
|
||||
}
|
||||
|
||||
pacemaker::service { "DnsUpdater":
|
||||
primitive_class => 'ocf',
|
||||
primitive_provider => 'fuel',
|
||||
primitive_type => 'DnsUpdater',
|
||||
operations => $operations,
|
||||
use_handler => false,
|
||||
complex_type => 'clone',
|
||||
}
|
||||
|
||||
service { "DnsUpdater":
|
||||
ensure => running,
|
||||
name => 'DnsUpdater',
|
||||
enable => true,
|
||||
provider => 'pacemaker'
|
||||
}
|
||||
|
||||
exec {"Cleanup resources":
|
||||
command => "crm resource cleanup clone_p_DnsUpdater",
|
||||
}
|
||||
|
||||
File['DnsUpdater'] ->
|
||||
Service['DnsUpdater'] ->
|
||||
Exec['Cleanup resources']
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
class dns_update::service {
|
||||
|
||||
Exec { path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' }
|
||||
|
||||
file {'init openstack-dns-updater.conf':
|
||||
path => '/etc/init/openstack-dns-updater.conf',
|
||||
source => '/tmp/os_dns_updater/openstack-dns-updater.conf',
|
||||
}
|
||||
|
||||
exec{"start openstack-dns-updater":
|
||||
command => "service openstack-dns-updater start",
|
||||
require => File['init openstack-dns-updater.conf'],
|
||||
returns => [0,1],
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
- id: fp-dns-update-controller
|
||||
role: ['primary-controller','controller']
|
||||
version: 2.0.0
|
||||
type: puppet
|
||||
parameters:
|
||||
puppet_manifest: puppet/manifests/controller.pp
|
||||
puppet_modules: puppet/modules:/etc/puppet/modules
|
||||
timeout: 360
|
||||
requires: ['post_deployment_start']
|
||||
required_for: ['post_deployment_end']
|
||||
- id: fp-dns-update-mysql
|
||||
role: ['primary-controller']
|
||||
version: 2.0.0
|
||||
type: puppet
|
||||
parameters:
|
||||
puppet_manifest: puppet/manifests/mysql.pp
|
||||
puppet_modules: puppet/modules:/etc/puppet/modules
|
||||
timeout: 360
|
||||
requires: ['post_deployment_start','fp-dns-update-controller']
|
||||
required_for: ['post_deployment_end']
|
||||
- id: fp-dns-update-service
|
||||
role: ['primary-controller','controller']
|
||||
version: 2.0.0
|
||||
type: puppet
|
||||
cross-depends:
|
||||
- name: fp-dns-update-controller
|
||||
role: 'controller'
|
||||
parameters:
|
||||
puppet_manifest: puppet/manifests/service.pp
|
||||
puppet_modules: puppet/modules:/etc/puppet/modules
|
||||
timeout: 360
|
||||
requires: ['post_deployment_start','fp-dns-update-mysql']
|
||||
required_for: ['post_deployment_end']
|
||||
- id: fp-dns-update-nova
|
||||
role: ['primary-controller','controller','compute']
|
||||
version: 2.0.0
|
||||
type: puppet
|
||||
parameters:
|
||||
puppet_manifest: puppet/manifests/nova.pp
|
||||
puppet_modules: puppet/modules:/etc/puppet/modules
|
||||
timeout: 360
|
||||
requires: ['post_deployment_start']
|
||||
required_for: ['post_deployment_end']
|
||||
- id: fp-dns-update-neutron
|
||||
role: ['primary-controller','controller','primary-network-node','network-node']
|
||||
version: 2.0.0
|
||||
type: puppet
|
||||
parameters:
|
||||
puppet_manifest: puppet/manifests/neutron.pp
|
||||
puppet_modules: puppet/modules:/etc/puppet/modules
|
||||
timeout: 360
|
||||
requires: ['post_deployment_start']
|
||||
required_for: ['post_deployment_end']
|
||||
- id: fp-dns-update-pacemaker
|
||||
role: ['primary-controller','controller']
|
||||
version: 2.0.0
|
||||
type: puppet
|
||||
parameters:
|
||||
puppet_manifest: puppet/manifests/pacemaker.pp
|
||||
puppet_modules: puppet/modules:/etc/puppet/modules
|
||||
timeout: 360
|
||||
requires: ['fp-dns-update-mysql','fp-dns-update-service']
|
||||
required_for: ['post_deployment_end']
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
attributes:
|
||||
metadata:
|
||||
group: 'other'
|
||||
net1:
|
||||
type: "text"
|
||||
weight: 10
|
||||
value: ""
|
||||
label: "Net1 Network name"
|
||||
net2:
|
||||
type: "text"
|
||||
weight: 11
|
||||
value: ""
|
||||
label: "Net2 Network name"
|
||||
dns_key:
|
||||
type: "file"
|
||||
weight: 12
|
||||
value: ""
|
||||
label: "Key for DNS server"
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# Plugin name
|
||||
name: fuel-plugin-dns-update
|
||||
title: DNS Update plugin
|
||||
# Plugin version
|
||||
version: 0.2.3
|
||||
# Description
|
||||
description: Enables custom dns servers
|
||||
# Required fuel version
|
||||
fuel_version: ['9.0']
|
||||
# Groups
|
||||
groups: []
|
||||
# Licenses
|
||||
licenses: ['Apache License, Version 2.0']
|
||||
# Homepage
|
||||
homepage: https://github.com/openstack/fuel-plugin-dns-updater
|
||||
# Authors
|
||||
authors: ['Ivan Zinoviev <zinoviev.ii@gmail.com>']
|
||||
# Change `false` to `true` if the plugin can be installed in the environment
|
||||
# after the deployment.
|
||||
is_hotpluggable: true
|
||||
|
||||
# The plugin is compatible with releases in the list
|
||||
releases:
|
||||
- os: ubuntu
|
||||
version: liberty-8.0
|
||||
mode: ['ha']
|
||||
deployment_scripts_path: deployment_scripts/
|
||||
repository_path: repositories/ubuntu
|
||||
- os: ubuntu
|
||||
version: mitaka-9.0
|
||||
mode: ['ha']
|
||||
deployment_scripts_path: deployment_scripts/
|
||||
repository_path: repositories/ubuntu
|
||||
|
||||
# Version of plugin package
|
||||
package_version: '4.0.0'
|
|
@ -0,0 +1 @@
|
|||
[]
|
Loading…
Reference in New Issue