Import plugin's code
Change-Id: Ic93c9f6f322d443ec60f8e39231b71b967267e3a
This commit is contained in:
parent
1fafa482b5
commit
87d4536613
176
LICENSE
Normal file
176
LICENSE
Normal file
@ -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.
|
||||||
|
|
54
README.md
Normal file
54
README.md
Normal file
@ -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 |
|
2
deployment_scripts/puppet/manifests/controller.pp
Normal file
2
deployment_scripts/puppet/manifests/controller.pp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
include dns_update::controller
|
||||||
|
notice('MODULAR: fuel-plugin-dns-update/controller.pp')
|
2
deployment_scripts/puppet/manifests/mysql.pp
Normal file
2
deployment_scripts/puppet/manifests/mysql.pp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
include dns_update::mysql
|
||||||
|
notice('MODULAR: fuel-plugin-dns-update/mysql.pp')
|
2
deployment_scripts/puppet/manifests/neutron.pp
Normal file
2
deployment_scripts/puppet/manifests/neutron.pp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
include dns_update::neutron
|
||||||
|
notice('MODULAR: fuel-plugin-dns-update/neutron.pp')
|
2
deployment_scripts/puppet/manifests/nova.pp
Normal file
2
deployment_scripts/puppet/manifests/nova.pp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
include dns_update::nova
|
||||||
|
notice('MODULAR: fuel-plugin-dns-update/nova.pp')
|
2
deployment_scripts/puppet/manifests/pacemaker.pp
Normal file
2
deployment_scripts/puppet/manifests/pacemaker.pp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
include dns_update::pacemaker
|
||||||
|
notice('MODULAR: fuel-plugin-dns-update/pacemaker.pp')
|
2
deployment_scripts/puppet/manifests/service.pp
Normal file
2
deployment_scripts/puppet/manifests/service.pp
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
include dns_update::service
|
||||||
|
notice('MODULAR: fuel-plugin-dns-update/service.pp')
|
10
deployment_scripts/puppet/modules/dns_update/files/PKG-INFO
Normal file
10
deployment_scripts/puppet/modules/dns_update/files/PKG-INFO
Normal file
@ -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()
|
164
deployment_scripts/puppet/modules/dns_update/files/dnsupdater-failover
Executable file
164
deployment_scripts/puppet/modules/dns_update/files/dnsupdater-failover
Executable file
@ -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
|
224
deployment_scripts/puppet/modules/dns_update/files/ocf/DnsUpdater
Executable file
224
deployment_scripts/puppet/modules/dns_update/files/ocf/DnsUpdater
Executable file
@ -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
|
79
deployment_scripts/puppet/modules/dns_update/files/openstack-dns-updater
Executable file
79
deployment_scripts/puppet/modules/dns_update/files/openstack-dns-updater
Executable file
@ -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
|
14
deployment_scripts/puppet/modules/dns_update/files/setup.cfg
Normal file
14
deployment_scripts/puppet/modules/dns_update/files/setup.cfg
Normal file
@ -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],
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
64
deployment_tasks.yaml
Normal file
64
deployment_tasks.yaml
Normal file
@ -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']
|
||||||
|
|
19
environment_config.yaml
Normal file
19
environment_config.yaml
Normal file
@ -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"
|
||||||
|
|
36
metadata.yaml
Normal file
36
metadata.yaml
Normal file
@ -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
repositories/centos/.gitkeep
Normal file
0
repositories/centos/.gitkeep
Normal file
0
repositories/ubuntu/.gitkeep
Normal file
0
repositories/ubuntu/.gitkeep
Normal file
1
tasks.yaml
Normal file
1
tasks.yaml
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
Loading…
Reference in New Issue
Block a user