Add openstack integration to skydive

This change will enable neutron network awareness and set the
auth-backend to to use keystone when `skydive_openstack_enabled` is
set to true. Options have been added to allow users to customize the
deployment, all of which have been documented in the default/main.yml
file.

Change-Id: Iab958c0631c7c396d218d8fb6302db03e5d9a5a6
Signed-off-by: Kevin Carter <kevin.carter@rackspace.com>
Signed-off-by: Kevin Carter <kevin@cloudnull.com>
This commit is contained in:
Kevin Carter
2019-01-18 12:12:38 -06:00
committed by Kevin Carter
parent b6bf88b7d9
commit 1fa93b1d8c
6 changed files with 246 additions and 67 deletions

View File

@@ -134,7 +134,7 @@ openstack-ansible -i /opt/openstack-ansible/inventory/dynamic_inventory.py \
More on using overlay inventories can be seen in the `overlay-inventory`
directory.
##### Configuration | Haproxy
##### Configuration | Haproxy (frontend)
The example overlay inventory contains a section for general haproxy
configuration which exposes the skydive UI internally.
@@ -170,12 +170,27 @@ This config will provide access to the web UI for both **skydive** and
* **Skydive** runs on port `8082`
* **Traefik** runs on port `8090`
##### OpenStack Integration
Skydive can be configured to work with OpenStack. For this to work a
`clouds.yaml` must be present on one of the nodes used within the deployment;
the path is typically to the clouds config is typically
`$HOME/.config/openstack/clouds.yaml`. The playbooks will use the
`clouds.yaml` file to read nessisary credentials used to create a new users
and roles to be used with `skydive` and to enable neutron probes within the
`skydive` agent.
When OpenStack integration is enabled, all authentication will be done through
keystone. User access to the skydive UI will be restricted to only users that
have the skydive role assigned to them.
All available options for the OpenStack integration can be found in the
`defaults/main.yml` file.
### Validating the skydive installation
Post-deployment, the skydive installation can be validated by simply running
the `validateSkydive.yml` playbook.
TODOs:
[] Setup cert based agent/server auth
[] Add OpenStack integration
[] Document OpenStack integration, what it adds to the admin service
- [] Setup cert based agent/server auth

View File

@@ -37,6 +37,7 @@
patterns: "*skydive*"
register: files_to_copy
delegate_to: "{{ skydive_staging_node }}"
run_once: true
become: false
- name: Install built skydive
copy:
@@ -55,6 +56,7 @@
dest: "/tmp/skydive/{{ ansible_architecture }}/{{ skydive_binary_url | basename }}"
mode: '0755'
delegate_to: "{{ skydive_staging_node }}"
run_once: true
become: false
- name: Install binary skydive
copy:
@@ -91,6 +93,7 @@
patterns: "*traefik*"
register: files_to_copy
delegate_to: "{{ traefik_staging_node }}"
run_once: true
become: false
- name: Install built traefik
copy:
@@ -109,6 +112,7 @@
dest: "/tmp/traefik/{{ ansible_architecture }}/{{ traefik_binary_url | basename }}"
mode: '0755'
delegate_to: "{{ traefik_staging_node }}"
run_once: true
become: false
- name: Install binary traefik
copy:

View File

@@ -108,32 +108,23 @@ skydive_basic_auth_file: /var/lib/skydive/skydive.secret
skydive_basic_auth_users: {}
# Skydive openstack setup
skydive_os_service_username: "{{ skydive_username }}.service"
skydive_os_service_password: "{{ skydive_password }}"
skydive_os_service_tenant_name: service
skydive_os_service_domain_name: Default
skydive_os_service_region_name: RegionOne
skydive_os_service_endpoint_type: internal
skydive_os_service_insecure: true
skydive_os_auth_url: null
skydive_auth_os_tenant_name: "{{ skydive_username }}"
skydive_auth_os_domain_name: Default
skydive_auth_os_domain_id: default
skydive_auth_os_user_role: admin
## These options are normally undefined, if undefined the value will be pulled from the local clouds.yml.
skydive_openstack_enabled: false
# skydive_os_auth_url: http://localhost:5000/v3
# skydive_os_region_name: RegionOne
# skydive_os_endpoint_type: public
os_auth_url:
os_username:
os_password:
os_tenant_name: admin
os_user_domain_name: Default
os_project_domain_name: Default
os_identity_api_version: 3
# Role of the user created that will be used for the probe
# authentication
skydive_os_cloud: default
skydive_os_cloud_file: "{{ ansible_env.HOME }}/.config/openstack/clouds.yaml"
skydive_os_domain_name: Default
skydive_os_project_name: "{{ skydive_username }}"
skydive_os_user_name: "{{ skydive_username }}"
skydive_os_user_role: admin
skydive_os_service_user: "{{ skydive_username }}.service"
skydive_os_service_user_role: admin
skydive_os_service_password: "{{ skydive_password }}"
skydive_os_service_insecure: true
# Configuration overrides can be set using a config template.

