[MediaWiki-commits] [Gerrit] operations/puppet[production]: Openstack: Added 'dnsleaks.py' script.

2017-06-09 Thread Andrew Bogott (Code Review)
Andrew Bogott has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/358124 )

Change subject: Openstack:  Added 'dnsleaks.py' script.
..


Openstack:  Added 'dnsleaks.py' script.

This hunts and (optionally) kills duplicate and leaked DNS entries.

The battle to actually /prevent/ the leaks continues...

Change-Id: Iaaf90e5e20fb35257cdfd9b10dd6f1a953f8e152
---
A modules/openstack/files/novastats/dnsleaks.py
M modules/openstack/manifests/adminscripts.pp
2 files changed, 158 insertions(+), 0 deletions(-)

Approvals:
  Andrew Bogott: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/modules/openstack/files/novastats/dnsleaks.py 
b/modules/openstack/files/novastats/dnsleaks.py
new file mode 100755
index 000..b3b0e30
--- /dev/null
+++ b/modules/openstack/files/novastats/dnsleaks.py
@@ -0,0 +1,150 @@
+#!/usr/bin/python
+#
+# Copyright 2017 Wikimedia Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+"""
+Dig through designate records, find and correct inconsistencies.
+
+- Arecs that point to multiple IPs
+- Arecs that resolve nova VMs that don't exist anymore
+- PTRs for nova VMs that don't exist anymore
+
+Be default this just reports on issues but with the --delete
+command it will attempt to clean up as well.
+
+
+Note that this is potentially racy and may misfire for instances that
+are already mid-deletion.  In that case it should be safe to re-run.
+"""
+
+import argparse
+import mwopenstackclients
+
+import requests
+import yaml
+import time
+
+clients = mwopenstackclients.clients()
+
+
+def designate_endpoint_and_token():
+services = clients.keystoneclient().services.list()
+for service in services:
+if service.type == 'dns':
+serviceid = service.id
+break
+endpoints = clients.keystoneclient().endpoints.list(serviceid)
+for endpoint in endpoints:
+if endpoint.interface == 'public':
+url = endpoint.url
+
+session = clients.session()
+token = session.get_token()
+
+return (url, token)
+
+
+def delete_recordset(endpoint, token, zoneid, recordsetid):
+headers = {'X-Auth-Token': token,
+   'X-Auth-Sudo-Tenant-ID': 'noauth-project',
+   'X-Designate-Edit-Managed-Records': 'true'}
+recordseturl = "%s/v2/zones/%s/recordsets/%s" % (endpoint, zoneid, 
recordsetid)
+print("Deleting %s with %s" % (recordsetid, recordseturl))
+req = requests.delete(recordseturl,
+  headers=headers, verify=False)
+req.raise_for_status()
+time.sleep(1)
+
+
+def edit_recordset(endpoint, token, zoneid, recordset, newrecords):
+headers = {'X-Auth-Token': token,
+   'X-Auth-Sudo-Tenant-ID': 'noauth-project',
+   'X-Designate-Edit-Managed-Records': 'true'}
+
+patch = {"records": newrecords}
+
+print("Updating %s with %s" % (recordset['id'], newrecords))
+recordseturl = "%s/v2/zones/%s/recordsets/%s" % (endpoint, zoneid, 
recordset['id'])
+
+req = requests.put(recordseturl,
+   headers=headers, verify=False,
+   json=patch)
+req.raise_for_status()
+
+
+def purge_duplicates(delete=False):
+(endpoint, token) = designate_endpoint_and_token()
+
+headers = {'X-Auth-Token': token, 'X-Auth-Sudo-Tenant-ID': 
'noauth-project'}
+req = requests.get("%s/v2/zones" % (endpoint), headers=headers, 
verify=False)
+req.raise_for_status()
+zones = yaml.safe_load(req.text)['zones']
+
+for zone in zones:
+req = requests.get("%s/v2/zones/%s/recordsets" % (endpoint, 
zone['id']),
+   headers=headers, verify=False)
+req.raise_for_status()
+recordsets = yaml.safe_load(req.text)['recordsets']
+
+# we need a fresh copy of all instances so we don't accidentally
+#  delete things that have been created since we last checked.
+instances = clients.allinstances()
+all_nova_instances = ["%s.%s.eqiad.wmflabs." % (instance.name, 
instance.tenant_id)
+  for instance in instances]
+all_nova_shortname_instances = ["%s.eqiad.wmflabs." % (instance.name)
+for instance in instances]
+
+for recordset in recordsets:
+name = recordset['name']
+recordsetid = recordset['id']
+if recordset['type'] == 'A':
+

[MediaWiki-commits] [Gerrit] operations/puppet[production]: Openstack: Added 'dnsleaks.py' script.

2017-06-09 Thread Andrew Bogott (Code Review)
Andrew Bogott has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/358124 )

Change subject: Openstack:  Added 'dnsleaks.py' script.
..

Openstack:  Added 'dnsleaks.py' script.

This hunts and (optionally) kills duplicate and leaked DNS entries.

The battle to actually /prevent/ the leaks continues...

Change-Id: Iaaf90e5e20fb35257cdfd9b10dd6f1a953f8e152
---
A modules/openstack/files/novastats/dnsleaks.py
M modules/openstack/manifests/adminscripts.pp
2 files changed, 157 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/operations/puppet 
refs/changes/24/358124/1

diff --git a/modules/openstack/files/novastats/dnsleaks.py 
b/modules/openstack/files/novastats/dnsleaks.py
new file mode 100755
index 000..c3d5b2e
--- /dev/null
+++ b/modules/openstack/files/novastats/dnsleaks.py
@@ -0,0 +1,149 @@
+#!/usr/bin/python
+#
+# Copyright 2017 Wikimedia Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+"""
+Dig through designate records, find and correct inconsistencies.
+
+- Arecs that point to multiple IPs
+- Arecs that resolve nova VMs that don't exist anymore
+- PTRs for nova VMs that don't exist anymore
+
+Be default this just reports on issues but with the --delete
+command it will attempt to clean up as well.
+
+
+Note that this is potentially racy and may misfire for instances that
+are already mid-deletion.  In that case it should be safe to re-run.
+"""
+
+import argparse
+import mwopenstackclients
+
+import requests
+import yaml
+import time
+
+clients = mwopenstackclients.clients()
+
+
+def designate_endpoint_and_token():
+services = clients.keystoneclient().services.list()
+for service in services:
+if service.type == 'dns':
+serviceid = service.id
+break
+endpoints = clients.keystoneclient().endpoints.list(serviceid)
+for endpoint in endpoints:
+if endpoint.interface == 'public':
+url = endpoint.url
+
+session = clients.session()
+token = session.get_token()
+
+return (url, token)
+
+
+def delete_recordset(endpoint, token, zoneid, recordsetid):
+headers = {'X-Auth-Token': token,
+   'X-Auth-Sudo-Tenant-ID': 'noauth-project',
+   'X-Designate-Edit-Managed-Records': 'true'}
+recordseturl = "%s/v2/zones/%s/recordsets/%s" % (endpoint, zoneid, 
recordsetid)
+print("Deleting %s with %s" % (recordsetid, recordseturl))
+req = requests.delete(recordseturl,
+  headers=headers, verify=False)
+req.raise_for_status()
+time.sleep(1)
+
+
+def edit_recordset(endpoint, token, zoneid, recordset, newrecords):
+headers = {'X-Auth-Token': token,
+   'X-Auth-Sudo-Tenant-ID': 'noauth-project',
+   'X-Designate-Edit-Managed-Records': 'true'}
+
+patch = {"records": newrecords}
+
+print("Updating %s with %s" % (recordset['id'], newrecords))
+recordseturl = "%s/v2/zones/%s/recordsets/%s" % (endpoint, zoneid, 
recordset['id'])
+
+req = requests.put(recordseturl,
+   headers=headers, verify=False,
+   json=patch)
+req.raise_for_status()
+
+
+def purge_duplicates(delete=False):
+(endpoint, token) = designate_endpoint_and_token()
+
+headers = {'X-Auth-Token': token, 'X-Auth-Sudo-Tenant-ID': 
'noauth-project'}
+req = requests.get("%s/v2/zones" % (endpoint), headers=headers, 
verify=False)
+req.raise_for_status()
+zones = yaml.safe_load(req.text)['zones']
+
+for zone in zones:
+req = requests.get("%s/v2/zones/%s/recordsets" % (endpoint, 
zone['id']),
+   headers=headers, verify=False)
+req.raise_for_status()
+recordsets = yaml.safe_load(req.text)['recordsets']
+
+# we need a fresh copy of all instances so we don't accidentally
+#  delete things that have been created since we last checked.
+instances = clients.allinstances()
+all_nova_instances = ["%s.%s.eqiad.wmflabs." % (instance.name, 
instance.tenant_id)
+  for instance in instances]
+all_nova_shortname_instances = ["%s.eqiad.wmflabs." % (instance.name)
+for instance in instances]
+
+for recordset in recordsets:
+name = recordset['name']
+recordsetid = recordset['id']
+if recordset['type'] == 'A':
+