CORD-2964 Implement new openstack models and steps

Change-Id: I32ac438e799f563b721e19ad7ebc8a033796c88e
diff --git a/xos/synchronizer/pull_steps/pull_ports.py b/xos/synchronizer/pull_steps/pull_ports.py
new file mode 100644
index 0000000..425d3eb
--- /dev/null
+++ b/xos/synchronizer/pull_steps/pull_ports.py
@@ -0,0 +1,94 @@
+# Copyright 2017-present Open Networking 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.
+
+from synchronizers.new_base.pullstep import PullStep
+from synchronizers.new_base.modelaccessor import Network, Port, OpenStackService, OpenStackServiceInstance
+
+from xosconfig import Config
+from multistructlog import create_logger
+
+log = create_logger(Config().get('logging'))
+
+class OpenStackPortPullStep(PullStep):
+    def __init__(self):
+        super(OpenStackPortPullStep, self).__init__(observed_model=Port)
+
+    def connect_openstack_admin(self, service, required_version=None):
+        import openstack
+
+        if required_version:
+            if LooseVersion(openstack.version.__version__) < LooseVersion(required_version):
+                raise Exception("Insufficient OpenStack library version",
+                                installed_version=openstack.version__version__,
+                                required_version=required_version)
+
+        conn = openstack.connect(auth_url=service.auth_url,
+                                 project_name="admin",
+                                 username=service.admin_user,
+                                 password=service.admin_password,
+                                 user_domain_name="Default",
+                                 project_domain_name="Default")
+        return conn
+
+    def pull_records(self):
+        service = OpenStackService.objects.first() # TODO(smbaker): Fix, hardcoded
+        conn = self.connect_openstack_admin(service)
+
+        ports = Port.objects.all()
+        ports_by_id = {}
+        ports_by_neutron_port = {}
+        for port in ports:
+            ports_by_id[port.id] = port
+            ports_by_neutron_port[port.port_id] = port
+
+        networks = Network.objects.all()
+        networks_by_id = {}
+        for network in networks:
+            for nd in network.controllernetworks.all():
+                networks_by_id[nd.net_id] = network
+
+        os_instances = OpenStackServiceInstance.objects.all()
+        os_instances_by_handle = {}
+        for instance in os_instances:
+            if instance.backend_handle:
+                os_instances_by_handle[instance.backend_handle] = instance
+
+        os_ports = list(conn.network.ports())
+        for os_port in os_ports:
+            if os_port.id in ports_by_neutron_port:
+                # we already have it
+                continue
+            if os_port.device_id not in os_instances_by_handle:
+                # it's not one of ours
+                log.info("No instance for port", os_port=os_port)
+                continue
+            if os_port.network_id not in networks_by_id:
+                # there's no network for it
+                log.info("No network for port", os_port=os_port)
+                continue
+            if not os_port.fixed_ips:
+                # there's no ip address
+                log.info("No ip for port", os_port=os_port)
+                continue
+            network = networks_by_id[os_port.network_id]
+            instance = os_instances_by_handle[os_port.device_id]
+            ip = os_port.fixed_ips[0]["ip_address"]
+            mac = os_port.mac_address
+            port = Port(network=network,
+                        instance=None, # TODO(smbaker): link to openstack instance
+                        ip=ip,
+                        mac=mac,
+                        port_id=os_port.id)
+            port.save()
+            log.info("Created port", port=port, os_port=os_port)