View File

@@ -68,4 +68,31 @@
tags:
- package_install
- name: Check for openstack deployment
block:
- name: Slurp clouds file
slurp:
src: "{{ skydive_os_cloud_file }}"
register: clouds_file
- name: Enable OpenStack integration
set_fact:
clouds_yaml: "{{ clouds_file['content'] | b64decode | from_yaml }}"
skydive_auth_type: mykeystone
skydive_openstack_enabled: true
run_once: true
delegate_to: "{{ item }}"
delegate_facts: true
with_items: "{{ ansible_play_hosts }}"
- include_tasks: skydive_keystone.yml
run_once: true
rescue:
- name: Notice
debug:
msg: >-
OpenStack setup is not possible, running in without it.
when:
- not (skydive_openstack_enabled | bool)
- include_tasks: skydive_setup.yml

View File

@@ -0,0 +1,131 @@
---
# Copyright 2019, Rackspace US, Inc.
#
# 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.
- name: Check credentials and clouds data
fail:
msg: >-
The following variable "{{ item.default }}" is undefined and no known value was defined
in the "{{ skydive_os_cloud_file }}" file.
when:
- hostvars[inventory_hostname][item.default] is undefined
- clouds_yaml['clouds'] is undefined
- clouds_yaml['clouds'][skydive_os_cloud] is undefined
- clouds_yaml['clouds'][skydive_os_cloud]['auth'] is undefined
- clouds_yaml['clouds'][skydive_os_cloud]['auth'][item.cfg] is undefined
with_items:
- default: "skydive_os_auth_url"
cfg: "auth_url"
- name: Create skydive venv
command: "/usr/bin/virtualenv --no-site-packages --no-setuptools /opt/skydive"
args:
creates: /opt/skydive/bin/pip
- name: Setup skydive venv
pip:
name:
- pip
- setuptools
extra_args: "-U"
virtualenv: /opt/skydive
- name: Ensure the openstacksdk is installed
pip:
name:
- openstacksdk
extra_args: "-U"
virtualenv: /opt/skydive
- name: Capture current ansible python interpreter
set_fact:
old_ansible_python_interpreter: "{{ ansible_python_interpreter | default('/usr/bin/python') }}"
- name: Set ansible python interpreter to skydive venv
set_fact:
ansible_python_interpreter: "/opt/skydive/bin/python"
- name: Add skydive project
os_project:
cloud: "{{ skydive_os_cloud }}"
state: present
name: "{{ skydive_os_project_name }}"
description: "Skydive admin project"
domain_id: "{{ skydive_os_domain_name }}"
verify: "{{ not (skydive_os_service_insecure | bool) }}"
enabled: true
register: keystone_api
until: keystone_api is success
retries: 5
delay: 10
- name: Add skydive user
os_user:
cloud: "{{ skydive_os_cloud }}"
state: present
name: "{{ skydive_os_user_name }}"
password: "{{ skydive_password }}"
update_password: on_create
domain: "{{ skydive_os_domain_name }}"
default_project: "{{ skydive_os_project_name }}"
verify: "{{ not (skydive_os_service_insecure | bool) }}"
enabled: true
register: keystone_api
until: keystone_api is success
retries: 5
delay: 10
- name: Assign skydive user role
os_user_role:
cloud: "{{ skydive_os_cloud }}"
state: present
user: "{{ skydive_os_user_name }}"
role: "{{ skydive_os_user_role }}"
project: "{{ skydive_os_project_name }}"
verify: "{{ not (skydive_os_service_insecure | bool) }}"
register: keystone_api
until: keystone_api is success
retries: 5
delay: 10
- name: Add skydive service user
os_user:
cloud: "{{ skydive_os_cloud }}"
state: present
name: "{{ skydive_os_service_user }}"
password: "{{ skydive_os_service_password }}"
domain: "{{ skydive_os_domain_name }}"
default_project: "{{ skydive_os_project_name }}"
verify: "{{ not (skydive_os_service_insecure | bool) }}"
register: keystone_api
until: keystone_api is success
retries: 5
delay: 10
- name: Assign skydive service user role
os_user_role:
cloud: "{{ skydive_os_cloud }}"
state: present
user: "{{ skydive_os_service_user }}"
role: "{{ skydive_os_service_user_role }}"
project: "{{ skydive_os_project_name }}"
verify: "{{ not (skydive_os_service_insecure | bool) }}"
register: keystone_api
until: keystone_api is success
retries: 5
delay: 10
- name: Reset ansible python
set_fact:
ansible_python_interpreter: "{{ old_ansible_python_interpreter }}"

