diff --git a/functions-common b/functions-common
index c80d3b2241..5851264773 100644
--- a/functions-common
+++ b/functions-common
@@ -815,6 +815,8 @@ function get_or_create_service {
         openstack service show $2 -f value -c id 2>/dev/null ||
         # Creates new service if not exists
         openstack service create \
+            --os-url $KEYSTONE_SERVICE_URI_V3 \
+            --os-identity-api-version=3 \
             $2 \
             --name $1 \
             --description="$3" \
@@ -823,29 +825,56 @@ function get_or_create_service {
     echo $service_id
 }
 
-# Gets or creates endpoint
-# Usage: get_or_create_endpoint <service> <region> <publicurl> <adminurl> <internalurl>
-function get_or_create_endpoint {
-    # Gets endpoint id
+# Create an endpoint with a specific interface
+# Usage: _get_or_create_endpoint_with_interface <service> <interface> <url> <region>
+function _get_or_create_endpoint_with_interface {
     local endpoint_id=$(openstack endpoint list \
-        --column "ID" \
-        --column "Region" \
-        --column "Service Name" \
-        | grep " $2 " \
-        | grep " $1 " | get_field 1)
+        --os-url $KEYSTONE_SERVICE_URI_V3 \
+        --os-identity-api-version=3 \
+        --service $1 \
+        --interface $2 \
+        --region $4 \
+        -c ID -f value)
     if [[ -z "$endpoint_id" ]]; then
         # Creates new endpoint
         endpoint_id=$(openstack endpoint create \
-            $1 \
-            --region $2 \
-            --publicurl $3 \
-            --adminurl $4 \
-            --internalurl $5 \
-            | grep " id " | get_field 2)
+            --os-url $KEYSTONE_SERVICE_URI_V3 \
+            --os-identity-api-version=3 \
+            $1 $2 $3 --region $4 -f value -c id)
     fi
+
     echo $endpoint_id
 }
 
+# Gets or creates endpoint
+# Usage: get_or_create_endpoint <service> <region> <publicurl> <adminurl> <internalurl>
+function get_or_create_endpoint {
+    # NOTE(jamielennnox): when converting to v3 endpoint creation we go from
+    # creating one endpoint with multiple urls to multiple endpoints each with
+    # a different interface.  To maintain the existing function interface we
+    # create 3 endpoints and return the id of the public one. In reality
+    # returning the public id will not make a lot of difference as there are no
+    # scenarios currently that use the returned id. Ideally this behaviour
+    # should be pushed out to the service setups and let them create the
+    # endpoints they need.
+    local public_id=$(_get_or_create_endpoint_with_interface $1 public $3 $2)
+    _get_or_create_endpoint_with_interface $1 admin $4 $2
+    _get_or_create_endpoint_with_interface $1 internal $5 $2
+
+    # return the public id to indicate success, and this is the endpoint most likely wanted
+    echo $public_id
+}
+
+# Get a URL from the identity service
+# Usage: get_endpoint_url <service> <interface>
+function get_endpoint_url {
+    echo $(openstack endpoint list \
+            --service $1 --interface $2 \
+            --os-url $KEYSTONE_SERVICE_URI_V3 \
+            --os-identity-api-version=3 \
+            -c URL -f value)
+}
+
 
 # Package Functions
 # =================
