2016년 1월 16일 토요일

Workaround for 503 error when trying to add Openstack cloud provider in miq after changing service IP's

Problem:

After changing the IP address of an Openstack Kilo installation (and editing all the service endpoints manually), trying to add an Openstack Cloud Provider in ManageIQ (miq) / Cloudforms will return a 503 Service Unavailable error.

Solution:

I will introduce the solution in two parts -- first I will explain how to change the service endpoints in Openstack Kilo from an old to new IP. Second, I will illustrate the deletion of non-existent endpoints from the Keystone database in mariadb which is ultimately causing the 503 error in miq.

Change IP for Existing Openstack Kilo Installation

1. Replace all occurrences of old_ip with new_ip in Openstack config files

My Openstack installation was done with Packstack All-in-one on a physical Fedora 21 server. All the Openstack configuration files can be found under /etc in subfolders named after component services like keystone, neutron, nova, cinder, etc. To find all the Openstack config files containing old_ip (which in my case was 192.168.40.198), I changed directories to /etc and ran the following:

[fedjun@fedrana etc]$ sudo grep -R "192.168.40.198" .

This returned voluminous output that included the following:

./rsync.conf:address = 192.168.40.198
./neutron/neutron.conf:nova_url = http://192.168.40.198:8774/v2
./neutron/neutron.conf:nova_admin_auth_url =http://192.168.40.198:5000/v2.0
./neutron/neutron.conf:auth_uri = http://192.168.40.198:5000/v2.0
./neutron/neutron.conf:identity_uri = http://192.168.40.198:35357
./neutron/neutron.conf:connection = mysql://neutron:2b9473d4f7f24714@192.168.40.1
98/neutron
./neutron/neutron.conf:rabbit_host = 192.168.40.198
./neutron/neutron.conf:rabbit_hosts = 192.168.40.198:5672
./neutron/plugins/openvswitch/ovs_neutron_plugin.ini:local_ip =192.168.40.198
./neutron/metadata_agent.ini:auth_url = http://192.168.40.198:5000/v2.0
./neutron/metadata_agent.ini:nova_metadata_ip = 192.168.40.198
./neutron/api-paste.ini:identity_uri=http://192.168.40.198:35357
./neutron/api-paste.ini:auth_uri=http://192.168.40.198:5000/v2.0
...


My old IP 192.168.40.198 appeared in the following config files (YMMV):

/etc/neutron/neutron.conf
/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini
/etc/neutron/metadata_agent.ini
/etc/neutron/api-paste.ini
/etc/swift/container-server.conf
/etc/swift/account-server.conf
/etc/swift/proxy-server.conf
/etc/libvirt/qemu/instance-00000007.xml
/etc/nova/nova.conf
/etc/ceilometer/ceilometer.conf
/etc/cinder/cinder.conf
/etc/cinder/api-paste.ini
/etc/openstack-dashboard/api-paste.ini
/etc/sysconfig/iptables
/etc/sysconfig/iptables.save
/etc/nagios/nagios_service.cfg
/etc/mongodb/mongodb.conf
/etc/glance/glance-api.conf
/etc/glance/glance-registry.conf
/etc/redis/redis.conf
/etc/httpd/conf.d/15-horizon_vhost.conf
/etc/xinetd.d/rsync.conf
/etc/target/saveconfig.json


You can replace 192.168.40.198 with 192.168.10.168 as follows:

sed -i "s/192.168.40.198/192.168.10.168/g" filename


Note that the old IP address will appear in lots of non-config files as well, such as in various Openstack logs under /var/log/. You do not need to change the IP's in these log files!

In a post by Brad Pokorny from Symantec about changing Openstack service IP's, he pipes grep to xargs and sed to replace IP's in conf files:

$ grep -rl '[old IP address]' /etc | xargs sed -i 's/[old IP address]/[new IP address]/g'

grep's -r option searches recursively (-R does the same, but unlike -r it also follows all symlinks) in the search path
grep's -l option suppresses normal output to stdout and simply prints the name of each file that matches the search pattern.

After editing the IP in all the Openstack and system config files, you are still not done; the old IP's are also saved as service endpoints within the Keystone database in mariadb.

2. Replace all occurrences of old_ip with new_ip in Keystone DB