View File

@@ -43,7 +43,7 @@ http:
# queue_size: 10000
# enable write compression
# enable_write_compression: true
enable_write_compression: true
{% if inventory_hostname in groups['skydive_analyzers'] %}
analyzer:
@@ -191,47 +191,50 @@ agent:
# Probes used to capture topology information like interfaces,
# bridges, namespaces, etc...
# Available: ovsdb, docker, neutron, opencontrail, socketinfo, lxd, lldp
{% if skydive_docker_exists | bool %}
{% set _ = skydive_probes.append('docker') %}
{% endif %}
{% if skydive_ovs_db_exists | bool %}
{% set _ = skydive_probes.append('ovsdb') %}
{% endif %}
{% if skydive_docker_exists | bool %}
{% set _ = skydive_probes.append('docker') %}
{% endif %}
{% if skydive_ovs_db_exists | bool %}
{% set _ = skydive_probes.append('ovsdb') %}
{% endif %}
{% if skydive_openstack_enabled | bool %}
{% set _ = skydive_probes.append('neutron') %}
{% endif %}
probes: {{ skydive_probes | to_json }}
netlink:
# delay in seconds between two metric updates
# metrics_update: 30
metrics_update: 30
{% if skydive_openstack_enabled | bool %}
# Define OpenStack Neutron credentials and the enpoint type
# used by the neutron probe
neutron:
# auth_url:
# username: neutron
# password: secret
# tenant_name: service
# region_name: RegionOne
# domain_name: Default
# ssl_insecure: false
# The endpoint_type value must be 'public', 'internal' or 'admin'
# endpoint_type: public
auth_url: {{ skydive_os_auth_url | default(clouds_yaml['clouds'][skydive_os_cloud]['auth']['auth_url']) }}
username: {{ skydive_os_service_user }}
password: {{ skydive_os_service_password }}
tenant_name: {{ skydive_os_project_name }}
region_name: {{ skydive_os_region_name | default(clouds_yaml['clouds'][skydive_os_cloud]['region_name']) }}
domain_name: {{ skydive_os_domain_name }}
ssl_insecure: {{ not (skydive_os_service_insecure | bool) }}
endpoint_type: {{ skydive_os_endpoint_type | default(clouds_yaml['clouds'][skydive_os_cloud]['interface']) }}
{% endif %}
lldp:
# Interfaces to listen for LLDP frames. If no list is specified,
# use all interfaces
interfaces:
{% if skydive_libvirt_exists | bool %}
{% if skydive_libvirt_exists | bool %}
libvirt:
url: qemu:///system
{% endif %}
{% endif %}
{% if skydive_runc_exists | bool %}
{% if skydive_runc_exists | bool %}
runc:
run_path:
- /var/run/runc
{% endif %}
{% endif %}
capture:
# Period in second to get capture stats from the probe. Note this
@@ -239,7 +242,6 @@ agent:
metadata:
# info: This is compute node
{% endif %}
dpdk:
# DPDK port listening flows from
@@ -253,6 +255,7 @@ dpdk:
# debug message every n seconds
# debug: 1
{% if skydive_ovs_db_exists | bool %}
sflow:
# Default listening address is 127.0.0.1
# bind_address: 127.0.0.1
@@ -262,7 +265,6 @@ sflow:
# port_min: 6345
# port_max: 6355
{% if skydive_ovs_db_exists | bool %}
ovs:
# ovsdb connection, Format supported :
# * addr:port
@@ -299,12 +301,12 @@ ovs:
address:
# Map translating bridge names into URL for remote connection
# - bridge: ssl:xxx.yyy.zzz.ttt:port
{% endif %}
{% endif %}
{% if skydive_docker_exists | bool %}
{% if skydive_docker_exists | bool %}
docker:
url: unix://{{ skydive_docker_socket }}
{% endif %}
{% endif %}
netns:
# allow to specify where the netns probe is watching network namespace
@@ -319,7 +321,9 @@ opencontrail:
# UDP dest port for MPLS traffic
# mpls_udp_port: 51234
{% endif %}
{% if inventory_hostname in groups['skydive_analyzers'] %}
storage:
# Elasticsearch backend information.
myelasticsearch:
@@ -351,6 +355,7 @@ storage:
# Memory backend
mymemory:
# driver: memory
{% endif %}
logging:
# level: INFO
@@ -383,19 +388,22 @@ auth:
# user1: secret1
# user2: secret2
{% if skydive_openstack_enabled | bool %}
mykeystone:
# Define a basic auth authentication backend
type: keystone
auth_url: {{ skydive_os_auth_url }}
auth_url: {{ skydive_os_auth_url | default(clouds_yaml['clouds'][skydive_os_cloud]['auth']['auth_url']) }}
# define the tenant and the domain that the users have to belong to
tenant_name: {{ skydive_auth_os_tenant_name }}
domain_name: {{ skydive_auth_os_domain_name }}
tenant_name: {{ skydive_os_project_name }}
domain_name: {{ skydive_os_domain_name }}
# define which role an authenticated user will have. Only used for API authentication.
# two roles are predefined, admin and guest.
role: {{ skydive_auth_os_user_role }}
role: {{ skydive_os_user_role }}
{% endif %}
{% if inventory_hostname in groups['skydive_analyzers'] %}
etcd:
# server parameters
# when 'embedded' is set to true, the analyzer will start an embedded etcd server
@@ -410,25 +418,27 @@ etcd:
# data_dir: /var/lib/skydive/etcd
# client parameters
{% if skydive_etcd_servers %}
{% if skydive_etcd_servers %}
servers: {{ skydive_etcd_servers | to_json }}
{% endif %}
{% endif %}
# name to use for clustering, by default it is set to the host id
name: {{ inventory_hostname }}
# list of peers for etcd clustering between analyzers
# each entry is composed of the peer name and the endpoints for this peer
{% set peers = {} %}
{% for node in groups['skydive_analyzers'] %}
{% if node in ansible_play_hosts %}
{% set _ansible_interface_name = hostvars[node]['skydive_network_device'] | default(hostvars[node]['ansible_default_ipv4']['interface']) | replace('-', '_') %}
{% set _ = peers.__setitem__(inventory_hostname, 'http://' ~ (hostvars[node]['skydive_bind_address'] | default(hostvars[node]["ansible_" ~ _ansible_interface_name]['ipv4']['address'])) ~ ':' ~ skydive_etcd_port) %}
{% endif %}
{% endfor %}
{% set peers = {} %}
{% for node in groups['skydive_analyzers'] %}
{% if node in ansible_play_hosts %}
{% set _ansible_interface_name = hostvars[node]['skydive_network_device'] | default(hostvars[node]['ansible_default_ipv4']['interface']) | replace('-', '_') %}
{% set _ = peers.__setitem__(inventory_hostname, 'http://' ~ (hostvars[node]['skydive_bind_address'] | default(hostvars[node]["ansible_" ~ _ansible_interface_name]['ipv4']['address'])) ~ ':' ~ skydive_etcd_port) %}
{% endif %}
{% endfor %}
peers: {{ skydive_etcd_peers | default(peers) | to_json }}
# client_timeout: 5
{% endif %}
{% if inventory_hostname in groups['skydive_agents'] %}
flow:
# Without any new packets, a flow expires after flow.expire
# seconds
@@ -455,6 +465,7 @@ flow:
# 1194: OPENVPN
udp:
# 1194: OPENVPN
{% endif %}
ui:
# Specify the extra assets folder. Javascript and CSS files present in this