diff --git a/lib/ceilometer b/lib/ceilometer
index 163ed0b0ab..7905384623 100644
--- a/lib/ceilometer
+++ b/lib/ceilometer
@@ -130,9 +130,8 @@ function create_ceilometer_accounts {
         create_service_user "ceilometer" "admin"
 
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-            local ceilometer_service=$(get_or_create_service "ceilometer" \
-                "metering" "OpenStack Telemetry Service")
-            get_or_create_endpoint $ceilometer_service \
+            get_or_create_service "ceilometer" "metering" "OpenStack Telemetry Service"
+            get_or_create_endpoint "metering" \
                 "$REGION_NAME" \
                 "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/" \
                 "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/" \
diff --git a/lib/cinder b/lib/cinder
index ab315ac8a2..ffbbe4ac6f 100644
--- a/lib/cinder
+++ b/lib/cinder
@@ -329,16 +329,14 @@ function create_cinder_accounts {
 
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
 
-            local cinder_service=$(get_or_create_service "cinder" \
-                "volume" "Cinder Volume Service")
-            get_or_create_endpoint $cinder_service "$REGION_NAME" \
+            get_or_create_service "cinder" "volume" "Cinder Volume Service"
+            get_or_create_endpoint "volume" "$REGION_NAME" \
                 "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \
                 "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \
                 "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s"
 
-            local cinder_v2_service=$(get_or_create_service "cinderv2" \
-                "volumev2" "Cinder Volume Service V2")
-            get_or_create_endpoint $cinder_v2_service "$REGION_NAME" \
+            get_or_create_service "cinderv2" "volumev2" "Cinder Volume Service V2"
+            get_or_create_endpoint "volumev2" "$REGION_NAME" \
                 "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s" \
                 "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s" \
                 "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s"
diff --git a/lib/glance b/lib/glance
index df7adfc94b..f200dcaeea 100644
--- a/lib/glance
+++ b/lib/glance
@@ -272,9 +272,8 @@ function create_glance_accounts {
 
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
 
-            local glance_service=$(get_or_create_service "glance" \
-                "image" "Glance Image Service")
-            get_or_create_endpoint $glance_service \
+            get_or_create_service "glance" "image" "Glance Image Service"
+            get_or_create_endpoint "image" \
                 "$REGION_NAME" \
                 "$GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT" \
                 "$GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT" \
@@ -285,10 +284,9 @@ function create_glance_accounts {
     # Add glance-search service and endpoints
     if is_service_enabled g-search; then
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-            local glance_search_service=$(get_or_create_service "glance-search" \
-                "search" "EXPERIMENTAL - Glance Graffiti Search Service")
+            get_or_create_service "glance-search" "search" "EXPERIMENTAL - Glance Graffiti Search Service"
 
-            get_or_create_endpoint $glance_search_service \
+            get_or_create_endpoint "search" \
                 "$REGION_NAME" \
                 "$GLANCE_SERVICE_PROTOCOL://$GLANCE_SEARCH_HOSTPORT" \
                 "$GLANCE_SERVICE_PROTOCOL://$GLANCE_SEARCH_HOSTPORT" \
diff --git a/lib/heat b/lib/heat
index 5cb0dbf6d9..cedddd2d26 100644
--- a/lib/heat
+++ b/lib/heat
@@ -250,17 +250,15 @@ function create_heat_accounts {
 
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
 
-            local heat_service=$(get_or_create_service "heat" \
-                    "orchestration" "Heat Orchestration Service")
-            get_or_create_endpoint $heat_service \
+            get_or_create_service "heat" "orchestration" "Heat Orchestration Service"
+            get_or_create_endpoint "orchestration" \
                 "$REGION_NAME" \
                 "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s" \
                 "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s" \
                 "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s"
 
-            local heat_cfn_service=$(get_or_create_service "heat-cfn" \
-                    "cloudformation" "Heat CloudFormation Service")
-            get_or_create_endpoint $heat_cfn_service \
+            get_or_create_service "heat-cfn" "cloudformation" "Heat CloudFormation Service"
+            get_or_create_endpoint "cloudformation"  \
                 "$REGION_NAME" \
                 "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1" \
                 "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1" \
diff --git a/lib/ironic b/lib/ironic
index a0ad4df28b..1323446c1f 100644
--- a/lib/ironic
+++ b/lib/ironic
@@ -411,9 +411,8 @@ function create_ironic_accounts {
 
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
 
-            local ironic_service=$(get_or_create_service "ironic" \
-                "baremetal" "Ironic baremetal provisioning service")
-            get_or_create_endpoint $ironic_service \
+            get_or_create_service "ironic" "baremetal" "Ironic baremetal provisioning service"
+            get_or_create_endpoint "baremetal" \
                 "$REGION_NAME" \
                 "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT" \
                 "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT" \
diff --git a/lib/keystone b/lib/keystone
index c33d466c6c..428e615444 100644
--- a/lib/keystone
+++ b/lib/keystone
@@ -406,9 +406,8 @@ function create_keystone_accounts {
     # Keystone
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
 
-        KEYSTONE_SERVICE=$(get_or_create_service "keystone" \
-            "identity" "Keystone Identity Service")
-        get_or_create_endpoint $KEYSTONE_SERVICE \
+        get_or_create_service "keystone" "identity" "Keystone Identity Service"
+        get_or_create_endpoint "identity" \
             "$REGION_NAME" \
             "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION" \
             "$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT/v$IDENTITY_API_VERSION" \
diff --git a/lib/neutron-legacy b/lib/neutron-legacy
index ee98015708..5abe55c3eb 100644
--- a/lib/neutron-legacy
+++ b/lib/neutron-legacy
@@ -519,9 +519,8 @@ function create_neutron_accounts {
 
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
 
-            local neutron_service=$(get_or_create_service "neutron" \
-                "network" "Neutron Service")
-            get_or_create_endpoint $neutron_service \
+            get_or_create_service "neutron" "network" "Neutron Service"
+            get_or_create_endpoint "network" \
                 "$REGION_NAME" \
                 "$Q_PROTOCOL://$SERVICE_HOST:$Q_PORT/" \
                 "$Q_PROTOCOL://$SERVICE_HOST:$Q_PORT/" \
diff --git a/lib/nova b/lib/nova
index 5fbce5d98d..a6cd651a9c 100644
--- a/lib/nova
+++ b/lib/nova
@@ -404,24 +404,22 @@ function create_nova_accounts {
         create_service_user "nova" "admin"
 
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-
-            local nova_service=$(get_or_create_service "nova" \
-                "compute" "Nova Compute Service")
             local nova_api_url
             if [[ "$NOVA_USE_MOD_WSGI" == "False" ]]; then
                 nova_api_url="$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT"
             else
                 nova_api_url="$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST/compute"
             fi
-            get_or_create_endpoint $nova_service \
+
+            get_or_create_service "nova" "compute" "Nova Compute Service"
+            get_or_create_endpoint "compute" \
                 "$REGION_NAME" \
                 "$nova_api_url/v2/\$(tenant_id)s" \
                 "$nova_api_url/v2/\$(tenant_id)s" \
                 "$nova_api_url/v2/\$(tenant_id)s"
 
-            local nova_v21_service=$(get_or_create_service "novav21" \
-                "computev21" "Nova Compute Service V2.1")
-            get_or_create_endpoint $nova_v21_service \
+            get_or_create_service "novav21" "computev21" "Nova Compute Service V2.1"
+            get_or_create_endpoint "computev21" \
                 "$REGION_NAME" \
                 "$nova_api_url/v2.1/\$(tenant_id)s" \
                 "$nova_api_url/v2.1/\$(tenant_id)s" \
@@ -440,9 +438,8 @@ function create_nova_accounts {
         # EC2
         if [[ "$KEYSTONE_CATALOG_BACKEND" = "sql" ]]; then
 
-            local ec2_service=$(get_or_create_service "ec2" \
-                "ec2" "EC2 Compatibility Layer")
-            get_or_create_endpoint $ec2_service \
+            get_or_create_service "ec2" "ec2" "EC2 Compatibility Layer"
+            get_or_create_endpoint "ec2" \
                 "$REGION_NAME" \
                 "$EC2_SERVICE_PROTOCOL://$SERVICE_HOST:8773/" \
                 "$EC2_SERVICE_PROTOCOL://$SERVICE_HOST:8773/" \
@@ -454,8 +451,8 @@ function create_nova_accounts {
     if is_service_enabled n-obj swift3; then
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
 
-            local s3_service=$(get_or_create_service "s3" "s3" "S3")
-            get_or_create_endpoint $s3_service \
+            get_or_create_service "s3" "s3" "S3"
+            get_or_create_endpoint "s3" \
                 "$REGION_NAME" \
                 "http://$SERVICE_HOST:$S3_SERVICE_PORT" \
                 "http://$SERVICE_HOST:$S3_SERVICE_PORT" \
diff --git a/lib/swift b/lib/swift
index 8147b7a8cd..826f233414 100644
--- a/lib/swift
+++ b/lib/swift
@@ -608,9 +608,8 @@ function create_swift_accounts {
 
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
 
-        local swift_service=$(get_or_create_service "swift" \
-            "object-store" "Swift Service")
-        get_or_create_endpoint $swift_service \
+        get_or_create_service "swift" "object-store" "Swift Service"
+        get_or_create_endpoint "object-store" \
             "$REGION_NAME" \
             "$SWIFT_SERVICE_PROTOCOL://$SERVICE_HOST:8080/v1/AUTH_\$(tenant_id)s" \
             "$SWIFT_SERVICE_PROTOCOL://$SERVICE_HOST:8080" \
diff --git a/lib/tempest b/lib/tempest
index a84ade2a81..1376c87a77 100644
--- a/lib/tempest
+++ b/lib/tempest
@@ -270,11 +270,11 @@ function configure_tempest {
         fi
     fi
 
-    EC2_URL=$(openstack endpoint show -f value -c publicurl ec2 || true)
+    EC2_URL=$(get_endpoint_url ec2 public || true)
     if [[ -z $EC2_URL ]]; then
         EC2_URL="$EC2_SERVICE_PROTOCOL://$SERVICE_HOST:8773/"
     fi
-    S3_URL=$(openstack endpoint show -f value -c publicurl s3 || true)
+    S3_URL=$(get_endpoint_url s3 public || true)
     if [[ -z $S3_URL ]]; then
         S3_URL="http://$SERVICE_HOST:${S3_SERVICE_PORT:-3333}"
     fi
diff --git a/lib/zaqar b/lib/zaqar
index 891b0eab04..fdab3a26a8 100644
--- a/lib/zaqar
+++ b/lib/zaqar
@@ -210,9 +210,8 @@ function create_zaqar_accounts {
 
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
 
-        local zaqar_service=$(get_or_create_service "zaqar" \
-            "messaging" "Zaqar Service")
-        get_or_create_endpoint $zaqar_service \
+        get_or_create_service "zaqar" "messaging" "Zaqar Service"
+        get_or_create_endpoint "messaging" \
             "$REGION_NAME" \
             "$ZAQAR_SERVICE_PROTOCOL://$ZAQAR_SERVICE_HOST:$ZAQAR_SERVICE_PORT" \
             "$ZAQAR_SERVICE_PROTOCOL://$ZAQAR_SERVICE_HOST:$ZAQAR_SERVICE_PORT" \