You can find your mariadb login credentials in your answer file under $HOME (which should have been automatically generated after running the packstsack or devstack installation script). You can also find the db login credentials within /etc/keystone/keystone.conf

Log into mariadb:

[fedjun@fedrana ~]$ mysql -ukeystone_admin -p123456789abc


(make sure there isn't a space after the -p flag)

MariaDB [(none)]> use keystone
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A


MariaDB [keystone]> show tables;
+------------------------+
| Tables_in_keystone     |
+------------------------+
| access_token           |
| assignment             |
| consumer               |
| credential             |
| domain                 |
| endpoint               |
| endpoint_group         |
| federation_protocol    |
| group                  |
| id_mapping             |
| identity_provider      |
| idp_remote_ids         |
| mapping                |
| migrate_version        |
| policy                 |
| policy_association     |
| project                |
| project_endpoint       |
| project_endpoint_group |
| region                 |
| request_token          |
| revocation_event       |
| role                   |
| sensitive_config       |
| service                |
| service_provider       |
| token                  |
| trust                  |
| trust_role             |
| user                   |
| user_group_membership  |
| whitelisted_config     |
+------------------------+
32 rows in set (0.00 sec)


MariaDB [keystone]> show columns from endpoint;
+--------------------+--------------+------+-----+---------+-------+
| Field              | Type         | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+-------+
| id                 | varchar(64)  | NO   | PRI | NULL    |       |
| legacy_endpoint_id | varchar(64)  | YES  |     | NULL    |       |
| interface          | varchar(8)   | NO   |     | NULL    |       |
| service_id         | varchar(64)  | NO   | MUL | NULL    |       |
| url                | text         | NO   |     | NULL    |       |
| extra              | text         | YES  |     | NULL    |       |
| enabled            | tinyint(1)   | NO   |     | 1       |       |
| region_id          | varchar(255) | YES  | MUL | NULL    |       |
+--------------------+--------------+------+-----+---------+-------+
8 rows in set (0.00 sec)


MariaDB [keystone]> select * from endpoint
    -> ;
+----------------------------------+----------------------------------+----------
-+----------------------------------+--------------------------------------------
------+-------+---------+-----------+
| id                               | legacy_endpoint_id               | interface
 | service_id                       | url                                       
      | extra | enabled | region_id |
+----------------------------------+----------------------------------+----------
-+----------------------------------+--------------------------------------------
------+-------+---------+-----------+
| 0824196fa17c446ca255e2978b6541f0 | 27e475394a484791951b539e3a0f933e | internal
 | 3c15bfa190cf4ea4af059978a71615dd | http://192.168.40.198:8080/v1/AUTH_%(tenant_id)s | {}    |       1 | RegionOne |
| 0d871e7d98124e78a452e192636386d7 | 843a20e3a0b84895ba10425f5631580c | admin     | c58ff58e9b2249798402afffe880acd3 | http://127.0.0.1:8774/v3                         | {}    |       1 | RegionOne |
| 2235601f13404931858d15d919bc0c5f | e7149dd44359447fbbd85d0bb502694c | admin     | a2cd703896714905afc15ab7e909902d | http://192.168.40.198:9292                       | {}    |       1 | RegionOne |
| 2c5edf0ae12a47448a92259d0db26ce7 | df679e86729d48fda2d9be9f5b960171 | admin     | 8fcfa027b51c4e40aeee09244d6400b7 | http://192.168.40.198:8773/services/Admin        | {}    |       1 | RegionOne |
| 2e2cbf33223f4c79b88442e2df3f7b6b | ad6f8e52ff1f4708b64dee23098021bd | public    | ed420763fd2a4ff3b9a858557bb4b5e0 | http://192.168.40.198:8774/v2/%(tenant_id)s      | {}    |       1 | RegionOne |
| 2ebacc0d9f0a47b79a8d003a2097756c | 45a8c7dda03344e58f4921aa2bbad62e | admin     | 33436af568cf4236936f4b6645a676d4 | http://192.168.40.198:8776/v1/%(tenant_id)s      | {}    |       1 | RegionOne |

...
+----------------------------------+----------------------------------+-----------+----------------------------------+--------------------------------------------------+-------+---------+-----------+
33 rows in set (0.01 sec)


Now replace all occurrences of old_ip with new_ip:

MariaDB [keystone]> update endpoint set url = replace(url, '192.168.40.198', '192.168.10.168');
Query OK, 30 rows affected (0.04 sec)
Rows matched: 33  Changed: 30  Warnings: 0


Now you must restart the keystone service:

[fedjun@fedrana ~]$ sudo systemctl restart openstack-keystone
[fedjun@fedrana ~]$ systemctl status openstack-keystone
openstack-keystone.service - OpenStack Identity Service (code-named Keystone)
   Loaded: loaded (/usr/lib/systemd/system/openstack-keystone.service; enabled)
   Active: active (running) since Thu 2016-01-14 13:58:13 KST; 9s ago
 Main PID: 13518 (keystone-all)
   CGroup: /system.slice/openstack-keystone.service
           ├─13518 /usr/bin/python /usr/bin/keystone-all
           ├─13527 /usr/bin/python /usr/bin/keystone-all
           ├─13528 /usr/bin/python /usr/bin/keystone-all
           ├─13529 /usr/bin/python /usr/bin/keystone-all
           ├─13530 /usr/bin/python /usr/bin/keystone-all
           ├─13531 /usr/bin/python /usr/bin/keystone-all
           └─13532 /usr/bin/python /usr/bin/keystone-all


Horizon UI should now appear and work with your new IP. Note that you will also have to edit your external network (and floating IP ranges) and change the gateway in your virtual router in Neutron, as they will still be using the old IP.


Remove unused endpoints from Keystone DB to solve 503 error in miq

My packstack install of Openstack Kilo does not include Swift Object Storage, but when adding an Openstack Cloud Provider to miq, one of the logs within the Cloudforms / miq appliance indicated that no endpoint for Swift on port 8080 could be found. When I navigated to the Openstack IP on port 8080 I got the following:


By contrast, navigating by browser to any other port corresponding to an Openstack service endpoint returns JSON or XML. To enable verbose debugging in miq / Cloudforms, follow the instructions from the link below:

http://talk.manageiq.org/t/get-error-when-adding-a-new-provider/961/4

In the ManageIQ UI go to configure/configuration/, Select the appliance and go to Advanced tab. Find the following line and make the change below.

level_fog: info

to

level_fog: debug

Once this is done, wait a few minutes for the changes to take effect in miq / Cloudforms and then log into your miq appliance and navigate to /var/www/miq/vmdb/log/fog.log

Note that the password for the miq appliance is root:smartvm whereas the default user:pass for the miq web interface is admin:smartvm.

Looking through the logs I noticed that the 503 error only occurred when a request was made on port 8080:


Output within fog.log indicates that port 8080 is used for the swift service endpoint:

{"endpoints"=>
         [{"adminURL"=>"http://192.168.10.168:8080",
           "region"=>"RegionOne",
           "internalURL"=>
            "http://192.168.10.168:8080/v1/AUTH_1e6f3fe16a7b4cb7ad2feb797172a7a0",
           "id"=>"0824196fa17c446ca255e2978b6541f0",
           "publicURL"=>
            "http://192.168.10.168:8080/v1/AUTH_1e6f3fe16a7b4cb7ad2feb797172a7a0"}],
        "endpoints_links"=>[],
        "type"=>"object-store",
        "name"=>"swift"},


I confirmed that port 8080 is used by swift from the following Openstack reference:

http://docs.openstack.org/kilo/config-reference/content/firewalls-default-ports.html

The link above states that port 8080 is the HTTP alternate for OpenStack Object Storage (swift) service. The problem is that I never installed Swift in my Openstack Kilo deployment, but Keystone DB is telling miq that the endpoint for swift is at :8080. Since this endpoint doesn't exist, miq fails when trying to add the Openstack Cloud Provider. The weird thing is, before I changed my Openstack IP, I could create an Openstack Cloud Provider in miq without any problems.

The solution for the problem of non-existent endpoints is to go into the Keystone DB and delete all rows containing port 8080 (for swift) from the table endpoints:

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| keystone           |
| test               |
+--------------------+
3 rows in set (0.05 sec)

MariaDB [(none)]> use keystone
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

MariaDB [keystone]> select url from endpoint;
+--------------------------------------------------+
| url                                              |
+--------------------------------------------------+
| http://192.168.10.168:8080/v1/AUTH_%(tenant_id)s |
| http://127.0.0.1:8774/v3                         |
| http://192.168.10.168:9292                       |
| http://192.168.10.168:8773/services/Admin        |
| http://192.168.10.168:8774/v2/%(tenant_id)s      |
| http://192.168.10.168:8776/v1/%(tenant_id)s      |
| http://192.168.10.168:8776/v2/%(tenant_id)s      |
| http://192.168.10.168:9292                       |
| http://192.168.10.168:8774/v2/%(tenant_id)s      |
| http://192.168.10.168:8774/v2/%(tenant_id)s      |
| http://192.168.10.168:8776/v1/%(tenant_id)s      |
| http://192.168.10.168:8080/v1/AUTH_%(tenant_id)s |
| http://192.168.10.168:8080                       |
| http://192.168.10.168:8777                       |
| http://192.168.10.168:8080                       |
| http://192.168.10.168:35357/v2.0                 |
| http://192.168.10.168:9696                       |
| http://192.168.10.168:8776/v2/%(tenant_id)s      |
| http://192.168.10.168:8776/v2/%(tenant_id)s      |
| http://192.168.10.168:9292                       |
| http://192.168.10.168:8080                       |
| http://192.168.10.168:8773/services/Cloud        |
| http://192.168.10.168:5000/v2.0                  |
| http://192.168.10.168:8773/services/Cloud        |
| http://192.168.10.168:9696                       |
| http://192.168.10.168:8776/v1/%(tenant_id)s      |
| http://192.168.10.168:5000/v2.0                  |
| http://192.168.10.168:8777                       |
| http://127.0.0.1:8774/v3                         |
| http://192.168.10.168:8080                       |
| http://127.0.0.1:8774/v3                         |
| http://192.168.10.168:9696                       |
| http://192.168.10.168:8777                       |

+--------------------------------------------------+
33 rows in set (0.00 sec)


I can see a variety of endpoints above, but just want to get rid of all the rows containing port 8080. In mysql/mariadb it is possible to match text patterns as below:


MariaDB [keystone]> select * from endpoint where url like '%:8080%';
+----------------------------------+----------------------------------+-----------+-------
---------------------------+--------------------------------------------------+-------+---
------+-----------+
| id                               | legacy_endpoint_id               | interface | servic
e_id                       | url                                              | extra | en
abled | region_id |
+----------------------------------+----------------------------------+-----------+-------
---------------------------+--------------------------------------------------+-------+---
------+-----------+

| 0824196fa17c446ca255e2978b6541f0 | 27e475394a484791951b539e3a0f933e | internal  | 3c15bf
a190cf4ea4af059978a71615dd | http://192.168.10.168:8080/v1/AUTH_%(tenant_id)s | {}    |  
    1 | RegionOne |
| 4a925e2860da4625b16ef3efd3ef1147 | 27e475394a484791951b539e3a0f933e | public    | 3c15bf
a190cf4ea4af059978a71615dd | http://192.168.10.168:8080/v1/AUTH_%(tenant_id)s | {}    |       1 | RegionOne |
| 4cda842dd58b4cfb91ec925f135be45d | 27e475394a484791951b539e3a0f933e | admin     | 3c15bfa190cf4ea4af059978a71615dd | http://192.168.10.168:8080                       | {}    |       1 | RegionOne |
| 5af0b27d3efe4a2d84bbf0b0b79a0642 | 06ec34b3c27a4164beb4c142bb4a890b | internal  | 06da29032bb74154834ce004621e1707 | http://192.168.10.168:8080                       | {}    |       1 | RegionOne |
| ab9bf978255b496b9fc62d46b90ee211 | 06ec34b3c27a4164beb4c142bb4a890b | public    | 06da29032bb74154834ce004621e1707 | http://192.168.10.168:8080                       | {}    |       1 | RegionOne |
| e29c2509559e48dbabe4d295f2877e43 | 06ec34b3c27a4164beb4c142bb4a890b | admin     | 06da29032bb74154834ce004621e1707 | http://192.168.10.168:8080                       | {}    |       1 | RegionOne |
+----------------------------------+----------------------------------+-----------+----------------------------------+--------------------------------------------------+-------+---------+-----------+
6 rows in set (0.00 sec)


Now I can delete these matches from the table endpoint like this:

MariaDB [keystone]> delete from endpoint where url like '%:8080%';
Query OK, 6 rows affected (0.21 sec)


After restarting keystone service, adding an Openstack Cloud Provider in miq works fine!