diff --git a/.gitattributes b/.gitattributes
index 3ebbb9d94..d207b1802 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1 @@
-/src/bosh_openstack_cpi/vendor/package/*.gem filter=lfs diff=lfs merge=lfs -text
*.go text eol=lf
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f72ac8b9c..b32791484 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -18,28 +18,6 @@ Follow these steps to make a contribution to any of CF open source repositories:
## Development
-### Prerequisites:
-- ruby 2.x
-- bundler
-
-### Running unit tests
-
-The CPI Ruby code has unit tests that can be run as follows.
-
-```bash
-./scripts/test-unit
-```
-
-### Running ERB job templates unit tests
-
-The ERB templates rendered by the jobs of this Bosh Release have specific unit
-tests that are run along with the other unit tests as instructed above. When
-required, you can run them separately though, with this command:
-
-```bash
-./scripts/test-unit-erb
-```
-
### Running manual tests
*Note:* This is not required for opening a pull request. Having green unit tests is good enough from our perspective.
diff --git a/ci/ops_files/use-golang-cpi.yml b/ci/ops_files/use-golang-cpi.yml
deleted file mode 100644
index ffff4fbfd..000000000
--- a/ci/ops_files/use-golang-cpi.yml
+++ /dev/null
@@ -1,18 +0,0 @@
----
-# Deploy the director with the Go CPI job instead of the Ruby one (bosh-deployment/openstack/cpi.yml
-# wires openstack_cpi).
-- type: replace
- path: /instance_groups/name=bosh/jobs/name=openstack_cpi
- value:
- name: openstack_cpi_golang
- release: bosh-openstack-cpi
-
-- type: replace
- path: /instance_groups/name=bosh/properties/director/cpi_job
- value: openstack_cpi_golang
-
-- type: replace
- path: /cloud_provider/template
- value:
- name: openstack_cpi_golang
- release: bosh-openstack-cpi
diff --git a/ci/tasks/run-lifecycle.sh b/ci/tasks/run-lifecycle.sh
deleted file mode 100755
index 182152e48..000000000
--- a/ci/tasks/run-lifecycle.sh
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-source bosh-openstack-cpi-release/ci/tasks/utils.sh
-
-: "${BOSH_OPENSTACK_DOMAIN:?}"
-: "${BOSH_OPENSTACK_AUTH_URL_V3:?}"
-: "${BOSH_OPENSTACK_USERNAME_V3:?}"
-: "${BOSH_OPENSTACK_API_KEY_V3:?}"
-: "${BOSH_OPENSTACK_PROJECT:?}"
-: "${BOSH_CLI_SILENCE_SLOW_LOAD_WARNING:?}"
-: "${BOSH_OPENSTACK_CONNECT_TIMEOUT:?}"
-: "${BOSH_OPENSTACK_READ_TIMEOUT:?}"
-: "${BOSH_OPENSTACK_WRITE_TIMEOUT:?}"
-: "${BOSH_OPENSTACK_FLAVOR_WITH_NO_ROOT_DISK:?}"
-: "${BOSH_OPENSTACK_EXCLUDE_CINDER_V1:-""}"
-: "${BOSH_OPENSTACK_AUTH_URL_V2:-""}"
-: "${BOSH_OPENSTACK_USERNAME_V2:-""}"
-: "${BOSH_OPENSTACK_API_KEY_V2:-""}"
-: "${BOSH_OPENSTACK_CA_CERT:-""}"
-: "${BOSH_OPENSTACK_VOLUME_TYPE:-""}"
-
-optional_value BOSH_OPENSTACK_AVAILABILITY_ZONE
-
-metadata=terraform-cpi/metadata
-
-BOSH_OPENSTACK_MANUAL_IP=$(jq --raw-output ".manual_ip" "${metadata}")
-export BOSH_OPENSTACK_MANUAL_IP
-BOSH_OPENSTACK_ALLOWED_ADDRESS_PAIRS=$(jq --raw-output ".allowed_address_pairs" "${metadata}")
-export BOSH_OPENSTACK_ALLOWED_ADDRESS_PAIRS
-BOSH_OPENSTACK_NO_DHCP_MANUAL_IP_1=$(jq --raw-output ".no_dhcp_manual_ip_1" "${metadata}")
-export BOSH_OPENSTACK_NO_DHCP_MANUAL_IP_1
-BOSH_OPENSTACK_NO_DHCP_MANUAL_IP_2=$(jq --raw-output ".no_dhcp_manual_ip_2" "${metadata}")
-export BOSH_OPENSTACK_NO_DHCP_MANUAL_IP_2
-BOSH_OPENSTACK_NET_ID=$(jq --raw-output ".net_id" "${metadata}")
-export BOSH_OPENSTACK_NET_ID
-BOSH_OPENSTACK_NET_ID_NO_DHCP_1=$(jq --raw-output ".net_id_no_dhcp_1" "${metadata}")
-export BOSH_OPENSTACK_NET_ID_NO_DHCP_1
-BOSH_OPENSTACK_NET_ID_NO_DHCP_2=$(jq --raw-output ".net_id_no_dhcp_2" "${metadata}")
-export BOSH_OPENSTACK_NET_ID_NO_DHCP_2
-BOSH_OPENSTACK_DEFAULT_KEY_NAME=$(jq --raw-output ".default_key_name" "${metadata}")
-export BOSH_OPENSTACK_DEFAULT_KEY_NAME
-BOSH_OPENSTACK_FLOATING_IP=$(jq --raw-output ".floating_ip" "${metadata}")
-export BOSH_OPENSTACK_FLOATING_IP
-BOSH_OPENSTACK_SECURITY_GROUP_NAME=$(jq --raw-output ".security_group_name" "${metadata}")
-export BOSH_OPENSTACK_SECURITY_GROUP_NAME
-BOSH_OPENSTACK_SECURITY_GROUP_ID=$(jq --raw-output ".security_group_id" "${metadata}")
-export BOSH_OPENSTACK_SECURITY_GROUP_ID
-pool_name=$(jq --raw-output ".loadbalancer_pool_name" "${metadata}")
-if [ "${pool_name}" != "" ]; then
- export BOSH_OPENSTACK_LBAAS_POOL_NAME=${pool_name}
-fi
-
-mkdir "${PWD}/openstack-lifecycle-stemcell/stemcell"
-tar -C "${PWD}/openstack-lifecycle-stemcell/stemcell" -xzf "${PWD}/openstack-lifecycle-stemcell/stemcell.tgz"
-export BOSH_OPENSTACK_STEMCELL_PATH="${PWD}/openstack-lifecycle-stemcell/stemcell"
-
-cd bosh-openstack-cpi-release/src/bosh_openstack_cpi
-
-bundle install
-
-rspec_args=()
-if [ -n "${BOSH_OPENSTACK_EXCLUDE_CINDER_V1}" ]; then
- rspec_args=(--tag ~cinder_v1)
-fi
-
-
-if [ -n "${BOSH_OPENSTACK_AUTH_URL_V2}" ]; then
- bundle exec rspec -f d "${rspec_args[@]}" spec/integration 2>&1 | tee ../../../output/lifecycle.log
-else
- echo "Excluding Keystone V2 tests."
- bundle exec rspec -f d "${rspec_args[@]}" spec/integration --exclude-pattern spec/integration/lifecycle_v2_spec.rb 2>&1 | tee ../../../output/lifecycle.log
-fi
diff --git a/ci/tasks/run-lifecycle.yml b/ci/tasks/run-lifecycle.yml
deleted file mode 100644
index 6143bc3a3..000000000
--- a/ci/tasks/run-lifecycle.yml
+++ /dev/null
@@ -1,36 +0,0 @@
----
-platform: linux
-image_resource:
- type: registry-image
- source:
- repository: ghcr.io/cloudfoundry/bosh-openstack-cpi-release/openstack-cpi-release
- username: ((github_read_write_packages.username))
- password: ((github_read_write_packages.password))
-inputs:
- - name: bosh-openstack-cpi-release
- - name: openstack-lifecycle-stemcell
- - name: terraform-cpi
-outputs:
- - name: output
-run:
- path: bosh-openstack-cpi-release/ci/tasks/run-lifecycle.sh
-params:
- BOSH_OPENSTACK_DOMAIN: ""
- BOSH_OPENSTACK_AUTH_URL_V2: ""
- BOSH_OPENSTACK_USERNAME_V2: ""
- BOSH_OPENSTACK_API_KEY_V2: ""
- BOSH_OPENSTACK_AUTH_URL_V3: ""
- BOSH_OPENSTACK_USERNAME_V3: ""
- BOSH_OPENSTACK_API_KEY_V3: ""
- BOSH_OPENSTACK_PROJECT: ""
- BOSH_CLI_SILENCE_SLOW_LOAD_WARNING: ""
- BOSH_OPENSTACK_VOLUME_TYPE: ""
- BOSH_OPENSTACK_CONNECT_TIMEOUT: ""
- BOSH_OPENSTACK_READ_TIMEOUT: ""
- BOSH_OPENSTACK_WRITE_TIMEOUT: ""
- BOSH_OPENSTACK_DEFAULT_KEY_NAME: ""
- BOSH_OPENSTACK_CA_CERT: ""
- BOSH_OPENSTACK_FLAVOR_WITH_NO_ROOT_DISK: ""
- BOSH_OPENSTACK_EXCLUDE_CINDER_V1: ""
- BOSH_OPENSTACK_AVAILABILITY_ZONE: replace-me
-
diff --git a/ci/tasks/run-unit-specs.sh b/ci/tasks/run-unit-specs.sh
deleted file mode 100755
index 1f721f93d..000000000
--- a/ci/tasks/run-unit-specs.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-set -eu -o pipefail
-
-pushd bosh-openstack-cpi-release/src/bosh_openstack_cpi
-
- bundle install
-
- bundle exec rake rubocop
-
- bundle exec rake spec:unit
-
-popd
diff --git a/ci/tasks/run-unit-specs.yml b/ci/tasks/run-unit-specs.yml
deleted file mode 100644
index 036d94c0d..000000000
--- a/ci/tasks/run-unit-specs.yml
+++ /dev/null
@@ -1,14 +0,0 @@
----
-platform: linux
-image_resource:
- type: registry-image
- source:
- repository: ghcr.io/cloudfoundry/bosh-openstack-cpi-release/openstack-cpi-release
- username: ((github_read_write_packages.username))
- password: ((github_read_write_packages.password))
-
-inputs:
-- name: bosh-openstack-cpi-release
-
-run:
- path: bosh-openstack-cpi-release/ci/tasks/run-unit-specs.sh
diff --git a/git-hooks/pre-commit b/git-hooks/pre-commit
index 0881be682..f65bb487a 100755
--- a/git-hooks/pre-commit
+++ b/git-hooks/pre-commit
@@ -13,5 +13,3 @@ else
>&2 echo -e "${RED}Not checking whether credentials get committed. cred-alert-cli is not installed.${NC}"
fi
-unset GIT_DIR
-scripts/rubocop-staged
diff --git a/jobs/openstack_cpi/monit b/jobs/openstack_cpi/monit
deleted file mode 100644
index e69de29bb..000000000
diff --git a/jobs/openstack_cpi/spec b/jobs/openstack_cpi/spec
deleted file mode 100644
index d06a8b86f..000000000
--- a/jobs/openstack_cpi/spec
+++ /dev/null
@@ -1,134 +0,0 @@
----
-name: openstack_cpi
-templates:
- cpi.erb: bin/cpi
- cpi.json.erb: config/cpi.json
- cacert.pem.erb: config/cacert.pem
-
-packages:
-- openstack-ruby-3.4
-- bosh_openstack_cpi
-
-properties:
- openstack.auth_url:
- description: URL of the OpenStack Identity endpoint to connect to (required)
- examples:
- - description: Keystone V2 endpoint
- value: http://192.168.0.1:5000/v2.0
- - description: Keystone V3 endpoint
- value: http://192.168.0.1:5000/v3
- openstack.username:
- description: OpenStack user name (required, if application_credential_id and application_credential_secret are not provided)
- openstack.api_key:
- description: OpenStack API key (required, if application_credential_id and application_credential_secret are not provided)
- openstack.application_credential_id:
- description: OpenStack application credential id (required, if username and api_key are not provided)
- openstack.application_credential_secret:
- description: OpenStack application credential secret (required, if username and api_key are not provided)
- openstack.tenant:
- description: OpenStack tenant name (required for Keystone API V2)
- openstack.project:
- description: OpenStack project name (required for Keystone API V3. Also can be used the project_id property )
- openstack.project_id:
- description: OpenStack project id (required for Keystone API V3. Also can be used the project property)
- openstack.domain:
- description: OpenStack domain (required for Keystone API V3)
- openstack.region:
- description: OpenStack region (optional)
- example: nova
- openstack.endpoint_type:
- description: OpenStack endpoint type
- default: publicURL
- openstack.state_timeout:
- description: Timeout (in seconds) for OpenStack resources desired state
- default: 300
- openstack.boot_from_volume:
- description: Boot from volume
- default: false
- openstack.stemcell_public_visibility:
- description: Set public visibility for stemcells
- default: false
- openstack.connection_options:
- description: Hash containing additional connection parameters (optional)
- examples:
- - description: Provide all required custom CA certificates
- value:
- ca_cert: |
- -----BEGIN CERTIFICATE-----
- MII...
- -----END CERTIFICATE-----
- - description: Disable SSL verification for DevStack
- value: {ssl_verify_peer: false}
- - description: Any other excon [connection option](https://github.com/excon/excon#options), e.g. setting the read timeout
- value: {read_timeout: 360}
- openstack.default_key_name:
- description: Default OpenStack keypair to use when spinning up new VMs (required)
- example: bosh
- openstack.default_security_groups:
- description: Default OpenStack security groups to use when spinning up new VMs (required)
- example: [bosh-grp]
- openstack.default_volume_type:
- description: Default OpenStack volume type to use when creating new disks (optional)
- example: SSD
- openstack.wait_resource_poll_interval:
- description: Changes the delay (in seconds) between each status check to OpenStack when creating a resource (optional, by default 5)
- default: 5
- openstack.config_drive:
- description: Config drive device (cdrom or disk) to use as metadata service on OpenStack (optional)
- example: cdrom
- openstack.use_dhcp:
- description: Whether to use DHCP when configuring networking on VM (for both manual and dynamic)
- default: true
- openstack.ignore_server_availability_zone:
- description: When creating a disk, do not use the availability zone of the server, fall back to Openstacks default
- default: false
- openstack.human_readable_vm_names:
- description: When creating a VM, use the job name as VM name if true. Otherwise use a generated UUID as name. If this parameter is set to true, the registry.endpoint parameter has to be set.
- default: false
- openstack.use_nova_networking:
- description: 'Use Nova networking APIs instead of Neutron APIs. Note: Nova networking APIs are deprecated with the Newton release, hence this switch will likely not work in future releases.'
- default: false
- openstack.enable_auto_anti_affinity:
- description: No longer supported (see https://www.pivotaltracker.com/story/show/159522260)
- openstack.user_domain_name:
- description: Defines the specific user domain to be used by the connection to the authentication service.
- openstack.project_domain_name:
- description: Defines the specific project domain to be used by the connection to the authentication service.
-
- registry.host:
- description: Address of the Registry to connect to (required)
- registry.port:
- description: Port of the Registry for CPI and agent to connect to
- default: 25777
- registry.username:
- description: Username to access the Registry
- registry.password:
- description: Password to access the Registry
- registry.endpoint:
- description: Full URL for the registry endpoint that may include basic auth credentials
- example: http://admin:admin-password@some-ip:port
-
- ntp:
- description: List of NTP servers
- example: ["0.us.pool.ntp.org", "1.us.pool.ntp.org"]
-
- agent.mbus:
- description: Message bus endpoint for the agent to start accepting agent requests
- example: https://user:password@192.168.0.1:5000
-
- nats.user:
- description: NATS username used by agent to subscribe to agent requests
- nats.password:
- description: NATS password used by agent to subscribe to agent requests
- nats.address:
- description: NATS address used by agent to subscribe to agent requests
- nats.port:
- description: NATS port used by agent to subscribe to agent requests
- default: 4222
-
- env.http_proxy:
- description: Http proxy to connect to cloud API's
- env.https_proxy:
- description: Https proxy to connect to cloud API's
- env.no_proxy:
- description: No proxy environment variable
diff --git a/jobs/openstack_cpi/templates/cacert.pem.erb b/jobs/openstack_cpi/templates/cacert.pem.erb
deleted file mode 100644
index ab1d15b90..000000000
--- a/jobs/openstack_cpi/templates/cacert.pem.erb
+++ /dev/null
@@ -1 +0,0 @@
-<%= p('openstack.connection_options.ca_cert', '') %>
\ No newline at end of file
diff --git a/jobs/openstack_cpi/templates/cpi.erb b/jobs/openstack_cpi/templates/cpi.erb
deleted file mode 100644
index f36df957c..000000000
--- a/jobs/openstack_cpi/templates/cpi.erb
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-
-<% if_p('env.http_proxy') do |http_proxy| %>
-export HTTP_PROXY="<%= http_proxy %>"
-export http_proxy="<%= http_proxy %>"
-<% end %>
-
-<% if_p('env.https_proxy') do |https_proxy| %>
-export HTTPS_PROXY="<%= https_proxy %>"
-export https_proxy="<%= https_proxy %>"
-<% end %>
-
-<% if_p('env.no_proxy') do |no_proxy| %>
-export NO_PROXY="<%= no_proxy %>"
-export no_proxy="<%= no_proxy %>"
-<% end %>
-
-BOSH_PACKAGES_DIR=${BOSH_PACKAGES_DIR:-/var/vcap/packages}
-BOSH_JOBS_DIR=${BOSH_JOBS_DIR:-/var/vcap/jobs}
-
-source "${BOSH_PACKAGES_DIR}/openstack-ruby-3.4/bosh/runtime.env"
-export HOME=~
-
-export BUNDLE_GEMFILE=$BOSH_PACKAGES_DIR/bosh_openstack_cpi/Gemfile
-
-bundle_cmd="$BOSH_PACKAGES_DIR/openstack-ruby-3.4/bin/bundle"
-
-exec $bundle_cmd exec $BOSH_PACKAGES_DIR/bosh_openstack_cpi/bin/openstack_cpi \
- $BOSH_JOBS_DIR/openstack_cpi/config/cpi.json \
- $BOSH_JOBS_DIR/openstack_cpi/config/cacert.pem
diff --git a/jobs/openstack_cpi/templates/cpi.json.erb b/jobs/openstack_cpi/templates/cpi.json.erb
deleted file mode 100644
index 4d864a140..000000000
--- a/jobs/openstack_cpi/templates/cpi.json.erb
+++ /dev/null
@@ -1,80 +0,0 @@
-<%=
- params = {
- 'cloud' => {
- 'plugin' => 'openstack',
- 'properties' => {
- 'openstack' => {
- 'auth_url' => p('openstack.auth_url'),
- 'default_key_name' => p('openstack.default_key_name'),
- 'default_security_groups' => p('openstack.default_security_groups'),
- 'default_volume_type' => p('openstack.default_volume_type', nil),
- 'wait_resource_poll_interval' => p('openstack.wait_resource_poll_interval'),
- 'ignore_server_availability_zone' => p('openstack.ignore_server_availability_zone'),
- 'use_nova_networking' => p('openstack.use_nova_networking')
- },
- }
- }
- }
-
- openstack_params = params['cloud']['properties']['openstack']
- if_p('openstack.application_credential_id') { |value| openstack_params['application_credential_id'] = value }
- if_p('openstack.application_credential_secret') { |value| openstack_params['application_credential_secret'] = value }
- if_p('openstack.username') { |value| openstack_params['username'] = value }
- if_p('openstack.api_key') { |value| openstack_params['api_key'] = value }
- if_p('openstack.region') { |value| openstack_params['region'] = value }
- if_p('openstack.endpoint_type') { |value| openstack_params['endpoint_type'] = value }
- if_p('openstack.state_timeout') { |value| openstack_params['state_timeout'] = value }
- if_p('openstack.stemcell_public_visibility') { |value| openstack_params['stemcell_public_visibility'] = value }
- if_p('openstack.connection_options') { |value| openstack_params['connection_options'] = value }
- if_p('openstack.boot_from_volume') { |value| openstack_params['boot_from_volume'] = value }
- if_p('openstack.config_drive') { |value| openstack_params['config_drive'] = value }
- if_p('openstack.use_dhcp') { |value| openstack_params['use_dhcp'] = value }
- if_p('openstack.domain') { |value| openstack_params['domain'] = value }
- if_p('openstack.user_domain_name') { |value| openstack_params['user_domain_name'] = value }
- if_p('openstack.project_domain_name') { |value| openstack_params['project_domain_name'] = value }
- if_p('openstack.project') { |value| openstack_params['project'] = value }
- if_p('openstack.project_id') { |value| openstack_params['project_id'] = value }
- if_p('openstack.tenant') { |value| openstack_params['tenant'] = value }
- if_p('openstack.human_readable_vm_names') { |value| openstack_params['human_readable_vm_names'] = value }
-
- if_p('openstack.enable_auto_anti_affinity') do
- raise "Property 'enable_auto_anti_affinity' is no longer supported. Please remove it from your configuration."
- end
-
- if_p('ntp') do |ntp|
- params['cloud']['properties']['agent'] ||= {}
- params['cloud']['properties']['agent']['ntp'] = ntp
- end
-
- if p(['registry.username', 'registry.password', 'registry.endpoint', 'registry.host'], false)
- params['cloud']['properties']['registry'] = {
- 'user' => p('registry.username'),
- 'password' => p('registry.password'),
- 'address' => p('registry.host')
- }
-
- if_p('registry.endpoint') do |endpoint|
- params['cloud']['properties']['registry']['endpoint'] = endpoint
- end.else do
- # 'registry.host==127.0.0.1' && registry.port==6901 is a special bosh-init case. Don't raise exception in this case.
- if p('openstack.human_readable_vm_names') == true && p('registry.host') != '127.0.0.1' && p('registry.port') != 6901
- raise "Property 'human_readable_vm_names' can only be used together with 'registry.endpoint'. " +
- "Please refer to http://bosh.io/docs/openstack-registry.html."
- else
- params['cloud']['properties']['registry']['endpoint'] = "http://#{p('registry.host')}:#{p('registry.port')}"
- end
- end
- end
-
- if_p('agent.mbus') do |mbus|
- params['cloud']['properties']['agent'] ||= {}
- params['cloud']['properties']['agent']['mbus'] = mbus
- end.else do
- if p(['nats.user', 'nats.password', 'nats.address', 'agent.nats.address'], false)
- params['cloud']['properties']['agent'] ||= {}
- params['cloud']['properties']['agent']['mbus'] = "nats://#{p('nats.user')}:#{p('nats.password')}@#{p(['agent.nats.address', 'nats.address'])}:#{p('nats.port')}"
- end
- end
-
- JSON.dump(params)
-%>
diff --git a/packages/bosh_openstack_cpi/packaging b/packages/bosh_openstack_cpi/packaging
deleted file mode 100644
index affe7fc84..000000000
--- a/packages/bosh_openstack_cpi/packaging
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-
-set -e -x
-
-BOSH_PACKAGES_DIR=${BOSH_PACKAGES_DIR:-/var/vcap/packages}
-# shellcheck disable=SC1090
-source "${BOSH_PACKAGES_DIR}/openstack-ruby-3.4/bosh/compile.env"
-
-cp -a bosh_openstack_cpi/* "${BOSH_INSTALL_TARGET}"
-cd "${BOSH_INSTALL_TARGET}"
-
-export BUNDLER_VERSION="$(bundle -v | grep -o -e '[0-9.]*')"
-bundle config set --local cache_path 'vendor/package'
-
-bosh_bundle_local
-
-
diff --git a/packages/bosh_openstack_cpi/pre_packaging b/packages/bosh_openstack_cpi/pre_packaging
deleted file mode 100644
index bb37e76f4..000000000
--- a/packages/bosh_openstack_cpi/pre_packaging
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-
-export BUNDLE_APP_CONFIG=$(mktemp -d $TMPDIR/bundler_config_XXXXXX)
-bundle config set --local cache_path 'vendor/package'
-bundle config set --local without 'development test'
-
-pushd ${BUILD_DIR}/bosh_openstack_cpi
- bundle package --all-platforms --no-install
-popd
-
-rm -rf $BUNDLE_APP_CONFIG
diff --git a/packages/bosh_openstack_cpi/spec b/packages/bosh_openstack_cpi/spec
deleted file mode 100644
index 0bff2848e..000000000
--- a/packages/bosh_openstack_cpi/spec
+++ /dev/null
@@ -1,11 +0,0 @@
----
-name: bosh_openstack_cpi
-dependencies:
-- openstack-ruby-3.4
-files:
-- bosh_openstack_cpi/Gemfile
-- bosh_openstack_cpi/Gemfile.lock
-- bosh_openstack_cpi/bin/**/*
-- bosh_openstack_cpi/lib/**/*
-- bosh_openstack_cpi/.bundle/*
-
diff --git a/packages/openstack-ruby-3.1/spec.lock b/packages/openstack-ruby-3.1/spec.lock
deleted file mode 100644
index 23ba98c97..000000000
--- a/packages/openstack-ruby-3.1/spec.lock
+++ /dev/null
@@ -1,2 +0,0 @@
-name: openstack-ruby-3.1
-fingerprint: 13c5d59dc656712a7da88fd6c19aa273dc8fd9c7297156313e61d35a31e7d629
diff --git a/packages/openstack-ruby-3.4/spec.lock b/packages/openstack-ruby-3.4/spec.lock
deleted file mode 100644
index 287498983..000000000
--- a/packages/openstack-ruby-3.4/spec.lock
+++ /dev/null
@@ -1,4 +0,0 @@
-name: openstack-ruby-3.4
-fingerprint: bd92d8beb74c60f3d618e26ffda3525f2a1d2e1aacabd628a5b4b32883a05482
-dependencies:
-- openstack-rust-1-linux
diff --git a/scripts/check-ruby-version b/scripts/check-ruby-version
deleted file mode 100755
index 448a7dc43..000000000
--- a/scripts/check-ruby-version
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env bash
-
-script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-
-PROJECT_RUBY_VERSION=$(< "${script_dir}/../src/bosh_openstack_cpi/.ruby-version")
-
-if [[ ! -f /usr/local/share/chruby/chruby.sh ]]; then
- brew install chruby
-fi
-source /usr/local/share/chruby/chruby.sh
-
-chruby "${PROJECT_RUBY_VERSION}"
-if [[ $? -eq 1 ]]; then
- echo "Ruby version ${PROJECT_RUBY_VERSION} not found. Installing..."
-
- which "ruby-install" > /dev/null 2>&1
- if [[ $? -eq 1 ]]; then
- brew install ruby-install
- fi
-
- echo "Installing Ruby version ${PROJECT_RUBY_VERSION} ..."
- ruby-install "ruby" "${PROJECT_RUBY_VERSION}"
- chruby "${PROJECT_RUBY_VERSION}"
-
- echo "Ruby version ${PROJECT_RUBY_VERSION} successfully installed."
-fi
-echo "Using ruby version ${PROJECT_RUBY_VERSION}"
-
-echo "Installing bundler..."
-gem install "bundler"
diff --git a/scripts/rubocop-staged b/scripts/rubocop-staged
deleted file mode 100755
index 69328bc82..000000000
--- a/scripts/rubocop-staged
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env ruby
-# frozen_string_literal: true
-
-require 'English'
-
-Dir.chdir(File.expand_path(__dir__ + '/../src/bosh_openstack_cpi')) do
- command = 'bundle exec rubocop-git --cached'
- puts("Running '#{command}'")
- system(command)
-end
-
-exit $CHILD_STATUS.exitstatus
diff --git a/scripts/test-unit b/scripts/test-unit
deleted file mode 100755
index e1a1c131d..000000000
--- a/scripts/test-unit
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env bash
-
-script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
-
-"${script_dir}/install-git-hooks"
-
-pushd "${script_dir}/../src/bosh_openstack_cpi"
- bundle install
- bundle exec rspec "spec/unit"
-popd
diff --git a/scripts/test-unit-erb b/scripts/test-unit-erb
deleted file mode 100755
index 79d67cddb..000000000
--- a/scripts/test-unit-erb
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
-
-"${script_dir}/install-git-hooks"
-
-pushd "${script_dir}/../src/bosh_openstack_cpi"
- source "${script_dir}/check-ruby-version"
-
- bundle install
- bundle exec rspec "spec/unit/bosh_release"
-popd
diff --git a/src/bosh_openstack_cpi/.bundle/config b/src/bosh_openstack_cpi/.bundle/config
deleted file mode 100644
index cd449e577..000000000
--- a/src/bosh_openstack_cpi/.bundle/config
+++ /dev/null
@@ -1,3 +0,0 @@
----
-BUNDLE_CACHE_ALL: "false"
-BUNDLE_NO_INSTALL: "true"
diff --git a/src/bosh_openstack_cpi/.gitignore b/src/bosh_openstack_cpi/.gitignore
deleted file mode 100644
index a2d0b265f..000000000
--- a/src/bosh_openstack_cpi/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-coverage
-.bundle
-.idea
-/_*
-vendor/cache
diff --git a/src/bosh_openstack_cpi/.rspec b/src/bosh_openstack_cpi/.rspec
deleted file mode 100644
index 5f1647637..000000000
--- a/src/bosh_openstack_cpi/.rspec
+++ /dev/null
@@ -1,2 +0,0 @@
---color
---format progress
diff --git a/src/bosh_openstack_cpi/.rubocop.yml b/src/bosh_openstack_cpi/.rubocop.yml
deleted file mode 100644
index 9c569c6b4..000000000
--- a/src/bosh_openstack_cpi/.rubocop.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-AllCops:
- NewCops: enable
- DisabledByDefault: true
- SuggestExtensions: false
-
-Lint:
- Enabled: true # equivalent to `--lint`
diff --git a/src/bosh_openstack_cpi/.ruby-version b/src/bosh_openstack_cpi/.ruby-version
deleted file mode 100644
index 2f4b60750..000000000
--- a/src/bosh_openstack_cpi/.ruby-version
+++ /dev/null
@@ -1 +0,0 @@
-3.4
diff --git a/src/bosh_openstack_cpi/Gemfile b/src/bosh_openstack_cpi/Gemfile
deleted file mode 100644
index cd0cc29d1..000000000
--- a/src/bosh_openstack_cpi/Gemfile
+++ /dev/null
@@ -1,21 +0,0 @@
-source 'https://rubygems.org'
-
-gem 'bosh_common'
-gem 'bosh_cpi'
-gem 'excon'
-gem 'fog-openstack'
-gem 'httpclient'
-gem 'membrane'
-gem 'netaddr'
-
-group :development, :test do
- gem 'pry-byebug'
- gem 'rb-readline'
- gem 'rake'
- gem 'rspec'
- gem 'rspec-its'
- gem 'rubocop'
- gem 'timecop'
- gem 'webmock'
- gem 'bosh-template'
-end
diff --git a/src/bosh_openstack_cpi/Gemfile.lock b/src/bosh_openstack_cpi/Gemfile.lock
deleted file mode 100644
index 0fee74c67..000000000
--- a/src/bosh_openstack_cpi/Gemfile.lock
+++ /dev/null
@@ -1,149 +0,0 @@
-GEM
- remote: https://rubygems.org/
- specs:
- addressable (2.9.0)
- public_suffix (>= 2.0.2, < 8.0)
- ast (2.4.3)
- base64 (0.3.0)
- bigdecimal (4.1.2)
- bosh-template (2.4.0)
- semi_semantic (~> 1.2.0)
- bosh_common (2.0.0)
- logging (~> 2.2.2)
- openssl (>= 3.2.0)
- semi_semantic (~> 1.2.0)
- bosh_cpi (3.0.0)
- base64
- httpclient
- logger
- membrane
- builder (3.3.0)
- byebug (13.0.0)
- reline (>= 0.6.0)
- coderay (1.1.3)
- crack (1.0.1)
- bigdecimal
- rexml
- diff-lcs (1.6.2)
- excon (1.7.1)
- logger
- fog-core (2.6.0)
- builder
- excon (~> 1.0)
- formatador (>= 0.2, < 2.0)
- mime-types
- fog-json (1.4.0)
- fog-core
- json (~> 2.19)
- fog-openstack (1.1.5)
- fog-core (~> 2.1)
- fog-json (>= 1.0)
- formatador (1.2.3)
- reline
- hashdiff (1.2.1)
- httpclient (2.9.0)
- mutex_m
- io-console (0.9.2)
- json (2.21.2)
- language_server-protocol (3.17.0.6)
- lint_roller (1.1.0)
- little-plugger (1.1.4)
- logger (1.7.0)
- logging (2.2.2)
- little-plugger (~> 1.1)
- multi_json (~> 1.10)
- membrane (1.1.0)
- method_source (1.1.0)
- mime-types (3.7.0)
- logger
- mime-types-data (~> 3.2025, >= 3.2025.0507)
- mime-types-data (3.2026.0701)
- multi_json (1.21.1)
- mutex_m (0.3.0)
- netaddr (2.0.6)
- openssl (4.0.2)
- parallel (2.1.0)
- parser (3.3.12.0)
- ast (~> 2.4.1)
- racc
- prism (1.9.0)
- pry (0.16.0)
- coderay (~> 1.1)
- method_source (~> 1.0)
- reline (>= 0.6.0)
- pry-byebug (3.12.0)
- byebug (~> 13.0)
- pry (>= 0.13, < 0.17)
- public_suffix (7.0.5)
- racc (1.8.1)
- rainbow (3.1.1)
- rake (13.4.2)
- rb-readline (0.5.5)
- regexp_parser (2.12.0)
- reline (0.7.0)
- io-console (~> 0.5)
- rexml (3.4.4)
- rspec (3.13.2)
- rspec-core (~> 3.13.0)
- rspec-expectations (~> 3.13.0)
- rspec-mocks (~> 3.13.0)
- rspec-core (3.13.6)
- rspec-support (~> 3.13.0)
- rspec-expectations (3.13.5)
- diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.13.0)
- rspec-its (2.0.0)
- rspec-core (>= 3.13.0)
- rspec-expectations (>= 3.13.0)
- rspec-mocks (3.13.8)
- diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.13.0)
- rspec-support (3.13.7)
- rubocop (1.90.0)
- json (>= 2.3)
- language_server-protocol (~> 3.17.0.2)
- lint_roller (~> 1.1.0)
- parallel (>= 1.10)
- parser (>= 3.3.0.2)
- rainbow (>= 2.2.2, < 4.0)
- regexp_parser (>= 2.9.3, < 3.0)
- rubocop-ast (>= 1.49.0, < 2.0)
- ruby-progressbar (~> 1.7)
- unicode-display_width (>= 2.4.0, < 4.0)
- rubocop-ast (1.50.0)
- parser (>= 3.3.7.2)
- prism (~> 1.7)
- ruby-progressbar (1.13.0)
- semi_semantic (1.2.0)
- timecop (0.9.11)
- unicode-display_width (3.2.0)
- unicode-emoji (~> 4.1)
- unicode-emoji (4.2.0)
- webmock (3.26.4)
- addressable (>= 2.8.0)
- crack (>= 0.3.2)
- hashdiff (>= 0.4.0, < 2.0.0)
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- bosh-template
- bosh_common
- bosh_cpi
- excon
- fog-openstack
- httpclient
- membrane
- netaddr
- pry-byebug
- rake
- rb-readline
- rspec
- rspec-its
- rubocop
- timecop
- webmock
-
-BUNDLED WITH
- 2.6.9
diff --git a/src/bosh_openstack_cpi/Rakefile b/src/bosh_openstack_cpi/Rakefile
deleted file mode 100644
index 34b5d0074..000000000
--- a/src/bosh_openstack_cpi/Rakefile
+++ /dev/null
@@ -1,10 +0,0 @@
-require 'rspec/core/rake_task'
-require 'rubocop/rake_task'
-
-namespace :spec do
- RSpec::Core::RakeTask.new(:unit) do |t|
- t.pattern = 'spec/unit/**{,/*/**}/*_spec.rb'
- end
-end
-
-RuboCop::RakeTask.new
\ No newline at end of file
diff --git a/src/bosh_openstack_cpi/bin/bosh_openstack_console b/src/bosh_openstack_cpi/bin/bosh_openstack_console
deleted file mode 100755
index 70472bd83..000000000
--- a/src/bosh_openstack_cpi/bin/bosh_openstack_console
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env ruby
-
-# Usage example:
-# irb(main):001:0> cpi.create_vm("test",
-# "natty-server-cloudimg-amd64",
-# {"instance_type" => "m1.tiny"},
-# {"default" => {"type" => "dynamic", "cloud_properties" => {"security_groups" => ["name" => "default"]}}},
-# [],
-# {"foo" =>"bar"})
-$LOAD_PATH.unshift File.expand_path('../lib', __dir__)
-
-require 'bosh_openstack_cpi'
-require 'irb'
-require 'irb/completion'
-require 'ostruct'
-require 'optparse'
-
-config_file = nil
-
-opts_parser = OptionParser.new do |opts|
- opts.on('-c', '--config FILE') { |file| config_file = file }
-end
-
-opts_parser.parse!
-
-unless config_file
- puts opts_parser
- exit(1)
-end
-
-@config = Psych.load_file(config_file)
-
-module ConsoleHelpers
- def cpi
- @cpi ||= Bosh::OpenStackCloud::Cloud.new(@config, 2)
- end
-
- def openstack
- cpi.compute
- end
-
- def glance
- cpi.glance
- end
-
- def registry
- cpi.registry
- end
-end
-
-cloud_config = OpenStruct.new(logger: Logger.new(STDOUT))
-
-Bosh::Clouds::Config.configure(cloud_config)
-
-include ConsoleHelpers
-
-begin
- require 'ruby-debug'
- puts '=> Debugger enabled'
-rescue LoadError
- puts '=> ruby-debug not found, debugger disabled'
-end
-
-puts '=> Welcome to BOSH OpenStack CPI console'
-puts "You can use 'cpi' to access CPI methods"
-puts "You can use 'openstack' to access Fog::Compute::OpenStack methods"
-puts "You can use 'glance' to access Fog::Image::OpenStack methods"
-
-IRB.start
diff --git a/src/bosh_openstack_cpi/bin/openstack_cpi b/src/bosh_openstack_cpi/bin/openstack_cpi
deleted file mode 100755
index 21d9d4fb1..000000000
--- a/src/bosh_openstack_cpi/bin/openstack_cpi
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env ruby
-$LOAD_PATH.unshift File.expand_path('../lib', __dir__)
-
-require 'yaml'
-require 'ostruct'
-require 'bosh/cpi'
-require 'cloud/openstack'
-
-cpi_config = YAML.load_file(ARGV.shift)
-ssl_ca_file = ARGV.shift
-
-cloud_config = OpenStruct.new(logger: Bosh::Cpi::Logger.new(STDERR))
-
-Bosh::Clouds::Config.configure(cloud_config)
-
-cpi_log = StringIO.new
-Dir.mktmpdir do |dir|
- cpi_lambda = Bosh::OpenStackCloud::CpiLambda.create(cpi_config, cpi_log, ssl_ca_file, File.join(dir, 'cacert_context.pem'))
- cli = Bosh::Cpi::Cli.new(cpi_lambda, cpi_log, STDOUT)
-
- cli.run(ARGF.read)
-end
diff --git a/src/bosh_openstack_cpi/docs/bosh_cpi.md b/src/bosh_openstack_cpi/docs/bosh_cpi.md
deleted file mode 100644
index 1a178b5fc..000000000
--- a/src/bosh_openstack_cpi/docs/bosh_cpi.md
+++ /dev/null
@@ -1,104 +0,0 @@
-# OpenStack CPI Implementation #
-OpenStack CPI is an implementation of BOSH CPI. It allows BOSH to interface with various services in OpenStack like glance, controller and registry.
-
-The OpenStack CPI is configured in the BOSH deployment manifest. Read the [OpenStack CPI Config docs](bosh_openstack_cpi/cpi_config.md) for more details.
-
-In the sections below we outline the implementation details for each of the method in CPI interface.
-
-## Initialize ##
-
-Implementation of `def initialize(options)` method.
-
-1. Validate the `options` passed to this method
-2. Instantiate `Registry_Client`.
-3. Extract required properties from `options` object.
-4. Instantiate `Bosh::OpenStackCloud::Openstack` with the provided openstack options. It is a `Fog` wrapper and manages all connections to OpenStack services. Connections are created lazy. First access to a service triggers the connection setup. `Bosh::OpenStackCloud::Openstack` manges the connections to the follwoing services:
- + Nova Service
- 1. Instantiate `Fog::Compute` instance
- 2. `Fog::Compute::OpenStack` instance is created
- 3. A New `Fog::Connection` object connects with the remote Nova Compute Service
- + Glance service
- 1. Instantiate `Fog::Image` instance
- 2. `Fog::Image::OpenStack` instance is created
- 3. A New `Fog::Connection` object connects with the remote Glance Service
- + Cinder service
- 1. Instantiate `Fog::Volume` instance
- 2. `Fog::Volume::OpenStack` instance is created
- 3. A New `Fog::Connection` object connects with the remote Cinder Service
- + Neutron service
- 1. Instantiate `Fog::Network` instance
- 2. `Fog::OpenStack::Network` instance is created
- 3. A New `Fog::Connection` object connects with the remote Neutron Service
-
-
-
-
-## Create Stemcell ##
-
-Implementation of method `create_stemcell(image_path, cloud_properties)`
-Steps outlined below are the flow control implemented to extract and upload kernel image, ramdisk and stem cell image.
-
-1. Extract parameters from the `cloud_properties`. Check if `kernel_file` parameter exists, instantiate `kernel_image` object
-2. Construct `kernel_params`
-3. Upload `kernel_image` to glance service by calling the method `upload_image(kernel_params)`
-4. If params contain `ramdisk_file`
-5. Instantiate ramdisk_image object and populate `ramdisk_parama`
-6. Upload the `ramdisk_image` to glance service by calling `upload(ramdisk_params)`
-7. Populate `image_params` for the stem cell to be uploaded to glance service
-8. Call the method `upload_image(image_params)`
-
-Figure below shows the flow control for the method `create_stemcell(image_path, cloud_properties)`
-
-
-
-## Delete Stemcell ##
-
-
-
-## Create VM ##
-
-Implementation of
-`def create_vm(agent_id, stemcell_id, resource_pool, network_spec = nil, disk_locality = nil, environment = nil)` method.
-
-1. Retrieve `security_groups` available on OpenStack and validate them against configured.
-2. If option `config_drive` and multiple manual networks are set, create network ports for manual networks.
-3. Find stemcell image for passed `stemcell_id`.
-4. Find OpenStack flavor for configured `instance_type`.
-5. Create VM.
-6. If `loadbalancer_pools` are specified, add VM as member to each pool and tag VM with pool and membership ID.
-7. If option `human_readable_vm_names` is provided, tag the created VM with it's BOSH registry key.
-8. Update BOSH registry settings for the new VM.
-
-
-
-## Delete VM ##
-
-Implementation of `delete_vm(server_id)`. This method deletes the VM created in Nova Compute.
-
-1. Get the `server` of the VM to be deleted
-2. If Neutron exists, get network port ids for server.
-3. Call `server.destroy`. This will send `delete_server` request to Nova Compute.
-4. If Neutron exists, delete network ports
-5. If VM was tagged with LBaaS pools, remove VM membership from load balancer pools
-6. Delete the settings from Registry by calling `delete_settings` method.
-
-Figure below shows the flow control for `delete_vm` method
-
-
-
-## Create Disk ##
-
-1. Check if size passed is integer, is greater than 1024 and less than 1024*1000, else throw an error
-2. Create `volume_params`
-3. Call `create()volume_params)` on `Fog::Compute` service
- 1. `create_volume` request on `Fog::Volume::OpenStack`
- 2. Opens a `Fog::Connection` request to access the remote service and create a volume.
-
-Figure below shows the flow control of `create_disk` method
-
-
-
-## Delete Disk ##
-
-This method deletes the volume created in OpenStack Nova Volume
-
diff --git a/src/bosh_openstack_cpi/docs/cpi_config.md b/src/bosh_openstack_cpi/docs/cpi_config.md
deleted file mode 100644
index 810e2a76f..000000000
--- a/src/bosh_openstack_cpi/docs/cpi_config.md
+++ /dev/null
@@ -1,113 +0,0 @@
-#OpenStack CPI Configuration
-
-CPI configuration is specified in both the microBOSH deployment manifest and the BOSH release deployment manifest.
-
-microBOSH deployment manifest example:
-
-```
----
-name: my-micro
-
-...
-
-cloud:
- plugin: openstack
- properties:
- openstack:
- auth_url: http://0.0.0.0:5000/v2.0
- username: openstack-user
- api_key: openstack-password
- tenant: dev
- region: west-coast
- endpoint_type: publicURL
- state_timeout: 300
- boot_from_volume: false
- stemcell_public_visibility: false
- connection_options: {}
- default_key_name:
- default_security_groups:
- wait_resource_poll_interval: 5
- config_drive: disk
- registry:
- endpoint: http://0.0.0.0:25777
- user: registry-user
- password: registry-password
- agent: {} # optional agent config
-
-```
-
-BOSH deployment manifest example:
-
-```
----
-name: my-bosh
-
-...
-
-properties:
- openstack:
- auth_url: http://0.0.0.0:5000/v3.0
- username: openstack-user
- api_key: openstack-password
- tenant: dev
- domain: domain1
- region: west-coast
- endpoint_type: publicURL
- state_timeout: 300
- boot_from_volume: false
- stemcell_public_visibility: false
- connection_options: {}
- default_key_name:
- default_security_groups:
- wait_resource_poll_interval: 5
- config_drive: disk
- registry:
- address: 0.0.0.0
- http:
- port: 25777
- user: registry-user
- password: registry-password
- agent: {} # optional agent config
-
-```
-
-## OpenStack Properties
-
-* `auth_url` - URL of the OpenStack Identity endpoint to connect to
-* `username` - OpenStack user name
-* `api_key` - OpenStack API key
-* `tenant` - OpenStack tenant name
-* `domain` - (optional) OpenStack domain (defaults to 'Default')
-* `region` - (optional) OpenStack region
-* `endpoint_type` - (optional) OpenStack endpoint type (defaults to 'publicURL')
-* `state_timeout` - (optional) Timeout (in seconds) for OpenStack resources desired state (defaults to 300)
-* `boot_from_volume` - (optional) Boot from volume
-* `stemcell_public_visibility` - (optional) Set public visibility for stemcells (defaults to false)
-* `connection_options` - Hash containing optional connection parameters to the OpenStack API
-* `default_key_name` - Default OpenStack keypair to use when spinning up new vms
-* `default_security_groups` - Default OpenStack security groups to use when spinning up new vms
-* `wait_resource_poll_interval` - (optional) Changes the delay (in seconds) between each status check to OpenStack when creating a resource
-* `config_drive` - (optional) Config drive device (cdrom or disk) to use as metadata service on OpenStack
-
-
-## Registry Properties
-
-Registry properties are directly set in the microBOSH deployment manifest, but full BOSH has some slight indirection.
-
-microBOSH properties:
-
-* `endpoint` - URI (including scheme, host and port) of the Registry service
-* `user` - User to access the Registry
-* `password` - Password to access the Registry
-
-BOSH properties:
-
-* `address` - Address of the Registry service
-* `http.port` - Port of the Registry to connect to
-* `http.user` - User to access the Registry
-* `http.password` - Password to access the Registry
-
-## Agent Properties
-
-Agent properties is a hash passed directly to the agent.
-
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_create_disk.graffle b/src/bosh_openstack_cpi/docs/images/openstack_cpi_create_disk.graffle
deleted file mode 100644
index 12e4f79e0..000000000
--- a/src/bosh_openstack_cpi/docs/images/openstack_cpi_create_disk.graffle
+++ /dev/null
@@ -1,1969 +0,0 @@
-
-
-
-
- ActiveLayerIndex
- 0
- ApplicationVersion
-
- com.omnigroup.OmniGrafflePro
- 139.16.0.171715
-
- AutoAdjust
-
- BackgroundGraphic
-
- Bounds
- {{0, 0}, {576, 733}}
- Class
- SolidGraphic
- ID
- 2
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
-
- BaseZoom
- 0
- CanvasOrigin
- {0, 0}
- ColumnAlign
- 1
- ColumnSpacing
- 36
- CreationDate
- 2012-12-20 10:10:00 +0000
- Creator
- rajdeepd
- DisplayScale
- 1 0/72 in = 1.0000 in
- GraphDocumentVersion
- 8
- GraphicsList
-
-
- Bounds
- {{378, 403.7253532409668}, {69, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 360
- Shape
- Rectangle
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.747526
- g
- 0.747526
- r
- 0.747526
-
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs28 \cf0 Fog Gem}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Bounds
- {{304, 124.54520702362061}, {143, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 357
- Shape
- Rectangle
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.747526
- g
- 0.747526
- r
- 0.747526
-
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs28 \cf0 Bosh OpenStack CPI}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 352
- Info
- 8
-
- ID
- 353
- Points
-
- {300.01228332519565, 608.98254741887342}
- {233.03073883056641, 608.9825803205315}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 315
-
-
-
- Bounds
- {{63, 590.5560302734375}, {170.03073883056641, 36.85308837890625}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 352
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.973627
- g
- 0.992442
- r
- 0.834
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.80124
- g
- 0.886111
- r
- 0.566755
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.850363
- g
- 0.883832
- r
- 0.488493
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Nova Volume}
-
-
-
- Bounds
- {{341.3319575753456, 570.2429509286485}, {54, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 320
- Line
-
- ID
- 318
- Position
- 0.59569668769836426
- RotationType
- 0
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-request }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Bounds
- {{321.03288241839817, 473.45068418304118}, {93, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 319
- Line
-
- ID
- 317
- Position
- 0.47598496079444885
- RotationType
- 0
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-create_volume }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 315
-
- ID
- 318
- Points
-
- {367.5092134475708, 553.36860656738281}
- {368.89035949851444, 598.4827475660544}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 314
- Info
- 13
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 314
-
- ID
- 317
- Points
-
- {367.5543794631958, 459}
- {367.50921617744456, 510.36860656738281}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 316
- Info
- 13
-
-
-
- Bounds
- {{298.8548583984375, 430}, {137.3990421295166, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 316
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.809665
- g
- 0.973391
- r
- 0.992442
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.610953
- g
- 0.706552
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Compute}
-
-
-
- Bounds
- {{300.51228332519531, 598.98251342773438}, {137.3990421295166, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 315
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.809665
- g
- 0.973391
- r
- 0.992442
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.610953
- g
- 0.706552
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Connection}
-
-
-
- Bounds
- {{298.8096923828125, 510.36860656738281}, {137.3990421295166, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 314
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.809665
- g
- 0.973391
- r
- 0.992442
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.610953
- g
- 0.706552
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Volume::\
-OpenStack}
-
-
-
- Bounds
- {{297.02395568167469, 351.29157276299429}, {141, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 308
- Line
-
- ID
- 258
- Position
- 0.73766463994979858
- RotationType
- 0
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-create(volume_params) }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 258
- Position
- 0.38146933913230896
-
- ID
- 307
- Points
-
- {345.99999982329541, 267.98217960429497}
- {367.48264298796443, 268.00022651177414}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- Pattern
- 1
- TailArrow
- 0
-
-
- Tail
-
- ID
- 285
-
-
-
- Bounds
- {{357.2591976275948, 318.48035579224052}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 306
- Line
-
- ID
- 258
- Position
- 0.61047923564910889
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 3}
-
-
-
- Bounds
- {{205.75322617648635, 191.5}, {47, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 301
- Line
-
- ID
- 302
- Position
- 0.5864027738571167
- RotationType
- 0
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-create }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Bounds
- {{226.5, 217.47472131252289}, {119, 100.91410827636719}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 285
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.992442
- g
- 0.919661
- r
- 0.828059
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.771739
- g
- 0.521768
- r
- 0.477113
-
- CornerRadius
- 9
-
-
- Text
-
- Align
- 0
- Pad
- 15
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\b\fs24 \cf0 \expnd0\expndtw0\kerning0
-volme_params
-\b0 \expnd0\expndtw0\kerning0
-\
-\
-:name \
-:description\
-:size\
-:availablity_zone }
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 299
-
- ID
- 300
- Points
-
- {112, 345}
- {112.43748368985048, 358.09725976452785}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{75.938514709472656, 358.59698104858398}, {74, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 299
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- a
- 0.26
- b
- 0
- g
- 0
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.771739
- g
- 0.521768
- r
- 0.477113
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Error}
-
-
-
- Bounds
- {{75.938514709472656, 293.13648483043426}, {69, 21.863536106721138}}
- Class
- ShapedGraphic
- ID
- 293
- Shape
- Rectangle
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Align
- 0
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-< 1024 OR\
-> 1024*1000}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Bounds
- {{50.938514709472656, 256.99999306948121}, {119, 21.863536106721138}}
- Class
- ShapedGraphic
- ID
- 294
- Shape
- Rectangle
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 If \
- size is not integer \
-OR}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Bounds
- {{31.938514709472656, 224.71001052856445}, {162, 118.17697143554688}}
- Class
- ShapedGraphic
- ID
- 296
- Shape
- Diamond
- Style
-
- fill
-
- Color
-
- b
- 0.838968
- g
- 0.981553
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.630487
- g
- 0.735237
- r
- 0.99551
-
- Pattern
- 1
-
-
- Text
-
- Align
- 0
- Pad
- 10
- VerticalPad
- 0
-
-
-
- Bounds
- {{173.6102647359512, 189.99999618530273}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 303
- Line
-
- ID
- 302
- Offset
- 2
- Position
- 0.33448684215545654
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 2}
-
-
-
- Bounds
- {{123.7019228041172, 176.63347372237627}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 298
- Line
-
- ID
- 297
- Position
- 0.23375198245048523
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 1}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 296
-
- ID
- 297
- Points
-
- {133, 168.08934020996094}
- {135, 206}
- {115, 206}
- {114.48778005344181, 225.3306941226887}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 316
- Info
- 3
-
- ID
- 258
- Points
-
- {367.43839892878884, 168.08934020996094}
- {367.55438219306956, 430}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 269
- Info
- 11
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 285
-
- ID
- 302
- Points
-
- {157.19203287972036, 168.08934020996094}
- {157, 201.5}
- {288.29541015625, 201.5}
- {287.7607034326499, 216.97501952863024}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 269
- Info
- 15
-
-
-
- Bounds
- {{104.63043196870763, 150.08934020996094}, {315.36956787109375, 18}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 269
- Magnets
-
- {-0.73960024176586936, -1.1094003915786743}
- {-0.42163697454145743, -1.2649110555648804}
- {1.9868216701487083e-08, -1.3333333730697632}
- {0.4216371064819644, -1.2649110555648804}
- {0.73960031615696409, -1.1094003915786743}
- {1.1094003915786752, -0.73960025003154684}
- {1.2649110555648815, -0.4216368426009538}
- {1.3333333730697643, 1.5894572413799324e-07}
- {1.2649110555648815, 0.42163714417925036}
- {1.1094003915786752, 0.73960034921967122}
- {0.73960021696883971, 1.1094003915786743}
- {0.42163699339010319, 1.2649110555648804}
- {1.1842379282265398e-15, 1.3333333730697632}
- {-0.42163733062650866, 1.2649109363555908}
- {-0.73960021696883826, 1.1094003915786743}
- {-1.1094003915786739, 0.73960034921967122}
- {-1.2649110555648797, 0.42163676720637966}
- {-1.3333333730697625, -6.3578289655197295e-07}
- {-1.2649109363555902, -0.4216371798373757}
- {-1.1094005107879634, -0.73960016419084695}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- VerticalPad
- 3
-
-
-
- Bounds
- {{23.90777587890625, 116.88748168945312}, {74, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 233
- Shape
- Rectangle
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs28 \cf0 Create Disk}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Bounds
- {{14.253219604492188, 111.68505859375}, {444.74676513671875, 239.31494140625}}
- Class
- ShapedGraphic
- ID
- 4
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.950215
- g
- 0.950215
- r
- 0.950215
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.48913
- g
- 0.48913
- r
- 0.48913
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- Bounds
- {{264, 392.68506050109863}, {194.99998474121094, 239.31494140625}}
- Class
- ShapedGraphic
- ID
- 321
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.950215
- g
- 0.950215
- r
- 0.950215
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.48913
- g
- 0.48913
- r
- 0.48913
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- GridInfo
-
- GuidesLocked
- NO
- GuidesVisible
- YES
- HPages
- 1
- ImageCounter
- 1
- KeepToScale
-
- Layers
-
-
- Lock
- NO
- Name
- Layer 1
- Print
- YES
- View
- YES
-
-
- LayoutInfo
-
- Animate
- NO
- circoMinDist
- 18
- circoSeparation
- 0.0
- layoutEngine
- dot
- neatoSeparation
- 0.0
- twopiSeparation
- 0.0
-
- LinksVisible
- NO
- MagnetsVisible
- NO
- MasterSheets
-
- ModificationDate
- 2013-01-07 11:25:38 +0000
- Modifier
- rajdeepd
- NotesVisible
- NO
- Orientation
- 2
- OriginVisible
- NO
- PageBreaks
- YES
- PrintInfo
-
- NSBottomMargin
-
- float
- 41
-
- NSHorizonalPagination
-
- coded
- BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
-
- NSLeftMargin
-
- float
- 18
-
- NSPaperSize
-
- size
- {612, 792}
-
- NSPrintReverseOrientation
-
- int
- 0
-
- NSRightMargin
-
- float
- 18
-
- NSTopMargin
-
- float
- 18
-
-
- PrintOnePage
-
- ReadOnly
- NO
- RowAlign
- 1
- RowSpacing
- 36
- SheetTitle
- Canvas 1
- SmartAlignmentGuidesActive
- YES
- SmartDistanceGuidesActive
- YES
- UniqueID
- 1
- UseEntirePage
-
- VPages
- 1
- WindowInfo
-
- CurrentSheet
- 0
- ExpandedCanvases
-
-
- name
- Canvas 1
-
-
- Frame
- {{963, 535}, {710, 811}}
- ListView
-
- OutlineWidth
- 142
- RightSidebar
-
- ShowRuler
-
- Sidebar
-
- SidebarWidth
- 120
- VisibleRegion
- {{0, 61}, {575, 672}}
- Zoom
- 1
- ZoomValues
-
-
- Canvas 1
- 1
- 1
-
-
-
-
-
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_create_disk.png b/src/bosh_openstack_cpi/docs/images/openstack_cpi_create_disk.png
deleted file mode 100644
index 7c2aa77b3..000000000
Binary files a/src/bosh_openstack_cpi/docs/images/openstack_cpi_create_disk.png and /dev/null differ
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_create_vm.graffle b/src/bosh_openstack_cpi/docs/images/openstack_cpi_create_vm.graffle
deleted file mode 100644
index 9bc70e813..000000000
--- a/src/bosh_openstack_cpi/docs/images/openstack_cpi_create_vm.graffle
+++ /dev/null
@@ -1,4813 +0,0 @@
-
-
-
-
- ApplicationVersion
-
- com.omnigroup.OmniGraffle7
- 177.6.0.286920
-
- CreationDate
- 2012-12-26 07:23:41 +0000
- Creator
- rajdeepd
- CurrentSheet
- 0
- GraphDocumentVersion
- 13
- GuidesLocked
- NO
- GuidesVisible
- YES
- ImageCounter
- 1
- LinksVisible
- NO
- MagnetsVisible
- NO
- MasterSheets
-
- ModificationDate
- 2017-05-09 15:48:23 +0000
- Modifier
- the openstack cpi user
- MovementHandleVisible
- NO
- NotesVisible
- NO
- OriginVisible
- NO
- PageBreaks
- YES
- PrintInfo
-
- NSBottomMargin
-
- float
- 41
-
- NSHorizonalPagination
-
- coded
- BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
-
- NSLeftMargin
-
- float
- 18
-
- NSPaperSize
-
- size
- {612, 792}
-
- NSPrintReverseOrientation
-
- coded
- BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
-
- NSRightMargin
-
- float
- 18
-
- NSTopMargin
-
- float
- 18
-
-
- ReadOnly
- NO
- Sheets
-
-
- ActiveLayerIndex
- 0
- AutoAdjust
- 6
- BackgroundGraphic
-
- Bounds
- {{0, 0}, {2448.0769230769229, 1530.1282051282051}}
- Class
- ShapedGraphic
- ID
- 2
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
-
- BaseZoom
- 0
- CanvasOrigin
- {0, 0}
- ColumnAlign
- 1
- ColumnSpacing
- 36
- DisplayScale
- 1 in = 1.00000 in
- GraphicsList
-
-
- Bounds
- {{137.9592262231638, 154.38420923887975}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 31
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326096296310425
- g
- 0.57326847314834595
- r
- 0.57325458526611328
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 2}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 69
-
- ID
- 118
- Points
-
- {274.41113056241045, 154.38420923887975}
- {274.41113056241045, 189.84917342084017}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- AllowConnections
- NO
- AllowLabelDrop
-
- Class
- LineGraphic
- Head
-
- ID
- 21
- Info
- 1
-
- ID
- 116
- OrthogonalBarAutomatic
-
- OrthogonalBarPoint
- {0, 0}
- OrthogonalBarPosition
- -1
- Points
-
- {274.41113233781994, 291.08280254777088}
- {356.10233440883803, 329.78198716130788}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- LineType
- 2
- TailArrow
- 0
-
-
- Tail
-
- ID
- 77
- Position
- 0.4625809125961135
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 21
-
- ID
- 115
- Points
-
- {385.97947378309135, 265.65521793255164}
- {385.88945108108362, 329.28198767509019}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 24
-
-
-
- Class
- LineGraphic
- ID
- 114
- Points
-
- {386.03828374177249, 431.10102977489856}
- {386.03828374177249, 473.75998941063881}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 103
- Info
- 13
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 39
-
- ID
- 117
- Points
-
- {158.29509041049988, 154.38420923887975}
- {158.29509041049988, 189.84917342084017}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 103
- Info
- 3
-
- ID
- 113
- Points
-
- {385.88873251973132, 372.78198716130782}
- {386.03828579958292, 410.60102977489851}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 21
- Info
- 13
-
-
-
- Bounds
- {{581.88444547870176, 154.25304666162859}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 112
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326100000000002
- g
- 0.573268
- r
- 0.57325499999999996
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 5}
-
-
-
- AllowConnections
- NO
- AllowLabelDrop
-
- Class
- LineGraphic
- ID
- 111
- Points
-
- {602.79731440712351, 437.66793103355212}
- {602.6724762533911, 473.62882683338762}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 110
- Info
- 13
-
-
-
- Bounds
- {{561.59998744726181, 403.66793103355212}, {82.394653919723396, 34}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 110
- Magnets
-
- {-0.73960026163363846, -1.1094003924504587}
- {-0.42163702135578457, -1.2649110640673515}
- {0, -1.3333333333333333}
- {0.42163702135578457, -1.2649110640673515}
- {0.73960026163363846, -1.1094003924504587}
- {1.1094003924504596, -0.73960026163363712}
- {1.2649110640673522, -0.42163702135578257}
- {1.3333333333333333, 0}
- {1.2649110640673509, 0.42163702135578662}
- {1.1094003924504576, 0.73960026163363979}
- {0.73960026163363846, 1.1094003924504587}
- {0.42163702135578257, 1.2649110640673522}
- {0, 1.3333333333333333}
- {-0.42163702135578257, 1.2649110640673522}
- {-0.73960026163363846, 1.1094003924504587}
- {-1.1094003924504576, 0.73960026163363979}
- {-1.2649110640673509, 0.42163702135578662}
- {-1.3333333333333333, 0}
- {-1.2649110640673522, -0.42163702135578257}
- {-1.1094003924504596, -0.73960026163363712}
-
- Style
-
- fill
-
- Color
-
- b
- 0.86827900000000002
- g
- 0.98061799999999999
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250200000000003
- g
- 0.74964200000000003
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-create(server_params)}
- VerticalPad
- 3
-
-
-
- AllowConnections
- NO
- AllowLabelDrop
-
- Class
- LineGraphic
- ID
- 109
- Points
-
- {549.36410392963262, 240.95801016767234}
- {549.36410392963239, 473.62882683338762}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 107
- Info
- 13
-
-
-
- AllowConnections
- NO
- AllowLabelDrop
-
- Class
- LineGraphic
- Head
-
- ID
- 107
-
- ID
- 108
- Points
-
- {549.36410392963239, 154.07999655604362}
- {549.36410392963239, 206.45801016767234}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{516.18444694721074, 206.95801016767234}, {66.35931396484375, 34}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 107
- Magnets
-
- {-0.73960026163363846, -1.1094003924504587}
- {-0.42163702135578457, -1.2649110640673515}
- {0, -1.3333333333333333}
- {0.42163702135578457, -1.2649110640673515}
- {0.73960026163363846, -1.1094003924504587}
- {1.1094003924504596, -0.73960026163363712}
- {1.2649110640673522, -0.42163702135578257}
- {1.3333333333333333, 0}
- {1.2649110640673509, 0.42163702135578662}
- {1.1094003924504576, 0.73960026163363979}
- {0.73960026163363846, 1.1094003924504587}
- {0.42163702135578257, 1.2649110640673522}
- {0, 1.3333333333333333}
- {-0.42163702135578257, 1.2649110640673522}
- {-0.73960026163363846, 1.1094003924504587}
- {-1.1094003924504576, 0.73960026163363979}
- {-1.2649110640673509, 0.42163702135578662}
- {-1.3333333333333333, 0}
- {-1.2649110640673522, -0.42163702135578257}
- {-1.1094003924504596, -0.73960026163363712}
-
- Style
-
- fill
-
- Color
-
- b
- 0.86827900000000002
- g
- 0.98061799999999999
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250200000000003
- g
- 0.74964200000000003
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-find flavour}
- VerticalPad
- 3
-
-
-
- Bounds
- {{528.78444666557857, 154.25304666162859}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 106
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326100000000002
- g
- 0.573268
- r
- 0.57325499999999996
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 4}
-
-
-
- Class
- LineGraphic
- ID
- 105
- Points
-
- {491.32880367205831, 430.60102977489851}
- {491.32880367205831, 473.62882683338762}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 102
- Info
- 13
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 102
- Info
- 3
-
- ID
- 104
- Points
-
- {491.32880367205831, 327.64322585771379}
- {491.32880556985072, 410.60102977489856}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 98
- Info
- 13
-
-
-
- Bounds
- {{334.25179014698818, 410.60102977489851}, {103.57298718956832, 20}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 103
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Style
-
- fill
-
- Color
-
- b
- 0.86827900000000002
- g
- 0.98061799999999999
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250200000000003
- g
- 0.74964200000000003
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-metadata.update}
- VerticalPad
- 3
-
-
-
- Bounds
- {{443.56929481936578, 410.60102977489851}, {95.51901770538484, 20}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 102
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Style
-
- fill
-
- Color
-
- b
- 0.86827900000000002
- g
- 0.98061799999999999
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250200000000003
- g
- 0.74964200000000003
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-security_groups}
- VerticalPad
- 3
-
-
-
- Bounds
- {{470.68096347524477, 154.25304666162859}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 101
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326100000000002
- g
- 0.573268
- r
- 0.57325499999999996
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 1}
-
-
-
- AllowConnections
- NO
- AllowLabelDrop
-
- Class
- LineGraphic
- Head
-
- ID
- 110
- Info
- 3
-
- ID
- 100
- Points
-
- {602.6724762533911, 155.5140517244738}
- {602.79706287340116, 403.16793109682129}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- AllowConnections
- NO
- AllowLabelDrop
-
- AllowToConnect
-
- Class
- LineGraphic
- Head
-
- ID
- 98
- Info
- 3
-
- ID
- 99
- Points
-
- {491.12916904555044, 154.07999655604362}
- {491.3288054474678, 260.16322720954713}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{446.64916194842539, 260.16322720954713}, {89.359283447265625, 67.479998648166656}}
- Class
- ShapedGraphic
- ID
- 98
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Style
-
- fill
-
- Color
-
- b
- 0.86827900000000002
- g
- 0.98061799999999999
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250200000000003
- g
- 0.74964200000000003
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-retrieve and validate security groups}
- VerticalPad
- 3
-
-
-
- Bounds
- {{632.73303703422766, 154.38420923887975}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 89
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326100000000002
- g
- 0.573268
- r
- 0.57325499999999996
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 8}
-
-
-
- AllowLabelDrop
-
- Class
- LineGraphic
- Head
-
- ID
- 87
-
- ID
- 77
- Points
-
- {274.41113233781994, 258.32917318495737}
- {274.41113233781994, 329.13544579049909}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 69
-
-
-
- AllowConnections
- NO
- AllowLabelDrop
-
- Class
- LineGraphic
- ID
- 76
- Points
-
- {274.41113056241056, 437.60102977489856}
- {274.41113056241056, 473.75998941063881}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 74
- Info
- 13
-
-
-
- AllowConnections
- NO
- AllowLabelDrop
-
- Class
- LineGraphic
- Head
-
- ID
- 74
-
- ID
- 75
- Points
-
- {274.41113233782005, 373.13544579049903}
- {274.41113233782005, 403.60102977489856}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 87
-
-
-
- Bounds
- {{229.73148883877764, 403.60102977489851}, {89.359283447265625, 34}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 74
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Style
-
- fill
-
- Color
-
- b
- 0.86827900000000002
- g
- 0.98061799999999999
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250200000000003
- g
- 0.74964200000000003
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-create_lbaas_pool_member}
- VerticalPad
- 3
-
-
-
- Bounds
- {{229.73148883877764, 329.63544579049903}, {89.359283447265625, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 87
- Magnets
-
- {-0.73960024176586991, -1.1094003915786763}
- {-0.42163697454145854, -1.2649110555648826}
- {1.9868215517249155e-08, -1.3333333730697656}
- {0.42163710648196329, -1.2649110555648826}
- {0.73960031615696287, -1.1094003915786763}
- {1.1094003915786741, -0.73960025003154883}
- {1.2649110555648801, -0.42163684260095602}
- {1.333333373069763, 1.5894572413799324e-07}
- {1.2649110555648801, 0.42163714417925036}
- {1.1094003915786741, 0.73960034921967122}
- {0.73960021696883849, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650977, 1.2649109363555908}
- {-0.73960021696883882, 1.1094003915786743}
- {-1.1094003915786743, 0.73960034921967122}
- {-1.2649110555648804, 0.42163676720637966}
- {-1.3333333730697632, -6.3578289655197295e-07}
- {-1.2649109363555908, -0.42163717983737792}
- {-1.1094005107879639, -0.73960016419084895}
-
- Style
-
- fill
-
- Color
-
- b
- 0.99431599999999998
- g
- 0.93638699999999997
- r
- 0.85887400000000003
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.996609
- g
- 0.75748
- r
- 0.483699
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.81430899999999995
- g
- 0.60083900000000001
- r
- 0.54992300000000005
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-LoadbalancerConfigurator}
-
-
-
- Bounds
- {{113.61544868686707, 329.78198716130782}, {89.359283447265625, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 88
- Magnets
-
- {-0.73960024176586991, -1.1094003915786763}
- {-0.42163697454145854, -1.2649110555648826}
- {1.9868215517249155e-08, -1.3333333730697656}
- {0.42163710648196329, -1.2649110555648826}
- {0.73960031615696287, -1.1094003915786763}
- {1.1094003915786741, -0.73960025003154883}
- {1.2649110555648801, -0.42163684260095602}
- {1.333333373069763, 1.5894572413799324e-07}
- {1.2649110555648801, 0.42163714417925036}
- {1.1094003915786741, 0.73960034921967122}
- {0.73960021696883849, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650977, 1.2649109363555908}
- {-0.73960021696883882, 1.1094003915786743}
- {-1.1094003915786743, 0.73960034921967122}
- {-1.2649110555648804, 0.42163676720637966}
- {-1.3333333730697632, -6.3578289655197295e-07}
- {-1.2649109363555908, -0.42163717983737792}
- {-1.1094005107879639, -0.73960016419084895}
-
- Style
-
- fill
-
- Color
-
- b
- 0.99431556463241577
- g
- 0.93638718128204346
- r
- 0.85887354612350464
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.996609
- g
- 0.75748
- r
- 0.483699
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.814308762550354
- g
- 0.60083860158920288
- r
- 0.54992306232452393
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Network\
-Configurator}
-
-
-
- Bounds
- {{220.73283971844683, 190.34917342084017}, {107.35658168792725, 67.479998648166656}}
- Class
- ShapedGraphic
- ID
- 69
- Shape
- Diamond
- Style
-
- fill
-
- Color
-
- b
- 0.86940200000000001
- g
- 0.98219100000000004
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.69062800000000002
- g
- 0.78484600000000004
- r
- 1
- space
- srgb
-
- Pattern
- 1
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 if loadbalancerpools}
- VerticalPad
- 0.0
-
-
-
- Bounds
- {{253.88869003562775, 154.38420923887975}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 68
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326100000000002
- g
- 0.573268
- r
- 0.57325499999999996
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 6}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 5
-
- ID
- 3
- Points
-
- {158.29509041049988, 372.78198716130782}
- {158.29509206989331, 410.60102977489856}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 88
- Info
- 13
-
-
-
- Class
- LineGraphic
- ID
- 4
- Points
-
- {158.29509041049997, 430.60102977489856}
- {158.29509041049997, 473.75998941063881}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 5
- Info
- 13
-
-
-
- Bounds
- {{116.53509134390862, 410.60102977489851}, {83.519998133182526, 20}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 5
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Style
-
- fill
-
- Color
-
- b
- 0.8682788610458374
- g
- 0.9806181788444519
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250247716903687
- g
- 0.74964249134063721
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-ports.create}
- VerticalPad
- 3
-
-
-
- AllowConnections
- NO
- AllowLabelDrop
-
- Class
- LineGraphic
- Head
-
- ID
- 36
-
- ID
- 13
- Points
-
- {69.169223244818525, 444.60102977489851}
- {69.169225113126416, 473.75998941063881}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 30
- Info
- 13
-
-
-
- AllowConnections
- NO
- AllowLabelDrop
-
- AllowToConnect
-
- Class
- LineGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 12
-
- Head
-
- ID
- 30
-
- ID
- 14
- Points
-
- {70.443109744649647, 152.72576335072517}
- {69.169224394331437, 396.60102977489845}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 88
- Info
- 3
-
- ID
- 15
- Points
-
- {158.29509041050002, 310.9032265336304}
- {158.2950921859094, 329.78198716130788}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 37
- Info
- 13
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 37
- Info
- 3
-
- ID
- 16
- Points
-
- {158.29509263080408, 258.3291734646001}
- {158.29509263080408, 276.90322653363046}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 39
-
-
-
- Bounds
- {{365.40882378185194, 154.38420923887975}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 18
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326096296310425
- g
- 0.57326847314834595
- r
- 0.57325458526611328
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 7}
-
-
-
- Bounds
- {{341.2091341882799, 329.78198716130782}, {89.359196662902832, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 21
- Magnets
-
- {-0.73960024176586991, -1.1094003915786763}
- {-0.42163697454145854, -1.2649110555648826}
- {1.9868215517249155e-08, -1.3333333730697656}
- {0.42163710648196329, -1.2649110555648826}
- {0.73960031615696287, -1.1094003915786763}
- {1.1094003915786741, -0.73960025003154883}
- {1.2649110555648801, -0.42163684260095602}
- {1.333333373069763, 1.5894572413799324e-07}
- {1.2649110555648801, 0.42163714417925036}
- {1.1094003915786741, 0.73960034921967122}
- {0.73960021696883849, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650977, 1.2649109363555908}
- {-0.73960021696883882, 1.1094003915786743}
- {-1.1094003915786743, 0.73960034921967122}
- {-1.2649110555648804, 0.42163676720637966}
- {-1.3333333730697632, -6.3578289655197295e-07}
- {-1.2649109363555908, -0.42163717983737792}
- {-1.1094005107879639, -0.73960016419084895}
-
- Style
-
- fill
-
- Color
-
- b
- 0.99431556463241577
- g
- 0.93638718128204346
- r
- 0.85887354612350464
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.996609
- g
- 0.75748
- r
- 0.483699
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.814308762550354
- g
- 0.60083860158920288
- r
- 0.54992306232452393
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Tag\
-Manager}
-
-
-
- AllowConnections
- NO
- Class
- LineGraphic
- Head
-
- ID
- 24
-
- ID
- 23
- Points
-
- {386.03828374177232, 154.38420923887975}
- {386.03828374177232, 182.47862812297907}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{332.3599928978087, 182.97862812297907}, {107.35658168792725, 82.221089243888855}}
- Class
- ShapedGraphic
- ID
- 24
- Shape
- Diamond
- Style
-
- fill
-
- Color
-
- b
- 0.86940175294876099
- g
- 0.98219138383865356
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.69062763452529907
- g
- 0.78484636545181274
- r
- 1
- space
- srgb
-
- Pattern
- 1
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 if human readable vm names}
- VerticalPad
- 0.0
-
-
-
- Bounds
- {{49.679998889565468, 154.38420923887975}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 29
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326096296310425
- g
- 0.57326847314834595
- r
- 0.57325458526611328
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 3}
-
-
-
- Bounds
- {{40.240784395793099, 396.60102977489851}, {57.85687769805071, 48}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 30
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Style
-
- fill
-
- Color
-
- b
- 0.8682788610458374
- g
- 0.9806181788444519
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250247716903687
- g
- 0.74964249134063721
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-find stem cell image}
- VerticalPad
- 3
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 33
-
- ID
- 32
- Points
-
- {69.169225465122565, 590.73998725414276}
- {69.169225465122565, 637.91998574137676}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 35
-
-
-
- Bounds
- {{13.29344334784389, 637.91998574137688}, {111.75155979394913, 36.85308837890625}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 33
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Style
-
- fill
-
- Color
-
- b
- 0.97923249006271362
- g
- 0.99126559495925903
- r
- 0.86211967468261719
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.838662
- g
- 0.902049
- r
- 0.624939
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.87963306903839111
- g
- 0.90069097280502319
- r
- 0.54882305860519409
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Glance}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 35
-
- ID
- 34
- Points
-
- {69.169223244818454, 517.25998941063881}
- {69.169223244818454, 569.73998725414276}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 36
-
-
-
- Bounds
- {{15.490932400854831, 570.23998725414276}, {107.35658168792725, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 35
- Style
-
- fill
-
- Color
-
- b
- 0.84499651193618774
- g
- 0.97522002458572388
- r
- 0.99423378705978394
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.624103
- g
- 0.822736
- r
- 0.999357
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.67316055297851562
- g
- 0.76121300458908081
- r
- 1
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Connection}
-
-
-
- Bounds
- {{22.151715360527945, 473.75998941063881}, {94.035015768581019, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 36
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Style
-
- fill
-
- Color
-
- b
- 0.84499651193618774
- g
- 0.97522002458572388
- r
- 0.99423378705978394
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.624103
- g
- 0.822736
- r
- 0.999357
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.67316055297851562
- g
- 0.76121300458908081
- r
- 1
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Image::\
-OpenStack}
-
-
-
- Bounds
- {{102.41931051352532, 276.90322653363046}, {111.75155979394913, 34}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 37
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Style
-
- fill
-
- Color
-
- b
- 0.8682788610458374
- g
- 0.9806181788444519
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250247716903687
- g
- 0.74964249134063721
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-prepare ports for manual networks}
- VerticalPad
- 3
-
-
-
- Bounds
- {{104.61679956653626, 190.34917342084017}, {107.35658168792725, 67.479998648166656}}
- Class
- ShapedGraphic
- ID
- 39
- Shape
- Diamond
- Style
-
- fill
-
- Color
-
- b
- 0.86940175294876099
- g
- 0.98219138383865356
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.69062763452529907
- g
- 0.78484636545181274
- r
- 1
- space
- srgb
-
- Pattern
- 1
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 if manual port creation}
- VerticalPad
- 0.0
-
-
-
- Bounds
- {{554.28134519614605, 99.900384902954102}, {143, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 40
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.79315453767776489
- g
- 0.79316467046737671
- r
- 0.79314583539962769
- space
- srgb
-
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs28 \cf0 Bosh OpenStack CPI}
- VerticalPad
- 0.0
-
- Wrap
- NO
-
-
- Bounds
- {{628.28134519614605, 473.75998941063881}, {69, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 41
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.79315453767776489
- g
- 0.79316467046737671
- r
- 0.79314583539962769
- space
- srgb
-
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs28 \cf0 Fog Gem}
- VerticalPad
- 0.0
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 43
- Info
- 3
-
- ID
- 42
- Points
-
- {472.63559326941231, 590.73998725414276}
- {472.63559326941231, 637.91998574137688}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 45
-
-
-
- Bounds
- {{416.75981115213364, 637.91998574137688}, {111.75155979394913, 36.85308837890625}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 43
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Style
-
- fill
-
- Color
-
- b
- 0.97923249006271362
- g
- 0.99126559495925903
- r
- 0.86211967468261719
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.838662
- g
- 0.902049
- r
- 0.624939
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.87963306903839111
- g
- 0.90069097280502319
- r
- 0.54882305860519409
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Nova Compute}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 45
-
- ID
- 44
- Points
-
- {472.6355910491082, 516.75998941063881}
- {472.6355910491082, 570.23998725414276}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 46
-
-
-
- Bounds
- {{418.95730020514458, 570.23998725414276}, {107.35658168792725, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 45
- Magnets
-
- {-0.73960026163363979, -1.1094003924504576}
- {-0.42163702135578457, -1.2649110640673515}
- {0, -1.3333333333333333}
- {0.42163702135578457, -1.2649110640673515}
- {0.73960026163363846, -1.1094003924504587}
- {0.5, -0.33333333333333215}
- {1.2649110640673509, -0.42163702135578662}
- {1.3333333333333333, 0}
- {1.2649110640673509, 0.42163702135578662}
- {0.5, 0.33333333333333215}
- {0.73960026163363846, 1.1094003924504587}
- {0.42163702135578457, 1.2649110640673515}
- {0, 1.3333333333333333}
- {-0.42163702135578457, 1.2649110640673515}
- {-0.73960026163363846, 1.1094003924504587}
- {-0.5, 0.33333333333333215}
- {-1.2649110640673509, 0.42163702135578662}
- {-1.3333333333333333, 0}
- {-1.2649110640673509, -0.42163702135578662}
- {-0.5, -0.33333333333333215}
-
- Style
-
- fill
-
- Color
-
- b
- 0.84499651193618774
- g
- 0.97522002458572388
- r
- 0.99423378705978394
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.624103
- g
- 0.822736
- r
- 0.999357
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.67316055297851562
- g
- 0.76121300458908081
- r
- 1
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Connection}
-
-
-
- Bounds
- {{333.27119577748238, 473.75998941063881}, {278.72879054325165, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 46
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Style
-
- fill
-
- Color
-
- b
- 0.84499651193618774
- g
- 0.97522002458572388
- r
- 0.99423378705978394
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.624103
- g
- 0.822736
- r
- 0.999357
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.67316055297851562
- g
- 0.76121300458908081
- r
- 1
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Compute::OpenStack}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 48
-
- ID
- 47
- Points
-
- {224.04206472182511, 590.73998725414276}
- {224.04206472182511, 637.91998574137676}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 50
-
-
-
- Bounds
- {{168.16628260454644, 637.91998574137688}, {111.75155979394913, 36.85308837890625}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 48
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Style
-
- fill
-
- Color
-
- b
- 0.97923249006271362
- g
- 0.99126559495925903
- r
- 0.86211967468261719
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.838662
- g
- 0.902049
- r
- 0.624939
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.87963306903839111
- g
- 0.90069097280502319
- r
- 0.54882305860519409
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Neutron}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 50
-
- ID
- 49
- Points
-
- {224.042062501521, 516.75998941063881}
- {224.042062501521, 569.73998725414276}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 51
- Info
- 13
-
-
-
- Bounds
- {{170.36377165755738, 570.23998725414276}, {107.35658168792725, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 50
- Style
-
- fill
-
- Color
-
- b
- 0.84499651193618774
- g
- 0.97522002458572388
- r
- 0.99423378705978394
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.624103
- g
- 0.822736
- r
- 0.999357
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.67316055297851562
- g
- 0.76121300458908081
- r
- 1
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Connection}
-
-
-
- Bounds
- {{130.96102272814659, 473.75998941063881}, {186.16207954674883, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 51
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Style
-
- fill
-
- Color
-
- b
- 0.84499651193618774
- g
- 0.97522002458572388
- r
- 0.99423378705978394
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.624103
- g
- 0.822736
- r
- 0.999357
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.67316055297851562
- g
- 0.76121300458908081
- r
- 1
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::OpenStack::Network}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 56
-
- ID
- 53
- Points
-
- {652.47672429780766, 240.95801016767234}
- {652.47672607321533, 329.78198716130788}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 55
- Info
- 13
-
-
-
- AllowConnections
- NO
- AllowLabelDrop
-
- Class
- LineGraphic
- Head
-
- ID
- 55
- Info
- 3
-
- ID
- 54
- Points
-
- {653.10239799263036, 154.21115913329479}
- {652.47672575318109, 206.95801016767234}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{615.85105205835816, 206.95801016767234}, {73.251344478898659, 34}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 55
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Style
-
- fill
-
- Color
-
- b
- 0.8682788610458374
- g
- 0.9806181788444519
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250247716903687
- g
- 0.74964249134063721
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 update_\
-settings}
- VerticalPad
- 3
-
-
-
- Bounds
- {{607.79712596635613, 329.78198716130782}, {89.359196662902832, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 56
- Magnets
-
- {-0.73960024176586991, -1.1094003915786763}
- {-0.42163697454145854, -1.2649110555648826}
- {1.9868215517249155e-08, -1.3333333730697656}
- {0.42163710648196329, -1.2649110555648826}
- {0.73960031615696287, -1.1094003915786763}
- {1.1094003915786741, -0.73960025003154883}
- {1.2649110555648801, -0.42163684260095602}
- {1.333333373069763, 1.5894572413799324e-07}
- {1.2649110555648801, 0.42163714417925036}
- {1.1094003915786741, 0.73960034921967122}
- {0.73960021696883849, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650977, 1.2649109363555908}
- {-0.73960021696883882, 1.1094003915786743}
- {-1.1094003915786743, 0.73960034921967122}
- {-1.2649110555648804, 0.42163676720637966}
- {-1.3333333730697632, -6.3578289655197295e-07}
- {-1.2649109363555908, -0.42163717983737792}
- {-1.1094005107879639, -0.73960016419084895}
-
- Style
-
- fill
-
- Color
-
- b
- 0.99431556463241577
- g
- 0.93638718128204346
- r
- 0.85887354612350464
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.996609
- g
- 0.75748
- r
- 0.483699
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.814308762550354
- g
- 0.60083860158920288
- r
- 0.54992306232452393
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Registry\
-Client}
-
-
-
- Bounds
- {{23.150572588585533, 99.900384902954102}, {67, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 61
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0.0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs28 \cf0 Create VM}
- VerticalPad
- 0.0
-
- Wrap
- NO
-
-
- Bounds
- {{23.425600710846197, 134.72576335072517}, {673.73072191841277, 18}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 62
- Magnets
-
- {-0.73960026163363879, -1.1094003924504581}
- {-0.42163702135578413, -1.2649110640673518}
- {0, -1.3333333333333333}
- {0.42163702135578357, -1.2649110640673518}
- {0.73960026163363857, -1.1094003924504585}
- {1.1094003924504587, -0.73960026163363846}
- {1.2649110640673522, -0.42163702135578257}
- {1.3333333333333333, 0}
- {1.2649110640673522, 0.42163702135578257}
- {1.1094003924504576, 0.73960026163363979}
- {0.73960026163363846, 1.1094003924504587}
- {0.42163702135578357, 1.2649110640673518}
- {0, 1.3333333333333333}
- {-0.42163702135578368, 1.2649110640673518}
- {-0.73960026163363857, 1.1094003924504585}
- {-1.1094003924504576, 0.73960026163363979}
- {-1.2649110640673522, 0.42163702135578257}
- {-1.3333333333333333, 0}
- {-1.2649110640673522, -0.42163702135578257}
- {-1.1094003924504587, -0.73960026163363846}
-
- Style
-
- fill
-
- Color
-
- b
- 0.8682788610458374
- g
- 0.9806181788444519
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250247716903687
- g
- 0.74964249134063721
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- VerticalPad
- 3
-
-
-
- Bounds
- {{9.6799996942281723, 88.559998020529747}, {693.75998458266258, 367.04937744140625}}
- Class
- ShapedGraphic
- ID
- 63
- IsLocked
- YES
- Style
-
- fill
-
- Color
-
- b
- 0.96036380529403687
- g
- 0.96037584543228149
- r
- 0.96035343408584595
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.56205445528030396
- g
- 0.56206178665161133
- r
- 0.56204819679260254
- space
- srgb
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- Bounds
- {{9.6799996942281723, 467.2799895554781}, {693.75998458266258, 138.64578247070312}}
- Class
- ShapedGraphic
- ID
- 64
- IsLocked
- YES
- Style
-
- fill
-
- Color
-
- b
- 0.96036380529403687
- g
- 0.96037584543228149
- r
- 0.96035343408584595
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.56205445528030396
- g
- 0.56206178665161133
- r
- 0.56204819679260254
- space
- srgb
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- GridInfo
-
- HPages
- 2
- KeepToScale
-
- Layers
-
-
- Artboards
-
- Lock
-
- Name
- Layer 1
- Print
-
- View
-
-
-
- LayoutInfo
-
- Animate
- NO
- circoMinDist
- 18
- circoSeparation
- 0.0
- layoutEngine
- dot
- neatoLineLength
- 0.20000000298023224
- neatoSeparation
- 0.0
- twopiSeparation
- 0.0
-
- Orientation
- 2
- PrintOnePage
-
- RowAlign
- 1
- RowSpacing
- 36
- SheetTitle
- Canvas 1
- UniqueID
- 1
- VPages
- 1
- VisibleVoidKey
- 1
-
-
- SmartAlignmentGuidesActive
- YES
- SmartDistanceGuidesActive
- YES
- UseEntirePage
-
- WindowInfo
-
- Frame
- {{-0, -0}, {2555, 1417}}
- ShowInfo
-
- ShowRuler
-
- Sidebar
-
- SidebarWidth
- 200
- Sidebar_Tab
- 0
- VisibleRegion
- {{-235.25641025641042, 59.615384615384677}, {1296.153846153846, 797.43589743589746}}
- ZoomValues
-
-
- Canvas 1
- 1.5600000000000001
- 1
-
-
-
- compressOnDiskKey
-
- copyLinkedImagesKey
-
- createSinglePDFKey
-
- exportAreaKey
- 0
- exportQualityKey
- 100
- exportSizesKey
-
- 1
-
-
- fileFormatKey
- 0
- htmlImageTypeKey
- 0
- includeBackgroundGraphicKey
-
- includeNonPrintingLayersKey
-
- lastExportTypeKey
- 0
- marginWidthKey
- 0.0
- previewTypeKey
- 0
- readOnlyKey
-
- resolutionForBMPKey
- 1
- resolutionForGIFKey
- 1
- resolutionForHTMLKey
- 1
- resolutionForJPGKey
- 1
- resolutionForPNGKey
- 1
- resolutionForTIFFKey
- 1
- resolutionUnitsKey
- 0
- saveAsFlatFileOptionKey
- 3
- useArtboardsKey
-
- useMarginKey
-
- useNotesKey
-
-
-
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_create_vm.png b/src/bosh_openstack_cpi/docs/images/openstack_cpi_create_vm.png
deleted file mode 100644
index a10bad97d..000000000
Binary files a/src/bosh_openstack_cpi/docs/images/openstack_cpi_create_vm.png and /dev/null differ
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_createstemcell.graffle b/src/bosh_openstack_cpi/docs/images/openstack_cpi_createstemcell.graffle
deleted file mode 100644
index 51784f760..000000000
--- a/src/bosh_openstack_cpi/docs/images/openstack_cpi_createstemcell.graffle
+++ /dev/null
@@ -1,2231 +0,0 @@
-
-
-
-
- ActiveLayerIndex
- 0
- ApplicationVersion
-
- com.omnigroup.OmniGrafflePro
- 139.16.0.171715
-
- AutoAdjust
-
- BackgroundGraphic
-
- Bounds
- {{0, 0}, {576, 733}}
- Class
- SolidGraphic
- ID
- 2
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
-
- BaseZoom
- 0
- CanvasOrigin
- {0, 0}
- ColumnAlign
- 1
- ColumnSpacing
- 36
- CreationDate
- 2012-12-26 07:23:41 +0000
- Creator
- rajdeepd
- DisplayScale
- 1 0/72 in = 1.0000 in
- GraphDocumentVersion
- 8
- GraphicsList
-
-
- Bounds
- {{401.65958404541016, 452}, {69, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 360
- Shape
- Rectangle
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.747526
- g
- 0.747526
- r
- 0.747526
-
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs28 \cf0 Fog Gem}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Bounds
- {{327.65956497192383, 106}, {143, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 357
- Shape
- Rectangle
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.747526
- g
- 0.747526
- r
- 0.747526
-
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs28 \cf0 Bosh OpenStack CPI}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 352
- Info
- 3
-
- ID
- 355
- Points
-
- {252.46617384869853, 622.76139010036434}
- {252.98184974988337, 650.80740356445312}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 298
-
-
-
- Bounds
- {{58.981842041015625, 650.80740356445312}, {388, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 352
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.973627
- g
- 0.992442
- r
- 0.834
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.80124
- g
- 0.886111
- r
- 0.566755
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.850363
- g
- 0.883832
- r
- 0.488493
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Nova Compute API Server}
-
-
-
- Bounds
- {{203.70276768046395, 565.95412171075532}, {97.195475716511652, 20}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 314
- Line
-
- ID
- 311
- Position
- 0.37672871351242065
- RotationType
- 0
-
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-create_request}
- VerticalPad
- 3
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 298
-
- ID
- 311
- Points
-
- {252.31236126271, 560.3551825125935}
- {252.28089107324737, 601.76147472941307}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 293
- Info
- 13
-
-
-
- Bounds
- {{183.57359313964844, 602.261474609375}, {137.3990421295166, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 298
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.809665
- g
- 0.973391
- r
- 0.992442
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.610953
- g
- 0.706552
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Connection}
-
-
-
- Bounds
- {{183.61322021484375, 516.85518264770508}, {137.3990421295166, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 293
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.809665
- g
- 0.973391
- r
- 0.992442
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.610953
- g
- 0.706552
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Image::\
-OpenStack}
-
-
-
- Bounds
- {{115.04947044698037, 471.97082045378124}, {275.1773681640625, 20}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 307
- Line
-
- ID
- 305
- Position
- 0.73913860321044922
- RotationType
- 0
-
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-upload image}
- VerticalPad
- 3
-
-
-
- Bounds
- {{45, 106}, {100, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 291
- Shape
- Rectangle
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs28 \cf0 Create Stemcell}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Bounds
- {{317.84771013259888, 177.31831693649292}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 290
- Line
-
- ID
- 289
- Position
- 0.45820209383964539
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 7}
-
-
-
- Class
- LineGraphic
- ID
- 289
- Points
-
- {288.73332227470399, 156.22575759887695}
- {288, 186}
- {386, 188}
- {386, 212.725830078125}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 245
- Info
- 11
-
-
-
- Bounds
- {{388.90956406588481, 393.89758717366936}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 309
- Line
-
- ID
- 308
- Position
- 0.21028764545917511
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 8}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 293
- Info
- 5
-
- ID
- 308
- Points
-
- {399.31677581556318, 345.66397422293471}
- {399, 462}
- {296.66823577880859, 461}
- {298.11242540178307, 516.85518264770508}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 285
-
-
-
- Bounds
- {{337, 216.36292016506195}, {124.98699188232422, 128.80105590820312}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 285
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.992442
- g
- 0.919661
- r
- 0.828059
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.771739
- g
- 0.521768
- r
- 0.477113
-
- CornerRadius
- 9
-
-
- Text
-
- Align
- 0
- Pad
- 15
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\b\fs24 \cf0 \expnd0\expndtw0\kerning0
-image_params
-\b0 \expnd0\expndtw0\kerning0
-\
-\
-:name \
-:disk_format\
-:container_format\
-:location \
-:is_public }
-
-
-
- Bounds
- {{227.21947259934504, 410.01180685131385}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 306
- Line
-
- ID
- 305
- Position
- 0.1533905416727066
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 6}
-
-
-
- Bounds
- {{229.99612809630355, 327.14381898028546}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 281
- Line
-
- ID
- 277
- Position
- 0.46183508634567261
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 5}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 293
-
- ID
- 305
- Points
-
- {237.72635707566332, 398.99997098324775}
- {237, 457}
- {252.87108891984059, 457}
- {252.31274400947584, 516.85518264770508}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 278
-
-
-
- Bounds
- {{179.16017913818359, 369.50001019239426}, {117.508056640625, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 278
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.992442
- g
- 0.919661
- r
- 0.828059
-
- Draws
- NO
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.994565
- g
- 0.699277
- r
- 0.416525
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.771739
- g
- 0.521768
- r
- 0.477113
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-ramdisk_params}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 278
-
- ID
- 277
- Points
-
- {241.58969342455336, 309.84999033833589}
- {241.58951226416718, 309.36285400390625}
- {238.6528120756206, 369.0006152892019}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 270
-
-
-
- Bounds
- {{232.37107556840016, 171.20798611367846}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 276
- Line
-
- ID
- 272
- Position
- 0.40752935409545898
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 4}
-
-
-
- Bounds
- {{93.354824964226111, 413.11479065578635}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 304
- Line
-
- ID
- 303
- Position
- 0.099847592413425446
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 3}
-
-
-
- Bounds
- {{94.311386000978771, 326.16396556630718}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 274
- Line
-
- ID
- 252
- Position
- 0.73561257123947144
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 2}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 270
-
- ID
- 272
- Points
-
- {242.93364429473894, 156.22575759887695}
- {242.16667610587723, 216.30052787852679}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 245
- Info
- 13
-
-
-
- Bounds
- {{128.0944339632988, 176.49999618530273}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 271
- Line
-
- ID
- 269
- Position
- 0.55914962291717529
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 1}
-
-
-
- Bounds
- {{179.07872352048093, 216.3629150390625}, {124.98699188232422, 92.99993896484375}}
- Class
- ShapedGraphic
- ID
- 270
- Shape
- Diamond
- Style
-
- fill
-
- Color
-
- b
- 0.838968
- g
- 0.981553
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.630487
- g
- 0.735237
- r
- 0.99551
-
- Pattern
- 1
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 if params contain ramdisk image}
- VerticalPad
- 0
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 6
-
- ID
- 269
- Points
-
- {197.13396631477369, 156.22575759887695}
- {197, 186}
- {104, 186}
- {103.45606667166638, 221.37232895155793}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 245
- Info
- 15
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 293
- Info
- 18
-
- ID
- 303
- Points
-
- {104.16697046179047, 400.88026370732462}
- {103, 446}
- {148.59444731473923, 446}
- {148.59444731473923, 538}
- {183.61322021484403, 538.35517239570618}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 267
-
-
-
- Bounds
- {{45.800895690917969, 371.38043087720871}, {117.508056640625, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 267
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.992442
- g
- 0.919661
- r
- 0.828059
-
- Draws
- NO
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.994565
- g
- 0.699277
- r
- 0.416525
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.771739
- g
- 0.521768
- r
- 0.477113
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-kernel_params}
-
-
-
- Bounds
- {{45, 221.36299133300781}, {115.55921422462984, 87.999862670898438}}
- Class
- ShapedGraphic
- ID
- 6
- Shape
- Diamond
- Style
-
- fill
-
- Color
-
- b
- 0.838968
- g
- 0.981553
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.630487
- g
- 0.735237
- r
- 0.99551
-
- Pattern
- 1
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 if params contain kernel image}
- VerticalPad
- 0
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 267
-
- ID
- 252
- Points
-
- {102.77960711231492, 265.36292266845703}
- {104.57222405615937, 251.57961654663086}
- {104.55685624578476, 370.8804308665118}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 6
-
-
-
- Bounds
- {{174.23412322998047, 136.22575759887695}, {137.3990421295166, 20}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 245
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-unpack stem cell }
- VerticalPad
- 3
-
-
-
- Bounds
- {{32.07110595703125, 442.85516357421875}, {447.82147216796875, 191}}
- Class
- ShapedGraphic
- ID
- 4
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.950215
- g
- 0.950215
- r
- 0.950215
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.48913
- g
- 0.48913
- r
- 0.48913
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- Bounds
- {{32.07110595703125, 97}, {447.82147216796875, 328.9029541015625}}
- Class
- ShapedGraphic
- ID
- 316
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.950215
- g
- 0.950215
- r
- 0.950215
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.48913
- g
- 0.48913
- r
- 0.48913
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- GridInfo
-
- GuidesLocked
- NO
- GuidesVisible
- YES
- HPages
- 1
- ImageCounter
- 1
- KeepToScale
-
- Layers
-
-
- Lock
- NO
- Name
- Layer 1
- Print
- YES
- View
- YES
-
-
- LayoutInfo
-
- Animate
- NO
- circoMinDist
- 18
- circoSeparation
- 0.0
- layoutEngine
- dot
- neatoSeparation
- 0.0
- twopiSeparation
- 0.0
-
- LinksVisible
- NO
- MagnetsVisible
- NO
- MasterSheets
-
- ModificationDate
- 2013-01-07 08:53:37 +0000
- Modifier
- rajdeepd
- NotesVisible
- NO
- Orientation
- 2
- OriginVisible
- NO
- PageBreaks
- YES
- PrintInfo
-
- NSBottomMargin
-
- float
- 41
-
- NSHorizonalPagination
-
- coded
- BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
-
- NSLeftMargin
-
- float
- 18
-
- NSPaperSize
-
- size
- {612, 792}
-
- NSPrintReverseOrientation
-
- int
- 0
-
- NSRightMargin
-
- float
- 18
-
- NSTopMargin
-
- float
- 18
-
-
- PrintOnePage
-
- ReadOnly
- NO
- RowAlign
- 1
- RowSpacing
- 36
- SheetTitle
- Canvas 1
- SmartAlignmentGuidesActive
- YES
- SmartDistanceGuidesActive
- YES
- UniqueID
- 1
- UseEntirePage
-
- VPages
- 1
- WindowInfo
-
- CurrentSheet
- 0
- ExpandedCanvases
-
-
- name
- Canvas 1
-
-
- Frame
- {{306, 383}, {1144, 1035}}
- ListView
-
- OutlineWidth
- 142
- RightSidebar
-
- ShowRuler
-
- Sidebar
-
- SidebarWidth
- 120
- VisibleRegion
- {{-217, -81}, {1009, 896}}
- Zoom
- 1
- ZoomValues
-
-
- Canvas 1
- 1
- 1
-
-
-
-
-
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_createstemcell.png b/src/bosh_openstack_cpi/docs/images/openstack_cpi_createstemcell.png
deleted file mode 100644
index fa1a3d4b6..000000000
Binary files a/src/bosh_openstack_cpi/docs/images/openstack_cpi_createstemcell.png and /dev/null differ
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_delete_disk.graffle b/src/bosh_openstack_cpi/docs/images/openstack_cpi_delete_disk.graffle
deleted file mode 100644
index 27e082d52..000000000
--- a/src/bosh_openstack_cpi/docs/images/openstack_cpi_delete_disk.graffle
+++ /dev/null
@@ -1,2591 +0,0 @@
-
-
-
-
- ActiveLayerIndex
- 0
- ApplicationVersion
-
- com.omnigroup.OmniGrafflePro
- 139.16.0.171715
-
- AutoAdjust
-
- BackgroundGraphic
-
- Bounds
- {{0, 0}, {576, 733}}
- Class
- SolidGraphic
- ID
- 2
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
-
- BaseZoom
- 0
- CanvasOrigin
- {0, 0}
- ColumnAlign
- 1
- ColumnSpacing
- 36
- CreationDate
- 2012-12-20 10:10:00 +0000
- Creator
- rajdeepd
- DisplayScale
- 1 0/72 in = 1.0000 in
- GraphDocumentVersion
- 8
- GraphicsList
-
-
- Class
- LineGraphic
- Head
-
- ID
- 352
- Info
- 5
-
- ID
- 361
- Points
-
- {401.17249798774725, 590.87644577026367}
- {401.17251533269882, 625.12625503540039}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 327
- Info
- 11
-
-
-
- Bounds
- {{411.4788818359375, 371.12105178833008}, {69, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 360
- Shape
- Rectangle
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.747526
- g
- 0.747526
- r
- 0.747526
-
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs28 \cf0 Fog Gem}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Bounds
- {{329.8382568359375, 117.69060134887695}, {143, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 357
- Shape
- Rectangle
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.747526
- g
- 0.747526
- r
- 0.747526
-
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs28 \cf0 Bosh OpenStack CPI}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 327
-
- ID
- 355
- Points
-
- {271.83918007214896, 625.12625503540039}
- {271.83917236328136, 590.87644577026367}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 352
- Info
- 3
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 352
- Info
- 1
-
- ID
- 353
- Points
-
- {142.50584673881531, 590.87644577026367}
- {142.5058424025774, 625.12625503540039}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 327
- Info
- 15
-
-
-
- Bounds
- {{77.83917236328125, 625.12625503540039}, {388, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 352
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.973627
- g
- 0.992442
- r
- 0.834
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.80124
- g
- 0.886111
- r
- 0.566755
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.850363
- g
- 0.883832
- r
- 0.488493
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Nova Volume}
-
-
-
- Bounds
- {{391.23943129815996, 514.38333824785764}, {20.50001335144043, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 349
- Line
-
- ID
- 347
- Position
- 0.22854259610176086
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.499609
- g
- 0.499609
- r
- 0.499609
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs22 \cf1 4.1}
-
-
-
- Bounds
- {{356.83825420336211, 536.5622626444831}, {89, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 348
- Line
-
- ID
- 347
- Position
- 0.59655618667602539
- RotationType
- 0
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-delete_volume}
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 327
- Info
- 5
-
- ID
- 347
- Points
-
- {401.58332562446594, 510.60985517501831}
- {401.17251533269882, 570.87644577026367}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 326
- Info
- 11
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 326
- Info
- 13
-
- ID
- 346
- Points
-
- {271.83918007214896, 570.87644577026367}
- {272.25, 510.60985517501831}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 327
- Info
- 3
-
-
-
- Bounds
- {{357.47110287626765, 319.62958296221007}, {95, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 345
- Line
-
- ID
- 320
- Position
- 0.22867006063461304
- RotationType
- 0
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-volume.destroy }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Bounds
- {{213.74999332427979, 298.62216384394895}, {20.50001335144043, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 344
- Line
-
- ID
- 313
- Position
- 0.5941430926322937
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.499609
- g
- 0.499609
- r
- 0.499609
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs22 \cf1 1.3}
-
-
-
- Bounds
- {{261.5891530555046, 424.13121193142706}, {20.50001335144043, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 343
- Line
-
- ID
- 313
- Position
- 0.095241762697696686
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.499609
- g
- 0.499609
- r
- 0.499609
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs22 \cf1 1.2}
-
-
-
- Bounds
- {{115.45372619019474, 431.78460850724548}, {53, 20}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 329
- Line
-
- ID
- 332
- Position
- 0.51718384027481079
- RotationType
- 0
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-request }
- VerticalPad
- 3
-
-
-
- Bounds
- {{85.726853482120134, 528.45544369499726}, {114, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 342
- Line
-
- ID
- 328
- Position
- 0.46204021573066711
- RotationType
- 0
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-get_volume_details}
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Bounds
- {{130.8573104004146, 409.08471362464661}, {20.50001335144043, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 340
- Line
-
- ID
- 332
- Position
- 0.092797726392745972
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.499609
- g
- 0.499609
- r
- 0.499609
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs22 \cf1 1.1}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 326
- Info
- 1
-
- ID
- 332
- Points
-
- {140.92223834991455, 414.12107658386236}
- {142.91667003929621, 467.60985517501831}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 330
- Info
- 13
-
-
-
- Bounds
- {{72.22271728515625, 371.1210765838623}, {137.3990421295166, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 330
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.809665
- g
- 0.973391
- r
- 0.992442
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.610953
- g
- 0.706552
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Compute::\
-OpenStack}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 327
- Info
- 1
-
- ID
- 328
- Points
-
- {142.91667437553411, 510.60985517501831}
- {142.5058424025774, 570.87644577026367}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 326
- Info
- 15
-
-
-
- Bounds
- {{77.83917236328125, 570.87644577026367}, {388, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 327
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.809665
- g
- 0.973391
- r
- 0.992442
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.610953
- g
- 0.706552
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Connection}
-
-
-
- Bounds
- {{78.25, 467.60985517501831}, {388, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 326
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.809665
- g
- 0.973391
- r
- 0.992442
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.610953
- g
- 0.706552
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Volume::\
-OpenStack}
-
-
-
- Bounds
- {{395.94126176417643, 290.76525660863206}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 324
- Line
-
- ID
- 320
- Position
- 0.08749021589756012
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 4}
-
-
-
- Bounds
- {{396.92659498116797, 187.56078838154738}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 323
- Line
-
- ID
- 319
- Position
- 0.47858265042304993
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 3}
-
-
-
- Bounds
- {{291.00121830013126, 183.48807290482765}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 322
- Line
-
- ID
- 316
- Position
- 0.38864663243293762
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 2}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 326
- Info
- 5
-
- ID
- 320
- Points
-
- {406.94741427204025, 282.06796756131979}
- {404, 353}
- {391.23943129815996, 353}
- {391.23943129815996, 394}
- {402, 395}
- {401.58334296941757, 467.60985517501831}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 318
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 318
-
- ID
- 319
- Points
-
- {406.74353715284985, 168.08934020996094}
- {407.64842678202399, 228.62527931381771}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{355.79937744140625, 228.92437165484625}, {104.50219710542638, 53.194953918457031}}
- Class
- ShapedGraphic
- ID
- 318
- Shape
- Diamond
- Style
-
- fill
-
- Color
-
- b
- 0.838968
- g
- 0.981553
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.630487
- g
- 0.735237
- r
- 0.99551
-
- Pattern
- 1
-
-
- Text
-
- Align
- 0
- Pad
- 10
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 if available}
- VerticalPad
- 0
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 267
-
- ID
- 317
- Points
-
- {301.25822042059082, 282.09660497491285}
- {301.25855807370016, 301.60726223382159}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 315
-
-
-
- Bounds
- {{275.70430755615234, 302.10726224885184}, {51.106880187988281, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 267
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.992442
- g
- 0.919661
- r
- 0.828059
-
- Draws
- NO
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.994565
- g
- 0.699277
- r
- 0.416525
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.771739
- g
- 0.521768
- r
- 0.477113
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-state}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 315
-
- ID
- 316
- Points
-
- {301.24888911796552, 170.79415314898688}
- {301.25489935371962, 227.89981602737984}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{254.00885009765625, 228.40139191851813}, {94.497802734375, 53.194953918457031}}
- Class
- ShapedGraphic
- ID
- 315
- Shape
- Diamond
- Style
-
- fill
-
- Color
-
- b
- 0.838968
- g
- 0.981553
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.630487
- g
- 0.735237
- r
- 0.99551
-
- Pattern
- 1
-
-
- Text
-
- Align
- 0
- Pad
- 10
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 if volume}
- VerticalPad
- 0
-
-
-
- Bounds
- {{197.5, 267.72855802716356}, {53, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 314
- Line
-
- ID
- 313
- Position
- 0.68335646390914917
- RotationType
- 0
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-volume }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 269
- Info
- 14
-
- ID
- 313
- Points
-
- {272.24387219948841, 467.10989280255512}
- {271, 365.75086008631865}
- {224, 366}
- {224, 208.8050479243775}
- {224, 206.30566164409609}
- {223.08690516849305, 168.08934020996094}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 326
-
-
-
- Bounds
- {{125.97498379313146, 209.03911102896791}, {76, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 308
- Line
-
- ID
- 258
- Position
- 0.2244144082069397
- RotationType
- 0
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-get(disk_id) }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Bounds
- {{130.2283156898869, 293.69275312051423}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 306
- Line
-
- ID
- 258
- Position
- 0.70079588890075684
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 1}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 330
-
- ID
- 258
- Points
-
- {163.85870034111562, 168.08934020996094}
- {164, 230}
- {140, 230}
- {140.92224107978834, 371.1210765838623}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 269
- Info
- 15
-
-
-
- Bounds
- {{104.63043196870763, 150.08934020996094}, {355.36956787109375, 18}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 269
- Magnets
-
- {-0.73960024176586936, -1.1094003915786743}
- {-0.42163697454145743, -1.2649110555648804}
- {1.9868216701487083e-08, -1.3333333730697632}
- {0.4216371064819644, -1.2649110555648804}
- {0.73960031615696409, -1.1094003915786743}
- {1.1094003915786752, -0.73960025003154684}
- {1.2649110555648815, -0.4216368426009538}
- {1.3333333730697643, 1.5894572413799324e-07}
- {1.2649110555648815, 0.42163714417925036}
- {1.1094003915786752, 0.73960034921967122}
- {0.73960021696883971, 1.1094003915786743}
- {0.42163699339010319, 1.2649110555648804}
- {1.1842379282265398e-15, 1.3333333730697632}
- {-0.42163733062650866, 1.2649109363555908}
- {-0.73960021696883826, 1.1094003915786743}
- {-1.1094003915786739, 0.73960034921967122}
- {-1.2649110555648797, 0.42163676720637966}
- {-1.3333333730697625, -6.3578289655197295e-07}
- {-1.2649109363555902, -0.4216371798373757}
- {-1.1094005107879634, -0.73960016419084695}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- VerticalPad
- 3
-
-
-
- Bounds
- {{56, 113.61789512634277}, {72, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 233
- Shape
- Rectangle
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs28 \cf0 Delete Disk}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Bounds
- {{52, 106.99999237060547}, {435, 240}}
- Class
- ShapedGraphic
- ID
- 4
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.950215
- g
- 0.950215
- r
- 0.950215
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.48913
- g
- 0.48913
- r
- 0.48913
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- Bounds
- {{52, 360}, {435, 240}}
- Class
- ShapedGraphic
- ID
- 351
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.950215
- g
- 0.950215
- r
- 0.950215
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.48913
- g
- 0.48913
- r
- 0.48913
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- GridInfo
-
- GuidesLocked
- NO
- GuidesVisible
- YES
- HPages
- 1
- ImageCounter
- 1
- KeepToScale
-
- Layers
-
-
- Lock
- NO
- Name
- Layer 1
- Print
- YES
- View
- YES
-
-
- LayoutInfo
-
- Animate
- NO
- circoMinDist
- 18
- circoSeparation
- 0.0
- layoutEngine
- dot
- neatoSeparation
- 0.0
- twopiSeparation
- 0.0
-
- LinksVisible
- NO
- MagnetsVisible
- NO
- MasterSheets
-
- ModificationDate
- 2013-01-07 09:06:44 +0000
- Modifier
- rajdeepd
- NotesVisible
- NO
- Orientation
- 2
- OriginVisible
- NO
- PageBreaks
- YES
- PrintInfo
-
- NSBottomMargin
-
- float
- 41
-
- NSHorizonalPagination
-
- coded
- BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
-
- NSLeftMargin
-
- float
- 18
-
- NSPaperSize
-
- size
- {612, 792}
-
- NSPrintReverseOrientation
-
- int
- 0
-
- NSRightMargin
-
- float
- 18
-
- NSTopMargin
-
- float
- 18
-
-
- PrintOnePage
-
- ReadOnly
- NO
- RowAlign
- 1
- RowSpacing
- 36
- SheetTitle
- Canvas 1
- SmartAlignmentGuidesActive
- YES
- SmartDistanceGuidesActive
- YES
- UniqueID
- 1
- UseEntirePage
-
- VPages
- 1
- WindowInfo
-
- CurrentSheet
- 0
- ExpandedCanvases
-
-
- name
- Canvas 1
-
-
- Frame
- {{457, 433}, {738, 896}}
- ListView
-
- OutlineWidth
- 142
- RightSidebar
-
- ShowRuler
-
- Sidebar
-
- SidebarWidth
- 120
- VisibleRegion
- {{-14, -12}, {603, 757}}
- Zoom
- 1
- ZoomValues
-
-
- Canvas 1
- 1
- 1
-
-
-
-
-
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_delete_disk.png b/src/bosh_openstack_cpi/docs/images/openstack_cpi_delete_disk.png
deleted file mode 100644
index 1383407c4..000000000
Binary files a/src/bosh_openstack_cpi/docs/images/openstack_cpi_delete_disk.png and /dev/null differ
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_delete_vm.graffle b/src/bosh_openstack_cpi/docs/images/openstack_cpi_delete_vm.graffle
deleted file mode 100644
index ccad8a374..000000000
--- a/src/bosh_openstack_cpi/docs/images/openstack_cpi_delete_vm.graffle
+++ /dev/null
@@ -1,3307 +0,0 @@
-
-
-
-
- ApplicationVersion
-
- com.omnigroup.OmniGraffle7
- 177.6.0.286920
-
- CreationDate
- 2012-12-20 10:10:00 +0000
- Creator
- rajdeepd
- CurrentSheet
- 0
- GraphDocumentVersion
- 13
- GuidesLocked
- NO
- GuidesVisible
- YES
- ImageCounter
- 1
- LinksVisible
- NO
- MagnetsVisible
- NO
- MasterSheets
-
- ModificationDate
- 2017-05-10 08:52:59 +0000
- Modifier
- the openstack cpi user
- MovementHandleVisible
- NO
- NotesVisible
- NO
- OriginVisible
- NO
- PageBreaks
- YES
- PrintInfo
-
- NSBottomMargin
-
- float
- 41
-
- NSHorizonalPagination
-
- coded
- BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
-
- NSLeftMargin
-
- float
- 18
-
- NSPaperSize
-
- size
- {612, 792}
-
- NSPrintReverseOrientation
-
- coded
- BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
-
- NSRightMargin
-
- float
- 18
-
- NSTopMargin
-
- float
- 18
-
-
- ReadOnly
- NO
- Sheets
-
-
- ActiveLayerIndex
- 0
- AutoAdjust
- 6
- BackgroundGraphic
-
- Bounds
- {{0, 0}, {2362.2754491017963, 1477.8443113772455}}
- Class
- ShapedGraphic
- ID
- 2
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
-
- BaseZoom
- 0
- CanvasOrigin
- {0, 0}
- ColumnAlign
- 1
- ColumnSpacing
- 36
- DisplayScale
- 1 in = 1.00000 in
- GraphicsList
-
-
- Class
- LineGraphic
- Head
-
- ID
- 67
- Info
- 3
-
- ID
- 68
- Points
-
- {581.84509602405478, 248.47556370438667}
- {581.84509783168482, 292.46091196601253}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 21
- Info
- 1
-
-
-
- Bounds
- {{536.35459843494345, 292.46091196601253}, {90.980995178222656, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 67
- Magnets
-
- {-0.73960024176586991, -1.1094003915786763}
- {-0.42163697454145854, -1.2649110555648826}
- {1.9868215517249155e-08, -1.3333333730697656}
- {0.42163710648196329, -1.2649110555648826}
- {0.73960031615696287, -1.1094003915786763}
- {1.1094003915786741, -0.73960025003154883}
- {1.2649110555648801, -0.42163684260095602}
- {1.333333373069763, 1.5894572413799324e-07}
- {1.2649110555648801, 0.42163714417925036}
- {1.1094003915786741, 0.73960034921967122}
- {0.73960021696883849, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650977, 1.2649109363555908}
- {-0.73960021696883882, 1.1094003915786743}
- {-1.1094003915786743, 0.73960034921967122}
- {-1.2649110555648804, 0.42163676720637966}
- {-1.3333333730697632, -6.3578289655197295e-07}
- {-1.2649109363555908, -0.42163717983737792}
- {-1.1094005107879639, -0.73960016419084895}
-
- Style
-
- fill
-
- Color
-
- b
- 0.99431599999999998
- g
- 0.93638699999999997
- r
- 0.85887400000000003
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.996609
- g
- 0.75748
- r
- 0.483699
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.81430899999999995
- g
- 0.60083900000000001
- r
- 0.54992300000000005
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-RegistryClient}
-
-
-
- Bounds
- {{560.77295653676038, 173.69504708450529}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 65
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326100000000002
- g
- 0.573268
- r
- 0.57325499999999996
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 6}
-
-
-
- Class
- LineGraphic
- ID
- 64
- Points
-
- {470.49467563065025, 407.53063163139001}
- {470.49467563065025, 460.07998931407928}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 43
- Info
- 1
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 43
-
- ID
- 63
- Points
-
- {470.49467563065025, 335.46091196601247}
- {470.49467563065025, 373.03063163139001}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 59
- Info
- 13
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 59
- Info
- 3
-
- ID
- 62
- Points
-
- {470.4946878878157, 258.57304653460614}
- {470.4946878878157, 291.96091196601253}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 60
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 60
-
- ID
- 61
- Points
-
- {470.49467563065025, 168.08934020996094}
- {470.49467563065025, 204.37808674515816}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{414.96577444853517, 204.87808674515816}, {111.05780236423016, 53.194953918457031}}
- Class
- ShapedGraphic
- ID
- 60
- Shape
- Diamond
- Style
-
- fill
-
- Color
-
- b
- 0.86940200000000001
- g
- 0.98219100000000004
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.69062800000000002
- g
- 0.78484600000000004
- r
- 1
- space
- srgb
-
- Pattern
- 1
-
-
- Text
-
- Pad
- 10
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 if lbaas pool tags}
- VerticalPad
- 0.0
-
-
-
- Bounds
- {{425.00417804153892, 292.46091196601253}, {90.980995178222656, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 59
- Magnets
-
- {-0.73960024176586991, -1.1094003915786763}
- {-0.42163697454145854, -1.2649110555648826}
- {1.9868215517249155e-08, -1.3333333730697656}
- {0.42163710648196329, -1.2649110555648826}
- {0.73960031615696287, -1.1094003915786763}
- {1.1094003915786741, -0.73960025003154883}
- {1.2649110555648801, -0.42163684260095602}
- {1.333333373069763, 1.5894572413799324e-07}
- {1.2649110555648801, 0.42163714417925036}
- {1.1094003915786741, 0.73960034921967122}
- {0.73960021696883849, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650977, 1.2649109363555908}
- {-0.73960021696883882, 1.1094003915786743}
- {-1.1094003915786743, 0.73960034921967122}
- {-1.2649110555648804, 0.42163676720637966}
- {-1.3333333730697632, -6.3578289655197295e-07}
- {-1.2649109363555908, -0.42163717983737792}
- {-1.1094005107879639, -0.73960016419084895}
-
- Style
-
- fill
-
- Color
-
- b
- 0.99431599999999998
- g
- 0.93638699999999997
- r
- 0.85887400000000003
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.996609
- g
- 0.75748
- r
- 0.483699
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.81430899999999995
- g
- 0.60083900000000001
- r
- 0.54992300000000005
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-LoadbalancerConfigurator}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 14
-
- ID
- 58
- Points
-
- {356.73876678261661, 335.46091196601253}
- {356.85805944728719, 380.03063163138995}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Class
- LineGraphic
- ID
- 57
- Points
-
- {356.85805944728719, 400.53063163138995}
- {356.85805944728719, 460.07998931407928}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 14
- Info
- 1
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 24
-
- ID
- 56
- Points
-
- {137.66272781872229, 168.08934020996094}
- {137.66272781872229, 380.03063163138995}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Class
- LineGraphic
- ID
- 55
- Points
-
- {246.44650554665913, 400.53063163138995}
- {246.44650554665913, 460.07998931407928}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 53
- Info
- 13
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 53
- Info
- 3
-
- ID
- 54
- Points
-
- {246.44650554665913, 335.46091196601253}
- {246.44650554665918, 380.03063163138995}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{199.19760036477442, 380.03063163138995}, {94.497810363769531, 20}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 53
- Magnets
-
- {-0.73960026163363846, -1.1094003924504587}
- {-0.42163702135578457, -1.2649110640673515}
- {0, -1.3333333333333333}
- {0.42163702135578457, -1.2649110640673515}
- {0.73960026163363846, -1.1094003924504587}
- {1.1094003924504556, -0.73960026163364234}
- {1.2649110640673535, -0.42163702135577852}
- {1.3333333333333333, 0}
- {1.2649110640673509, 0.42163702135578662}
- {1.1094003924504556, 0.73960026163364234}
- {0.73960026163363846, 1.1094003924504587}
- {0.42163702135578257, 1.2649110640673522}
- {0, 1.3333333333333333}
- {-0.42163702135578257, 1.2649110640673522}
- {-0.73960026163363846, 1.1094003924504587}
- {-1.1094003924504556, 0.73960026163364234}
- {-1.2649110640673509, 0.42163702135578662}
- {-1.3333333333333333, 0}
- {-1.2649110640673535, -0.42163702135577852}
- {-1.1094003924504556, -0.73960026163364234}
-
- Style
-
- fill
-
- Color
-
- b
- 0.86827900000000002
- g
- 0.98061799999999999
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250200000000003
- g
- 0.74964200000000003
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-ports.all(server)}
- VerticalPad
- 3
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 51
-
- ID
- 52
- Points
-
- {301.65228656815663, 258.57304261364851}
- {301.65228656815663, 292.46091196601253}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 47
-
-
-
- Bounds
- {{199.19760036477442, 292.46091196601253}, {204.9093642643976, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 51
- Magnets
-
- {-0.73960024176586991, -1.1094003915786763}
- {-0.42163697454145854, -1.2649110555648826}
- {1.9868215517249155e-08, -1.3333333730697656}
- {0.42163710648196329, -1.2649110555648826}
- {0.73960031615696287, -1.1094003915786763}
- {1.1094003915786741, -0.73960025003154883}
- {1.2649110555648801, -0.42163684260095602}
- {1.333333373069763, 1.5894572413799324e-07}
- {1.2649110555648801, 0.42163714417925036}
- {1.1094003915786741, 0.73960034921967122}
- {0.73960021696883849, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650977, 1.2649109363555908}
- {-0.73960021696883882, 1.1094003915786743}
- {-1.1094003915786743, 0.73960034921967122}
- {-1.2649110555648804, 0.42163676720637966}
- {-1.3333333730697632, -6.3578289655197295e-07}
- {-1.2649109363555908, -0.42163717983737792}
- {-1.1094005107879639, -0.73960016419084895}
-
- Style
-
- fill
-
- Color
-
- b
- 0.99431599999999998
- g
- 0.93638699999999997
- r
- 0.85887400000000003
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.996609
- g
- 0.75748
- r
- 0.483699
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.81430899999999995
- g
- 0.60083900000000001
- r
- 0.54992300000000005
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-NetworkConfigurator}
-
-
-
- Class
- LineGraphic
- ID
- 46
- Points
-
- {68.186345486850087, 248.4755637043867}
- {68.186345486850087, 460.07998931407928}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 45
-
-
-
- Bounds
- {{31.466346307606045, 214.47556370438667}, {73.439998358488083, 34}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 45
- Magnets
-
- {-0.73960026163363879, -1.1094003924504581}
- {-0.42163702135578413, -1.2649110640673518}
- {0, -1.3333333333333333}
- {0.42163702135578357, -1.2649110640673518}
- {0.73960026163363857, -1.1094003924504581}
- {1.1094003924504596, -0.73960026163363712}
- {1.2649110640673509, -0.42163702135578662}
- {1.3333333333333333, 0}
- {1.2649110640673509, 0.42163702135578662}
- {1.1094003924504596, 0.73960026163363712}
- {0.73960026163363846, 1.1094003924504587}
- {0.42163702135578357, 1.2649110640673518}
- {0, 1.3333333333333333}
- {-0.42163702135578357, 1.2649110640673518}
- {-0.73960026163363846, 1.1094003924504587}
- {-1.1094003924504596, 0.73960026163363712}
- {-1.2649110640673509, 0.42163702135578662}
- {-1.3333333333333333, 0}
- {-1.2649110640673509, -0.42163702135578662}
- {-1.1094003924504596, -0.73960026163363712}
-
- Style
-
- fill
-
- Color
-
- b
- 0.86827900000000002
- g
- 0.98061799999999999
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250200000000003
- g
- 0.74964200000000003
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-servers.get\
-(server_id) }
- VerticalPad
- 3
-
-
-
- Bounds
- {{47.427543542251726, 173.69504708450529}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 44
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326100000000002
- g
- 0.573268
- r
- 0.57325499999999996
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 1}
-
-
-
- Bounds
- {{425.00417804153892, 373.03063163138995}, {90.980995178222656, 34}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 43
- Magnets
-
- {0, 1}
- {0, -1}
-
- Style
-
- fill
-
- Color
-
- b
- 0.86827900000000002
- g
- 0.98061799999999999
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250200000000003
- g
- 0.74964200000000003
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-delete_lbaas_pool_member}
- VerticalPad
- 3
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 20
- Info
- 3
-
- ID
- 5
- Points
-
- {357.59138679226805, 565.81194040134687}
- {357.59138999800012, 611.97192305281897}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 19
- Info
- 13
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 19
-
- ID
- 6
- Points
-
- {357.591386792268, 503.07998931407923}
- {357.59138999800012, 545.81194040134687}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 18
- Info
- 13
-
-
-
- Bounds
- {{336.46604092806689, 344.15999230742455}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 8
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326096296310425
- g
- 0.57326847314834595
- r
- 0.57325458526611328
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 4}
-
-
-
- Bounds
- {{116.93262445268985, 173.69504708450529}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 9
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326096296310425
- g
- 0.57326847314834595
- r
- 0.57325458526611328
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 3}
-
-
-
- Class
- LineGraphic
- ID
- 12
- Points
-
- {137.66272781872229, 400.53063163138995}
- {137.66272781872229, 460.07998931407928}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 24
-
-
-
- Bounds
- {{309.60915426540242, 380.03063163138995}, {94.497810363769531, 20}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 14
- Magnets
-
- {0, 1}
- {0, -1}
-
- Style
-
- fill
-
- Color
-
- b
- 0.8682788610458374
- g
- 0.9806181788444519
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250247716903687
- g
- 0.74964249134063721
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-port.destroy}
- VerticalPad
- 3
-
-
-
- Bounds
- {{225.58604340642808, 344.15999230742455}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 15
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326096296310425
- g
- 0.57326847314834595
- r
- 0.57325458526611328
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 2}
-
-
-
- Bounds
- {{199.19760036477442, 460.07998931407928}, {316.78757285498716, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 18
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Style
-
- fill
-
- Color
-
- b
- 0.84499651193618774
- g
- 0.97522002458572388
- r
- 0.99423378705978394
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.624103
- g
- 0.822736
- r
- 0.999357
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.67316055297851562
- g
- 0.76121300458908081
- r
- 1
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::OpenStack::Network}
-
-
-
- Bounds
- {{276.91650044287871, 545.81194040134687}, {161.34977269877859, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 19
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Style
-
- fill
-
- Color
-
- b
- 0.84499651193618774
- g
- 0.97522002458572388
- r
- 0.99423378705978394
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.624103
- g
- 0.822736
- r
- 0.999357
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.67316055297851562
- g
- 0.76121300458908081
- r
- 1
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Connection}
-
-
-
- Bounds
- {{276.91650044287871, 611.97192305281897}, {161.34977269877859, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 20
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Style
-
- fill
-
- Color
-
- b
- 0.97923249006271362
- g
- 0.99126559495925903
- r
- 0.86211967468261719
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.838662
- g
- 0.902049
- r
- 0.624939
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.87963306903839111
- g
- 0.90069097280502319
- r
- 0.54882305860519409
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Neutron Network}
-
-
-
- Bounds
- {{536.35459843494345, 214.47556370438667}, {90.980995178222656, 34}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 21
- Magnets
-
- {0, 1}
- {0, -1}
-
- Style
-
- fill
-
- Color
-
- b
- 0.8682788610458374
- g
- 0.9806181788444519
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250247716903687
- g
- 0.74964249134063721
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-delete_settings(server.name) }
- VerticalPad
- 3
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 31
-
- ID
- 23
- Points
-
- {108.1247879488476, 503.07998931407928}
- {108.1247911545797, 545.81194040134687}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 30
- Info
- 13
-
-
-
- Bounds
- {{90.413822636837523, 380.03063163138995}, {94.497810363769531, 20}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 24
- Magnets
-
- {0, 1}
- {0, -1}
-
- Style
-
- fill
-
- Color
-
- b
- 0.8682788610458374
- g
- 0.9806181788444519
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250247716903687
- g
- 0.74964249134063721
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-server.destroy }
- VerticalPad
- 3
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 29
- Info
- 3
-
- ID
- 26
- Points
-
- {108.12478794884764, 565.81194040134687}
- {108.1247911545797, 611.97192305281897}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 31
- Info
- 13
-
-
-
- Bounds
- {{558.37774695592179, 446.39999002218246}, {69, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 27
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.79315453767776489
- g
- 0.79316467046737671
- r
- 0.79314583539962769
- space
- srgb
-
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs28 \cf0 Fog Gem}
- VerticalPad
- 0.0
-
- Wrap
- NO
-
-
- Bounds
- {{484.33559361316611, 117.35999737679958}, {143, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 28
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.79315453767776489
- g
- 0.79316467046737671
- r
- 0.79314583539962769
- space
- srgb
-
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs28 \cf0 Bosh OpenStack CPI}
- VerticalPad
- 0.0
-
- Wrap
- NO
-
-
- Bounds
- {{27.4499015994583, 611.97192305281897}, {161.34977269877859, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 29
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Style
-
- fill
-
- Color
-
- b
- 0.97923249006271362
- g
- 0.99126559495925903
- r
- 0.86211967468261719
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.838662
- g
- 0.902049
- r
- 0.624939
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.87963306903839111
- g
- 0.90069097280502319
- r
- 0.54882305860519409
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Nova Compute}
-
-
-
- Bounds
- {{31.929580017568242, 460.07998931407928}, {152.39041586255871, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 30
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Style
-
- fill
-
- Color
-
- b
- 0.84499651193618774
- g
- 0.97522002458572388
- r
- 0.99423378705978394
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.624103
- g
- 0.822736
- r
- 0.999357
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.67316055297851562
- g
- 0.76121300458908081
- r
- 1
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Compute::OpenStack}
-
-
-
- Bounds
- {{27.4499015994583, 545.81194040134687}, {161.34977269877859, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 31
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Style
-
- fill
-
- Color
-
- b
- 0.84499651193618774
- g
- 0.97522002458572388
- r
- 0.99423378705978394
- space
- srgb
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.624103
- g
- 0.822736
- r
- 0.999357
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.67316055297851562
- g
- 0.76121300458908081
- r
- 1
- space
- srgb
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Connection}
-
-
-
- Bounds
- {{449.75739032987252, 172.79999613761902}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 32
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.57326096296310425
- g
- 0.57326847314834595
- r
- 0.57325458526611328
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 5}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 21
- Info
- 2
-
- ID
- 49
- Points
-
- {581.84509602405478, 168.08934020996094}
- {581.84509602405478, 213.97556370438667}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 47
-
- ID
- 48
- Points
-
- {301.65228249697321, 168.08934020996094}
- {301.65228249697321, 204.37808674515816}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{246.12338131485814, 204.87808674515816}, {111.05780236423016, 53.194953918457031}}
- Class
- ShapedGraphic
- ID
- 47
- Shape
- Diamond
- Style
-
- fill
-
- Color
-
- b
- 0.86940175294876099
- g
- 0.98219138383865356
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.69062763452529907
- g
- 0.78484636545181274
- r
- 1
- space
- srgb
-
- Pattern
- 1
-
-
- Text
-
- Pad
- 10
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 if neutron networking}
- VerticalPad
- 0.0
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 45
- Info
- 3
-
- ID
- 38
- Points
-
- {68.186345486850087, 168.08934020996094}
- {68.186345486850087, 213.9755637043867}
-
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{31.929580017568242, 150.08934020996094}, {595.40601359559787, 18}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 39
- Magnets
-
- {-0.73960024176586936, -1.1094003915786743}
- {-0.42163697454145743, -1.2649110555648804}
- {1.9868216701487083e-08, -1.3333333730697632}
- {0.4216371064819644, -1.2649110555648804}
- {0.73960031615696409, -1.1094003915786743}
- {1.1094003915786752, -0.73960025003154684}
- {1.2649110555648815, -0.4216368426009538}
- {1.3333333730697643, 1.5894572413799324e-07}
- {1.2649110555648815, 0.42163714417925036}
- {1.1094003915786752, 0.73960034921967122}
- {0.73960021696883971, 1.1094003915786743}
- {0.42163699339010319, 1.2649110555648804}
- {1.1842379282265398e-15, 1.3333333730697632}
- {-0.42163733062650866, 1.2649109363555908}
- {-0.73960021696883826, 1.1094003915786743}
- {-1.1094003915786739, 0.73960034921967122}
- {-1.2649110555648797, 0.42163676720637966}
- {-1.3333333730697625, -6.3578289655197295e-07}
- {-1.2649109363555902, -0.4216371798373757}
- {-1.1094005107879634, -0.73960016419084695}
-
- Style
-
- fill
-
- Color
-
- b
- 0.8682788610458374
- g
- 0.9806181788444519
- r
- 1
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.65250247716903687
- g
- 0.74964249134063721
- r
- 1
- space
- srgb
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- VerticalPad
- 3
-
-
-
- Bounds
- {{31.929580017568242, 113.75999745726585}, {66, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 40
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0.0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf820
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-{\*\expandedcolortbl;;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs28 \cf0 Delete VM}
- VerticalPad
- 0.0
-
- Wrap
- NO
-
-
- Bounds
- {{12.959999710321426, 105.07173349007826}, {629.99998591840267, 312.27630473673344}}
- Class
- ShapedGraphic
- ID
- 41
- IsLocked
- YES
- Style
-
- fill
-
- Color
-
- b
- 0.96036380529403687
- g
- 0.96037584543228149
- r
- 0.96035343408584595
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.56205445528030396
- g
- 0.56206178665161133
- r
- 0.56204819679260254
- space
- srgb
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- Bounds
- {{12.959999710321426, 439.21112973988056}, {629.99998591840267, 138.64607906341553}}
- Class
- ShapedGraphic
- ID
- 42
- IsLocked
- YES
- Style
-
- fill
-
- Color
-
- b
- 0.96036380529403687
- g
- 0.96037584543228149
- r
- 0.96035343408584595
- space
- srgb
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.56205445528030396
- g
- 0.56206178665161133
- r
- 0.56204819679260254
- space
- srgb
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- GridInfo
-
- HPages
- 2
- KeepToScale
-
- Layers
-
-
- Artboards
-
- Lock
-
- Name
- Layer 1
- Print
-
- View
-
-
-
- LayoutInfo
-
- Animate
- NO
- circoMinDist
- 18
- circoSeparation
- 0.0
- layoutEngine
- dot
- neatoLineLength
- 0.20000000298023224
- neatoSeparation
- 0.0
- twopiSeparation
- 0.0
-
- Orientation
- 2
- PrintOnePage
-
- RowAlign
- 1
- RowSpacing
- 36
- SheetTitle
- Canvas 1
- UniqueID
- 1
- VPages
- 1
- VisibleVoidKey
- 1
-
-
- SmartAlignmentGuidesActive
- YES
- SmartDistanceGuidesActive
- YES
- UseEntirePage
-
- WindowInfo
-
- Frame
- {{-0, -0}, {2555, 1417}}
- ShowInfo
-
- ShowRuler
-
- Sidebar
-
- SidebarWidth
- 200
- Sidebar_Tab
- 0
- VisibleRegion
- {{-201.79640718562874, 65.269461077844227}, {1210.7784431137725, 744.91017964071864}}
- ZoomValues
-
-
- Canvas 1
- 1.6699999999999999
- 1
-
-
-
- compressOnDiskKey
-
- copyLinkedImagesKey
-
- createSinglePDFKey
-
- exportAreaKey
- 0
- exportQualityKey
- 100
- exportSizesKey
-
- 1
-
-
- fileFormatKey
- 0
- htmlImageTypeKey
- 0
- includeBackgroundGraphicKey
-
- includeNonPrintingLayersKey
-
- lastExportTypeKey
- 0
- marginWidthKey
- 0.0
- previewTypeKey
- 0
- readOnlyKey
-
- resolutionForBMPKey
- 1
- resolutionForGIFKey
- 1
- resolutionForHTMLKey
- 1
- resolutionForJPGKey
- 1
- resolutionForPNGKey
- 1
- resolutionForTIFFKey
- 1
- resolutionUnitsKey
- 0
- saveAsFlatFileOptionKey
- 3
- useArtboardsKey
-
- useMarginKey
-
- useNotesKey
-
-
-
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_delete_vm.png b/src/bosh_openstack_cpi/docs/images/openstack_cpi_delete_vm.png
deleted file mode 100644
index 5aa411ab4..000000000
Binary files a/src/bosh_openstack_cpi/docs/images/openstack_cpi_delete_vm.png and /dev/null differ
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_deletestemcell.graffle b/src/bosh_openstack_cpi/docs/images/openstack_cpi_deletestemcell.graffle
deleted file mode 100644
index cdae6d791..000000000
--- a/src/bosh_openstack_cpi/docs/images/openstack_cpi_deletestemcell.graffle
+++ /dev/null
@@ -1,3939 +0,0 @@
-
-
-
-
- ActiveLayerIndex
- 0
- ApplicationVersion
-
- com.omnigroup.OmniGrafflePro
- 139.16.0.171715
-
- AutoAdjust
-
- BackgroundGraphic
-
- Bounds
- {{0, 0}, {576, 733}}
- Class
- SolidGraphic
- ID
- 2
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
-
- BaseZoom
- 0
- CanvasOrigin
- {0, 0}
- ColumnAlign
- 1
- ColumnSpacing
- 36
- CreationDate
- 2012-12-26 07:23:41 +0000
- Creator
- rajdeepd
- DisplayScale
- 1 0/72 in = 1.0000 in
- GraphDocumentVersion
- 8
- GraphicsList
-
-
- Class
- LineGraphic
- Head
-
- ID
- 352
-
- ID
- 361
- Points
-
- {259.2294129214248, 572.2193717956543}
- {259.49494179089896, 601.49496459960938}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 335
- Info
- 13
-
-
-
- Bounds
- {{425.70345497131348, 506.87995052337646}, {20.50001335144043, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 345
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.499609
- g
- 0.499609
- r
- 0.499609
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs22 \cf1 6.1}
-
-
-
- Bounds
- {{393.99837303161621, 502.87994861602783}, {27.579854965209961, 28}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 344
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.499609
- g
- 0.499609
- r
- 0.499609
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs22 \cf1 10.1}
-
-
-
- Bounds
- {{360.77123069763184, 502.87994861602783}, {27.579854965209961, 28}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 343
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.499609
- g
- 0.499609
- r
- 0.499609
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs22 \cf1 11.1}
-
-
-
- Bounds
- {{101.00509071350098, 547.43933773040771}, {20.50001335144043, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 342
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.499609
- g
- 0.499609
- r
- 0.499609
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs22 \cf1 8.1}
-
-
-
- Bounds
- {{101.00509071350098, 527.43934345245361}, {20.50001335144043, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 341
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.499609
- g
- 0.499609
- r
- 0.499609
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs22 \cf1 4.1}
-
-
-
- Bounds
- {{101.00509071350098, 506.71967506408691}, {20.50001335144043, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 340
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.499609
- g
- 0.499609
- r
- 0.499609
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs22 \cf1 1.1}
-
-
-
- Bounds
- {{260.84931208787555, 506.87994081245938}, {87.159675598144531, 20}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 339
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-delete_image}
- VerticalPad
- 3
-
-
-
- Class
- LineGraphic
- ID
- 338
- Points
-
- {301.49801275322432, 493.719970703125}
- {300.72002753284085, 552.21936416625977}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{121.50510432420367, 506.87994081245938}, {118.38997052015668, 20}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 337
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-get_image_by_id}
- VerticalPad
- 3
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 335
- Info
- 1
-
- ID
- 336
- Points
-
- {188.2380029875992, 493.71997833251953}
- {187.46001776721582, 552.2193717956543}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 293
- Info
- 14
-
-
-
- Bounds
- {{151.57531738281239, 552.2193717956543}, {215.30819107722482, 20}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 335
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145854, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696264, -1.1094003915786743}
- {0.5, -0.3333333283662796}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {0.5, 0.33333337306976318}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650977, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.5, 0.33333337306976318}
- {-1.2649110555648804, 0.42163676720637966}
- {-1.3333333730697632, -6.3578289655197295e-07}
- {-1.2649109363555908, -0.4216371798373757}
- {-0.5, -0.33333325386047363}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.809665
- g
- 0.973391
- r
- 0.992442
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.610953
- g
- 0.706552
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Connection}
-
-
-
- Bounds
- {{59.724312253463722, 461.71997833251953}, {385.54123306274414, 32}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 293
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145854, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786745, -0.73960025003154684}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {1.1094003915786745, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650977, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-1.1094003915786743, 0.73960034921967122}
- {-1.2649110555648804, 0.42163676720637966}
- {-1.3333333730697632, -6.3578289655197295e-07}
- {-1.2649109363555908, -0.4216371798373757}
- {-1.1094005107879639, -0.73960016419084695}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.809665
- g
- 0.973391
- r
- 0.992442
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.610953
- g
- 0.706552
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Image::OpenStack}
-
-
-
- Bounds
- {{150.00381925746689, 246.70429252876107}, {20.50001335144043, 20.89453125}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 334
- Line
-
- ID
- 332
- Position
- 0.561756432056427
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 11\
-}
- VerticalPad
- 0
-
- TextPlacement
- 0
- Wrap
- NO
-
-
- Bounds
- {{123.11460257140507, 136.32182998258111}, {72.418045043945312, 19}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- FontInfo
-
- Color
-
- b
- 0.0197765
- g
- 0.0245039
- r
- 0.5
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 333
- Line
-
- ID
- 332
- Position
- 0.10683052241802216
- RotationType
- 0
-
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;\red128\green6\blue5;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs22 \cf2 destroy}
- VerticalPad
- 3
-
-
-
- Class
- LineGraphic
- ID
- 332
- Points
-
- {159.10518547592551, 119.67820358276367}
- {161.14991588169363, 364.39877414703369}
-
- Style
-
- stroke
-
- Color
-
- a
- 0.78
- b
- 0.0803854
- g
- 0.00920142
- r
- 0.5
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{424.76553196476749, 243.46534448559515}, {20.50001335144043, 20.89453125}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 331
- Line
-
- ID
- 329
- Position
- 0.54129225015640259
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 10\
-}
- VerticalPad
- 0
-
- TextPlacement
- 0
- Wrap
- NO
-
-
- Bounds
- {{397.91815901366584, 137.14362639981744}, {72.418045043945312, 19}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- FontInfo
-
- Color
-
- b
- 0.0197765
- g
- 0.0245039
- r
- 0.5
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 330
- Line
-
- ID
- 329
- Position
- 0.10683052241802216
- RotationType
- 0
-
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;\red128\green6\blue5;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs22 \cf2 destroy}
- VerticalPad
- 3
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 326
- Info
- 3
-
- ID
- 329
- Points
-
- {433.90874191818625, 120.5}
- {435.95347232395437, 365.22057056427002}
-
- Style
-
- stroke
-
- Color
-
- a
- 0.78
- b
- 0.0803854
- g
- 0.00920142
- r
- 0.5
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{401.0782065987587, 420.22027267906503}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 328
- Line
-
- ID
- 327
- Position
- 0.57514631748199463
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 9}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 326
- Info
- 13
-
- ID
- 327
- Points
-
- {381.00854704543423, 461.21997834212675}
- {381, 429.7202764937623}
- {436, 429.7202764937623}
- {435.95455317129966, 408.72056940309682}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 293
- Info
- 5
-
-
-
- Bounds
- {{404.93446245489508, 365.22057056427002}, {62.038017272949219, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 326
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145854, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650977, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-1.1094003915786743, 0.73960034921967122}
- {-1.2649110555648804, 0.42163676720637966}
- {-1.3333333730697632, -6.3578289655197295e-07}
- {-1.2649109363555908, -0.4216371798373757}
- {-1.1094005107879639, -0.73960016419084695}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.992442
- g
- 0.919661
- r
- 0.828059
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.994565
- g
- 0.699277
- r
- 0.416525
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.771739
- g
- 0.521768
- r
- 0.477113
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-ramdisk}
-
-
-
- Bounds
- {{281.22001016230564, 245.35986736114256}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 325
- Line
-
- ID
- 323
- Position
- 0.54129225015640259
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 6}
-
-
-
- Bounds
- {{254.88374094237963, 137.51753322828051}, {72.418045043945312, 19}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- FontInfo
-
- Color
-
- b
- 0.0197765
- g
- 0.0245039
- r
- 0.5
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 324
- Line
-
- ID
- 323
- Position
- 0.10683052241802216
- RotationType
- 0
-
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;\red128\green6\blue5;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs22 \cf2 destroy}
- VerticalPad
- 3
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 308
- Info
- 3
-
- ID
- 323
- Points
-
- {291, 120.5}
- {291.8683236050212, 368.72057056427002}
-
- Style
-
- stroke
-
- Color
-
- a
- 0.78
- b
- 0.0803854
- g
- 0.00920142
- r
- 0.5
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Class
- LineGraphic
- ID
- 320
- Points
-
- {359.90933374647898, 227.00019342994034}
- {359.90889600180054, 256.75954694873474}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{323.3911497497665, 265.61307203436911}, {73, 28}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 319
- Shape
- Rectangle
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Find ramdisk \
-Image}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Bounds
- {{323.39115250309965, 301.70122909545898}, {72.418045043945312, 32}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 318
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs22 \cf0 find_by_id(\
-ramdisk_id)}
- VerticalPad
- 3
-
-
-
- Bounds
- {{327.22814711286901, 434.01422825908537}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 317
- Line
-
- ID
- 315
- Offset
- 1
- Position
- 0.76141887903213501
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 8}
-
-
-
- Bounds
- {{350.60865380000303, 133.36906015872955}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 316
- Line
-
- ID
- 321
- Position
- 0.434273362159729
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 7}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 293
- Info
- 4
-
- ID
- 315
- Points
-
- {359.89663658065717, 345.39045970338992}
- {359.90889600180054, 444}
- {316.31131362915039, 445}
- {316.75181436698813, 461.71997833251947}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 314
-
-
-
- Bounds
- {{316.31131362915039, 257.65001934766769}, {87.159675598144531, 87.240440368652344}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 314
- Shape
- Rectangle
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.771739
- g
- 0.521768
- r
- 0.477113
-
- CornerRadius
- 9
-
-
-
-
- Bounds
- {{306.99999809265137, 169.90017604827881}, {105, 56.99029541015625}}
- Class
- ShapedGraphic
- ID
- 313
- Shape
- Diamond
- Style
-
- fill
-
- Color
-
- b
- 0.838968
- g
- 0.981553
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.630487
- g
- 0.735237
- r
- 0.99551
-
- Pattern
- 1
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 if image and ramdisk_id}
- VerticalPad
- 0
-
-
-
- Bounds
- {{274.93479272081339, 429.7202764937623}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 312
- Line
-
- ID
- 311
- Position
- 0.57514631748199463
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 5}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 308
- Info
- 13
-
- ID
- 311
- Points
-
- {260.70902741154691, 461}
- {260.70902741154691, 440}
- {292, 439.00316984854919}
- {291.87073556064973, 412.22056474124122}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{192.05619262696376, 265.61307203436911}, {65, 28}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 310
- Shape
- Rectangle
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Find Kernel \
-Image}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Bounds
- {{61.104372963309288, 226.73976909989153}, {73, 28}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 309
- Line
-
- ID
- 296
- Position
- 0.32375586032867432
- RotationType
- 0
-
- Shape
- Rectangle
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Find Stemcell\
- Image}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Bounds
- {{260.84931373596191, 368.72057056427002}, {62.038017272949219, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 308
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145854, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650977, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-1.1094003915786743, 0.73960034921967122}
- {-1.2649110555648804, 0.42163676720637966}
- {-1.3333333730697632, -6.3578289655197295e-07}
- {-1.2649109363555908, -0.4216371798373757}
- {-1.1094005107879639, -0.73960016419084695}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.992442
- g
- 0.919661
- r
- 0.828059
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.994565
- g
- 0.699277
- r
- 0.416525
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.771739
- g
- 0.521768
- r
- 0.477113
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-kernel}
-
-
-
- Bounds
- {{188.2909823676016, 301.70123672485352}, {72.418045043945312, 32}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 307
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs22 \cf0 find_by_id(\
-kernel_id)}
- VerticalPad
- 3
-
-
-
- Bounds
- {{141.78015182421683, 425.04688819690057}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 306
- Line
-
- ID
- 305
- Position
- 0.47938805818557739
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 2}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 304
- Info
- 13
-
- ID
- 305
- Points
-
- {151.57531738281239, 458}
- {152.52411270141602, 409.07698440551758}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{121.50510406494141, 366.07698440551758}, {62.038017272949219, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 304
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145854, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650977, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-1.1094003915786743, 0.73960034921967122}
- {-1.2649110555648804, 0.42163676720637966}
- {-1.3333333730697632, -6.3578289655197295e-07}
- {-1.2649109363555908, -0.4216371798373757}
- {-1.1094005107879639, -0.73960016419084695}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.992442
- g
- 0.919661
- r
- 0.828059
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.994565
- g
- 0.699277
- r
- 0.416525
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.771739
- g
- 0.521768
- r
- 0.477113
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-image}
-
-
-
- Bounds
- {{61.247077211737633, 269.05370825361683}, {72.418045043945312, 32}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 11
-
- ID
- 302
- Line
-
- ID
- 296
- Position
- 0.44509318470954895
- RotationType
- 0
-
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural
-
-\f0\fs22 \cf0 find_by_id(\
-stemcell_id)}
- VerticalPad
- 3
-
-
-
- Bounds
- {{50.672644689723043, 220.97900705650756}, {93.686903804452839, 92.287269592285156}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 303
- Line
-
- ID
- 296
- Position
- 0.3959956169128418
- RotationType
- 0
-
- Shape
- Rectangle
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.771739
- g
- 0.521768
- r
- 0.477113
-
- CornerRadius
- 9
-
-
-
-
- Bounds
- {{87.529612325131893, 178.86455051711718}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 297
- Line
-
- ID
- 296
- Position
- 0.18034569919109344
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 1}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 293
- Info
- 1
-
- ID
- 296
- Points
-
- {98, 122.5}
- {97, 421.36675614722321}
- {123.11460257140507, 421}
- {123.97054940393325, 461.2200915206455}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{47, 67.630931854248047}, {99, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 291
- Shape
- Rectangle
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs28 \cf0 Delete Stemcell}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Bounds
- {{182.36217166700192, 420.33999396768849}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 275
- Line
-
- ID
- 268
- Offset
- 1
- Position
- 0.76795053482055664
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 4}
-
-
-
- Bounds
- {{215.25509738922119, 131.01610314846039}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 299
- Line
-
- ID
- 298
- Position
- 0.40462815761566162
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50101
- g
- 0.50101
- r
- 0.50101
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf1 3}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 6
-
- ID
- 298
- Points
-
- {225.50510406494141, 121.5}
- {225.50510406494141, 165.5}
- {225.40955501725654, 168.49497769492311}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 293
- Info
- 2
-
- ID
- 268
- Points
-
- {224.02739493545792, 343.99995141391793}
- {223, 429.7202764937623}
- {188.2909823676016, 431}
- {188.2380633102257, 461.71997833251947}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 267
-
-
-
- Bounds
- {{180.97635650634766, 256.25954693555832}, {87.159675598144531, 87.240440368652344}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 267
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- archive
-
- YnBsaXN0MDDUAQIDBAUGHyBYJHZl
- cnNpb25YJG9iamVjdHNZJGFyY2hp
- dmVyVCR0b3ASAAGGoKUHCBEVHFUk
- bnVsbNQJCgsMDQ4PEF8QEk5TQ3Vz
- dG9tQ29sb3JTcGFjZVYkY2xhc3Nc
- TlNDb2xvclNwYWNlV05TV2hpdGWA
- AoAEEANCMQDSChITFFROU0lEgAMQ
- AtIWFxgZWiRjbGFzc25hbWVYJGNs
- YXNzZXNcTlNDb2xvclNwYWNlohob
- XE5TQ29sb3JTcGFjZVhOU09iamVj
- dNIWFx0eV05TQ29sb3KiHRtfEA9O
- U0tleWVkQXJjaGl2ZXLRISJUcm9v
- dIABCBEaIy0yNz1DTGFodX1/gYOG
- i5CSlJmkrbq9ytPY4OP1+P0AAAAA
- AAABAQAAAAAAAAAjAAAAAAAAAAAA
- AAAAAAAA/w==
-
- b
- 1
- g
- 1
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.771739
- g
- 0.521768
- r
- 0.477113
-
- CornerRadius
- 9
-
-
-
-
- Bounds
- {{172.00000190734863, 168.50970363616943}, {105, 56.99029541015625}}
- Class
- ShapedGraphic
- ID
- 6
- Shape
- Diamond
- Style
-
- fill
-
- Color
-
- b
- 0.838968
- g
- 0.981553
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.630487
- g
- 0.735237
- r
- 0.99551
-
- Pattern
- 1
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 if image and kernel_id}
- VerticalPad
- 0
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 267
-
- ID
- 252
- Points
-
- {224.51964580161635, 225.98952084505945}
- {224.53982195872041, 255.7595469685505}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 6
-
-
-
- Bounds
- {{66.458778381347656, 99.999996185302734}, {385.54123306274414, 18}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 295
- Magnets
-
- {-0.7396002417658688, -1.1094003915786723}
- {-0.42163697454145743, -1.2649110555648782}
- {1.9868216701487083e-08, -1.3333333730697607}
- {0.4216371064819644, -1.2649110555648782}
- {0.73960031615696409, -1.1094003915786723}
- {1.1094003915786752, -0.73960025003154484}
- {1.2649110555648815, -0.42163684260095158}
- {1.3333333730697643, 1.5894572650646909e-07}
- {1.2649110555648815, 0.42163714417925258}
- {1.1094003915786752, 0.73960034921967321}
- {0.73960021696883971, 1.1094003915786763}
- {0.42163699339010319, 1.2649110555648826}
- {1.1842379282265398e-15, 1.3333333730697656}
- {-0.42163733062650866, 1.264910936355593}
- {-0.73960021696883771, 1.1094003915786763}
- {-1.1094003915786739, 0.73960034921967321}
- {-1.2649110555648797, 0.42163676720638188}
- {-1.3333333730697625, -6.357828941834971e-07}
- {-1.2649109363555902, -0.42163717983737348}
- {-1.1094005107879634, -0.73960016419084496}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.837612
- g
- 0.979516
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.588068
- g
- 0.693116
- r
- 0.99798
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- VerticalPad
- 3
-
-
-
- Bounds
- {{31.584197998046875, 63.71966552734375}, {447.82147216796875, 352.28033447265625}}
- Class
- ShapedGraphic
- ID
- 4
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.950215
- g
- 0.950215
- r
- 0.950215
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.48913
- g
- 0.48913
- r
- 0.48913
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- Class
- LineGraphic
- ID
- 321
- Points
-
- {360.85866047572324, 122.5}
- {360.85866047572324, 166.5}
- {360.77124049304501, 169.40246908201695}
-
- Style
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{389, 553.71937942504883}, {69, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 360
- Shape
- Rectangle
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.747526
- g
- 0.747526
- r
- 0.747526
-
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs28 \cf0 Fog Gem}
- VerticalPad
- 0
-
- Wrap
- NO
-
-
- Bounds
- {{65.49493408203125, 601.49496459960938}, {388, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 352
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.973627
- g
- 0.992442
- r
- 0.834
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.80124
- g
- 0.886111
- r
- 0.566755
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.850363
- g
- 0.883832
- r
- 0.488493
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Nova Volume}
-
-
-
- Bounds
- {{34.99493408203125, 454.00000190734863}, {435, 127}}
- Class
- ShapedGraphic
- ID
- 351
- Shape
- Rectangle
- Style
-
- fill
-
- Color
-
- b
- 0.950215
- g
- 0.950215
- r
- 0.950215
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.48913
- g
- 0.48913
- r
- 0.48913
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- GridInfo
-
- GuidesLocked
- NO
- GuidesVisible
- YES
- HPages
- 1
- ImageCounter
- 1
- KeepToScale
-
- Layers
-
-
- Lock
- NO
- Name
- Layer 1
- Print
- YES
- View
- YES
-
-
- LayoutInfo
-
- Animate
- NO
- circoMinDist
- 18
- circoSeparation
- 0.0
- layoutEngine
- dot
- neatoSeparation
- 0.0
- twopiSeparation
- 0.0
-
- LinksVisible
- NO
- MagnetsVisible
- NO
- MasterSheets
-
- ModificationDate
- 2013-01-07 08:55:29 +0000
- Modifier
- rajdeepd
- NotesVisible
- NO
- Orientation
- 2
- OriginVisible
- NO
- PageBreaks
- YES
- PrintInfo
-
- NSBottomMargin
-
- float
- 41
-
- NSHorizonalPagination
-
- coded
- BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
-
- NSLeftMargin
-
- float
- 18
-
- NSPaperSize
-
- size
- {612, 792}
-
- NSPrintReverseOrientation
-
- int
- 0
-
- NSRightMargin
-
- float
- 18
-
- NSTopMargin
-
- float
- 18
-
-
- PrintOnePage
-
- ReadOnly
- NO
- RowAlign
- 1
- RowSpacing
- 36
- SheetTitle
- Canvas 1
- SmartAlignmentGuidesActive
- YES
- SmartDistanceGuidesActive
- YES
- UniqueID
- 1
- UseEntirePage
-
- VPages
- 1
- WindowInfo
-
- CurrentSheet
- 0
- ExpandedCanvases
-
-
- name
- Canvas 1
-
-
- Frame
- {{976, 553}, {710, 811}}
- ListView
-
- OutlineWidth
- 142
- RightSidebar
-
- ShowRuler
-
- Sidebar
-
- SidebarWidth
- 120
- VisibleRegion
- {{0, 61}, {575, 672}}
- Zoom
- 1
- ZoomValues
-
-
- Canvas 1
- 1
- 1
-
-
-
-
-
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_deletestemcell.png b/src/bosh_openstack_cpi/docs/images/openstack_cpi_deletestemcell.png
deleted file mode 100644
index 413ae9ec0..000000000
Binary files a/src/bosh_openstack_cpi/docs/images/openstack_cpi_deletestemcell.png and /dev/null differ
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_initialize.graffle b/src/bosh_openstack_cpi/docs/images/openstack_cpi_initialize.graffle
deleted file mode 100644
index 166e0188e..000000000
--- a/src/bosh_openstack_cpi/docs/images/openstack_cpi_initialize.graffle
+++ /dev/null
@@ -1,4090 +0,0 @@
-
-
-
-
- ActiveLayerIndex
- 0
- ApplicationVersion
-
- com.omnigroup.OmniGraffle6
- 169.8.0.255486
-
- AutoAdjust
-
- BackgroundGraphic
-
- Bounds
- {{0, 0}, {576, 733}}
- Class
- SolidGraphic
- ID
- 2
- Style
-
- stroke
-
- Draws
- NO
-
-
-
- BaseZoom
- 0
- CanvasOrigin
- {0, 0}
- ColumnAlign
- 1
- ColumnSpacing
- 36
- CreationDate
- 2012-12-20 10:10:00 +0000
- Creator
- rajdeepd
- DisplayScale
- 1 in = 1.00000 in
- GraphDocumentVersion
- 12
- GraphicsList
-
-
- Bounds
- {{157.06841206800038, 391.37573056252666}, {182.15492635980138, 20}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 260
- Line
-
- ID
- 258
- Offset
- -24
- RotationType
- 0
-
- Style
-
- fill
-
- Color
-
- b
- 0.83761200000000002
- g
- 0.97951600000000005
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.58806800000000004
- g
- 0.69311599999999995
- r
- 0.99797999999999998
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
- new(openstack_params) #lazy}
- VerticalPad
- 3
-
-
-
- Class
- LineGraphic
- ID
- 400
- Points
-
- {236.39453956627611, 380.44952427238013}
- {435.24657810315597, 444.23999007046223}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 259
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 371
-
- ID
- 398
- Points
-
- {236.39453956627611, 380.44952427238013}
- {298.14082457468044, 442.44572338732161}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 259
-
-
-
- Class
- LineGraphic
- ID
- 397
- Points
-
- {427.48817350427794, 639.35998570919037}
- {427.03999063372612, 678.2408717724287}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Class
- LineGraphic
- ID
- 396
- Points
-
- {313.04896725709159, 638.21995349192048}
- {312.60078438653977, 677.10083955515881}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 383
-
-
-
- Bounds
- {{407.6312342448316, 560.1934517417626}, {36, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 395
- Line
-
- ID
- 394
- Offset
- 2
- Position
- 0.36649477481842041
- RotationType
- 0
-
- Style
-
- fill
-
- Color
-
- b
- 0.83761200000000002
- g
- 0.97951600000000005
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.58806800000000004
- g
- 0.69311599999999995
- r
- 0.99797999999999998
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-new }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 386
-
- ID
- 394
- Points
-
- {427.74710913279938, 556.31998743116856}
- {427.43074838862378, 594.22000412518878}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{410.00421559513603, 479.70592042476795}, {36, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 393
- Line
-
- ID
- 392
- Position
- 0.393485426902771
- RotationType
- 0
-
- Style
-
- fill
-
- Color
-
- b
- 0.83761200000000002
- g
- 0.97951600000000005
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.58806800000000004
- g
- 0.69311599999999995
- r
- 0.99797999999999998
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-new }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 385
- Info
- 3
-
- ID
- 392
- Points
-
- {428.12198438501133, 474.35998933017254}
- {427.82268793424134, 513.35998852550972}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{296.97577273845565, 560.67725539472758}, {36, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 391
- Line
-
- ID
- 390
- Offset
- 2
- Position
- 0.36649477481842041
- RotationType
- 0
-
- Style
-
- fill
-
- Color
-
- b
- 0.83761200000000002
- g
- 0.97951600000000005
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.58806800000000004
- g
- 0.69311599999999995
- r
- 0.99797999999999998
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-new }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 383
-
- ID
- 390
- Points
-
- {312.87813929560133, 557.07998850941658}
- {313.14467773807888, 594.21999958231743}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 381
- Info
- 13
-
-
-
- Bounds
- {{294.9036112060287, 478.73980970945445}, {36, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 389
- Line
-
- ID
- 388
- Position
- 0.393485426902771
- RotationType
- 0
-
- Style
-
- fill
-
- Color
-
- b
- 0.83761200000000002
- g
- 0.97951600000000005
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.58806800000000004
- g
- 0.69311599999999995
- r
- 0.99797999999999998
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-new }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 381
- Info
- 3
-
- ID
- 388
- Points
-
- {312.92013517875472, 472.29998985008297}
- {312.87814131481673, 514.07998850941658}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 371
-
-
-
- Bounds
- {{377.43999151885509, 676.79998487234116}, {101.6304358635042, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 387
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Style
-
- fill
-
- Color
-
- b
- 0.97362700000000002
- g
- 0.99244200000000005
- r
- 0.83399999999999996
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.80124
- g
- 0.886111
- r
- 0.566755
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.85036299999999998
- g
- 0.88383199999999995
- r
- 0.48849300000000001
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
- Neutron}
-
-
-
- Bounds
- {{376.85631441882072, 594.71998670697212}, {100.78158942795733, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 386
- Style
-
- fill
-
- Color
-
- b
- 0.80966499999999997
- g
- 0.97339100000000001
- r
- 0.99244200000000005
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.61095299999999997
- g
- 0.70655199999999996
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Connection}
-
-
-
- Bounds
- {{377.00746798327384, 513.35998852550983}, {101.6304358635042, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 385
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Style
-
- fill
-
- Color
-
- b
- 0.80966499999999997
- g
- 0.97339100000000001
- r
- 0.99244200000000005
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.61095299999999997
- g
- 0.70655199999999996
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Network::\
-OpenStack}
-
-
-
- Bounds
- {{262.11999402940273, 676.79998487234116}, {101.6304358635042, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 384
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Style
-
- fill
-
- Color
-
- b
- 0.97362700000000002
- g
- 0.99244200000000005
- r
- 0.83399999999999996
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.80124
- g
- 0.886111
- r
- 0.566755
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.85036299999999998
- g
- 0.88383199999999995
- r
- 0.48849300000000001
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
- Cinder}
-
-
-
- Bounds
- {{262.9117677993961, 594.71998670697212}, {100.78158942795733, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 383
- Style
-
- fill
-
- Color
-
- b
- 0.80966499999999997
- g
- 0.97339100000000001
- r
- 0.99244200000000005
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.61095299999999997
- g
- 0.70655199999999996
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Connection}
-
-
-
- Bounds
- {{262.06292136384923, 514.07998850941658}, {101.6304358635042, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 381
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Style
-
- fill
-
- Color
-
- b
- 0.80966499999999997
- g
- 0.97339100000000001
- r
- 0.99244200000000005
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.61095299999999997
- g
- 0.70655199999999996
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Volume::\
-OpenStack}
-
-
-
- Bounds
- {{376.95999166369438, 445.15998989343643}, {101.6304358635042, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 380
- Style
-
- fill
-
- Color
-
- b
- 0.80966499999999997
- g
- 0.97339100000000001
- r
- 0.99244200000000005
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.61095299999999997
- g
- 0.70655199999999996
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Network}
-
-
-
- Bounds
- {{184.00224352598181, 559.52410302831254}, {36, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 379
- Line
-
- ID
- 378
- Offset
- 2
- Position
- 0.3664947824952256
- RotationType
- 0
-
- Style
-
- fill
-
- Color
-
- b
- 0.83761200000000002
- g
- 0.97951600000000005
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.58806800000000004
- g
- 0.69311599999999995
- r
- 0.99797999999999998
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-new }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 364
-
- ID
- 378
- Points
-
- {199.93359267617672, 555.77555847167969}
- {200.12097805286706, 593.31641247866526}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 288
- Info
- 13
-
-
-
- Bounds
- {{68.954029433389735, 558.8473030055585}, {36, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 377
- Line
-
- ID
- 376
- Offset
- -2
- Position
- 0.35040513273679408
- RotationType
- 0
-
- Style
-
- fill
-
- Color
-
- b
- 0.83761200000000002
- g
- 0.97951600000000005
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.58806800000000004
- g
- 0.69311599999999995
- r
- 0.99797999999999998
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-new }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 283
-
- ID
- 376
- Points
-
- {84.989046056752102, 555.63998854160309}
- {84.889134303836954, 593.31640800805167}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 279
- Info
- 13
-
-
-
- Bounds
- {{66.989048075967503, 477.50303937947604}, {36, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 375
- Line
-
- ID
- 374
- Position
- 0.40348854660987854
- RotationType
- 0
-
- Style
-
- fill
-
- Color
-
- b
- 0.83761200000000002
- g
- 0.97951600000000005
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.58806800000000004
- g
- 0.69311599999999995
- r
- 0.99797999999999998
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-new }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 279
- Info
- 3
-
- ID
- 374
- Points
-
- {84.989048075967503, 470.50006103515619}
- {84.989048075967503, 512.63998854160309}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 256
-
-
-
- Bounds
- {{181.89925629788752, 476.93811263989164}, {36, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 373
- Line
-
- ID
- 372
- Position
- 0.39348542524682073
- RotationType
- 0
-
- Style
-
- fill
-
- Color
-
- b
- 0.83761200000000002
- g
- 0.97951600000000005
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.58806800000000004
- g
- 0.69311599999999995
- r
- 0.99797999999999998
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-new }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 288
-
- ID
- 372
- Points
-
- {199.87541569839962, 470.50006050929278}
- {199.93600396310407, 512.27556427628429}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 287
-
-
-
- Bounds
- {{262.11999402940273, 442.79999010264874}, {101.6304358635042, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 371
- Style
-
- fill
-
- Color
-
- b
- 0.80966499999999997
- g
- 0.97339100000000001
- r
- 0.99244200000000005
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.61095299999999997
- g
- 0.70655199999999996
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Volume}
-
-
-
- Bounds
- {{221.47999502718449, 290.55999359488487}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 370
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50100999999999996
- g
- 0.50100999999999996
- r
- 0.50100999999999996
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 4}
-
-
-
- Bounds
- {{174.18267784622296, 310.24270584444582}, {145, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 369
- Line
-
- ID
- 368
- Offset
- -3
- Position
- 0.47992599010467529
- RotationType
- 0
-
- Style
-
- fill
-
- Color
-
- b
- 0.83761200000000002
- g
- 0.97951600000000005
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.58806800000000004
- g
- 0.69311599999999995
- r
- 0.99797999999999998
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-new(openstack_params) }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Class
- LineGraphic
- Head
-
- ID
- 366
-
- ID
- 368
- Points
-
- {243.68850708007812, 292.3199934661389}
- {243.67636110627058, 350.49997699736502}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 231
-
-
-
- Bounds
- {{175.99566818505082, 350.99997698646928}, {135.35512287720917, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 366
- Style
-
- fill
-
- Color
-
- b
- 0.80966499999999997
- g
- 0.97339100000000001
- r
- 0.99244200000000005
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.61095299999999997
- g
- 0.70655199999999996
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Bosh::OpenStackCloud::OpenStack}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 361
- Info
- 3
-
- ID
- 365
- Points
-
- {200.12097879895487, 637.31640002141933}
- {199.93359469539215, 674.85725402832031}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 364
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 352
- Info
- 3
-
- ID
- 362
- Points
-
- {85.044245600218204, 637.31638271770714}
- {85.406372678571444, 674.63998492062092}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 283
-
-
-
- Bounds
- {{149.11837474442461, 674.85725402832031}, {101.6304358635042, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 361
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Style
-
- fill
-
- Color
-
- b
- 0.97362700000000002
- g
- 0.99244200000000005
- r
- 0.83399999999999996
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.80124
- g
- 0.886111
- r
- 0.566755
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.85036299999999998
- g
- 0.88383199999999995
- r
- 0.48849300000000001
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
- Glance}
-
-
-
- Bounds
- {{445.67999003827572, 421.55999037623405}, {69, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 360
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.74752600000000002
- g
- 0.74752600000000002
- r
- 0.74752600000000002
-
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs28 \cf0 Fog Gem}
- VerticalPad
- 0.0
-
- Wrap
- NO
-
-
- Bounds
- {{371.67999164760113, 156.23999650776386}, {143, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 357
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.74752600000000002
- g
- 0.74752600000000002
- r
- 0.74752600000000002
-
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs28 \cf0 Bosh OpenStack CPI}
- VerticalPad
- 0.0
-
- Wrap
- NO
-
-
- Bounds
- {{34.591152727603912, 674.63998492062092}, {101.6304358635042, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 352
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215813308637e-08, -1.3333333730697632}
- {0.42163710648196356, -1.2649110555648804}
- {0.73960031615696331, -1.1094003915786743}
- {0.50000000000000011, -0.3333333283662796}
- {1.2649110555648806, -0.4216368426009538}
- {1.3333333730697634, 1.5894572413799324e-07}
- {1.2649110555648806, 0.42163714417925036}
- {0.50000000000000011, 0.33333337306976318}
- {0.73960021696883893, 1.1094003915786743}
- {0.42163699339010235, 1.2649110555648804}
- {2.9605948205663494e-16, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883871, 1.1094003915786743}
- {-0.49999999999999994, 0.33333337306976318}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-0.49999999999999994, -0.33333325386047363}
-
- Style
-
- fill
-
- Color
-
- b
- 0.97362700000000002
- g
- 0.99244200000000005
- r
- 0.83399999999999996
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.80124
- g
- 0.886111
- r
- 0.566755
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.85036299999999998
- g
- 0.88383199999999995
- r
- 0.48849300000000001
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Nova Compute}
-
-
-
- Bounds
- {{149.83999642729759, 593.81640625}, {100.78158942795733, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 364
- Style
-
- fill
-
- Color
-
- b
- 0.80966499999999997
- g
- 0.97339100000000001
- r
- 0.99244200000000005
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.61095299999999997
- g
- 0.70655199999999996
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Connection}
-
-
-
- Bounds
- {{149.11837474442461, 512.77555847167969}, {101.6304358635042, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 288
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Style
-
- fill
-
- Color
-
- b
- 0.80966499999999997
- g
- 0.97339100000000001
- r
- 0.99244200000000005
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.61095299999999997
- g
- 0.70655199999999996
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Image::\
-OpenStack}
-
-
-
- Bounds
- {{149.03844281801122, 441.00006103515625}, {101.6304358635042, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 287
- Style
-
- fill
-
- Color
-
- b
- 0.80966499999999997
- g
- 0.97339100000000001
- r
- 0.99244200000000005
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.61095299999999997
- g
- 0.70655199999999996
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Image}
-
-
-
- Bounds
- {{34.439999163150787, 593.81640625}, {100.78158942795733, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 283
- Style
-
- fill
-
- Color
-
- b
- 0.80966499999999997
- g
- 0.97339100000000001
- r
- 0.99244200000000005
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.61095299999999997
- g
- 0.70655199999999996
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Connection}
-
-
-
- Bounds
- {{34.173828125, 512.63998854160309}, {101.6304358635042, 43}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 279
- Magnets
-
- {-0.73960024176586958, -1.1094003915786743}
- {-0.42163697454145826, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696309, -1.1094003915786743}
- {1.1094003915786743, -0.73960025003154684}
- {1.2649110555648804, -0.4216368426009538}
- {1.3333333730697632, 1.5894572413799324e-07}
- {1.2649110555648804, 0.42163714417925036}
- {1.1094003915786743, 0.73960034921967122}
- {0.73960021696883871, 1.1094003915786743}
- {0.42163699339010208, 1.2649110555648804}
- {0, 1.3333333730697632}
- {-0.42163733062650949, 1.2649109363555908}
- {-0.73960021696883849, 1.1094003915786743}
- {-1.1094003915786741, 0.73960034921967122}
- {-1.2649110555648801, 0.42163676720637966}
- {-1.333333373069763, -6.3578289655197295e-07}
- {-1.2649109363555906, -0.4216371798373757}
- {-1.1094005107879636, -0.73960016419084695}
-
- Style
-
- fill
-
- Color
-
- b
- 0.80966499999999997
- g
- 0.97339100000000001
- r
- 0.99244200000000005
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.61095299999999997
- g
- 0.70655199999999996
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Compute::\
-OpenStack}
-
-
-
- Bounds
- {{294.3040312786415, 223.04465866088867}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 276
- Line
-
- ID
- 266
- Position
- 0.37499326467514038
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50100999999999996
- g
- 0.50100999999999996
- r
- 0.50100999999999996
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 2}
-
-
-
- Bounds
- {{157.11837474442461, 197.9001387883261}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 273
- Line
-
- ID
- 270
- Offset
- 2
- Position
- 0.15934100547108523
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50100999999999996
- g
- 0.50100999999999996
- r
- 0.50100999999999996
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 3}
-
-
-
- Bounds
- {{103.85809152883793, 217.790003720481}, {20.50001335144043, 19.000007629394531}}
- Class
- ShapedGraphic
- FontInfo
-
- Color
-
- b
- 1
- g
- 1
- r
- 1
-
-
- ID
- 272
- Line
-
- ID
- 271
- Position
- 0.58284473419189453
- RotationType
- 0
-
- Shape
- Circle
- Style
-
- fill
-
- Color
-
- b
- 0.50100999999999996
- g
- 0.50100999999999996
- r
- 0.50100999999999996
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf1 1}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 268
-
- ID
- 271
- Points
-
- {145.17097500847333, 193.45905766468556}
- {144, 212.54466247558594}
- {114, 212.54466247558594}
- {114.44319850558085, 273.00001343536854}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 269
- Info
- 15
-
-
-
- Bounds
- {{63.737945556640625, 273.5}, {101.6304358635042, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 268
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.77173899999999995
- g
- 0.52176800000000001
- r
- 0.47711300000000001
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-validate_options}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 264
-
- ID
- 267
- Points
-
- {390.16638102803455, 310.50002911765671}
- {390.16562181729756, 332.49999058353137}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 265
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 265
-
- ID
- 266
- Points
-
- {275.12634198092138, 193.45999347706302}
- {275, 232.54466247558594}
- {372, 232.54466247558594}
- {390, 232.54466247558594}
- {390.09058221361596, 261.5000315645629}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 269
- Info
- 11
-
-
-
- Bounds
- {{331.4131981938873, 262.00002911795445}, {117.508056640625, 48}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 265
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.77173899999999995
- g
- 0.52176800000000001
- r
- 0.47711300000000001
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-registry_endpoint\
-registry_user\
-registry_password}
-
-
-
- Bounds
- {{331.41319274902344, 332.99999058246613}, {117.508056640625, 48}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 264
- Style
-
- fill
-
- Color
-
- b
- 0.99244200000000005
- g
- 0.91966099999999995
- r
- 0.82805899999999999
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.994565
- g
- 0.699277
- r
- 0.416525
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.77173899999999995
- g
- 0.52176800000000001
- r
- 0.47711300000000001
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Registry_Client}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 287
-
- ID
- 259
- Points
-
- {236.39453956627611, 380.44952427238013}
- {207.13235080714259, 440.5505137492454}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 366
-
-
-
- Class
- LineGraphic
- ID
- 258
- Points
-
- {236.39453956627611, 380.44952427238013}
- {123.22694730758667, 444}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 259
-
-
-
- Bounds
- {{34.173828125, 441.00006103515625}, {101.6304358635042, 29}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 256
- Style
-
- fill
-
- Color
-
- b
- 0.80966499999999997
- g
- 0.97339100000000001
- r
- 0.99244200000000005
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.557168
- g
- 0.784505
- r
- 0.994565
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.61095299999999997
- g
- 0.70655199999999996
- r
- 1
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Fog::Compute}
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 231
-
- ID
- 255
- Points
-
- {242.64560076118829, 233.04418933065318}
- {243.68850963070031, 257}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
- Tail
-
- ID
- 249
-
-
-
- Class
- LineGraphic
- Head
-
- ID
- 249
-
- ID
- 270
- Points
-
- {165.36838142014483, 195}
- {165.36838142014483, 222}
- {216.18851964698857, 222.36031992994629}
-
- Style
-
- shadow
-
- Draws
- NO
-
- stroke
-
- HeadArrow
- FilledArrow
- Legacy
-
- TailArrow
- 0
-
-
-
-
- Bounds
- {{216.68850708007812, 212.54466247558594}, {51, 20}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- ID
- 249
- Style
-
- fill
-
- Color
-
- b
- 0.83761200000000002
- g
- 0.97951600000000005
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.58806800000000004
- g
- 0.69311599999999995
- r
- 0.99797999999999998
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Extract }
- VerticalPad
- 3
-
- Wrap
- NO
-
-
- Bounds
- {{112.71999756991863, 174.95999608933926}, {194.8895574417021, 18}}
- Class
- ShapedGraphic
- FitText
- Vertical
- Flow
- Resize
- ID
- 269
- Magnets
-
- {-0.73960024176586936, -1.1094003915786743}
- {-0.42163697454145743, -1.2649110555648804}
- {1.9868216701487083e-08, -1.3333333730697632}
- {0.4216371064819644, -1.2649110555648804}
- {0.73960031615696409, -1.1094003915786743}
- {1.1094003915786752, -0.73960025003154684}
- {1.2649110555648815, -0.4216368426009538}
- {1.3333333730697643, 1.5894572413799324e-07}
- {1.2649110555648815, 0.42163714417925036}
- {1.1094003915786752, 0.73960034921967122}
- {0.73960021696883971, 1.1094003915786743}
- {0.42163699339010319, 1.2649110555648804}
- {1.1842379282265398e-15, 1.3333333730697632}
- {-0.42163733062650866, 1.2649109363555908}
- {-0.73960021696883826, 1.1094003915786743}
- {-1.1094003915786739, 0.73960034921967122}
- {-1.2649110555648797, 0.42163676720637966}
- {-1.3333333730697625, -6.3578289655197295e-07}
- {-1.2649109363555902, -0.4216371798373757}
- {-1.1094005107879634, -0.73960016419084695}
-
- Style
-
- fill
-
- Color
-
- b
- 0.83761200000000002
- g
- 0.97951600000000005
- r
- 1
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.58806800000000004
- g
- 0.69311599999999995
- r
- 0.99797999999999998
-
- Pattern
- 2
-
-
- Text
-
- Align
- 0
- VerticalPad
- 3
-
-
-
- Bounds
- {{44.173828125, 155}, {50, 17}}
- Class
- ShapedGraphic
- FitText
- YES
- Flow
- Resize
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 233
- Style
-
- fill
-
- Draws
- NO
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Draws
- NO
-
-
- Text
-
- Pad
- 0.0
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs28 \cf0 initialize}
- VerticalPad
- 0.0
-
- Wrap
- NO
-
-
- Bounds
- {{179.5, 257}, {128.37701416015625, 35.31999346613884}}
- Class
- ShapedGraphic
- FontInfo
-
- Font
- Helvetica
- Size
- 14
-
- ID
- 231
- Magnets
-
- {-0.7396002417658698, -1.1094003915786743}
- {-0.42163697454145854, -1.2649110555648804}
- {1.9868215517249155e-08, -1.3333333730697632}
- {0.42163710648196329, -1.2649110555648804}
- {0.73960031615696264, -1.1094003915786743}
- {1.1094003915786739, -0.73960025003154684}
- {1.2649110555648797, -0.4216368426009538}
- {1.3333333730697625, 1.5894572176951738e-07}
- {1.2649110555648797, 0.42163714417924814}
- {1.1094003915786739, 0.73960034921966922}
- {0.73960021696883826, 1.1094003915786723}
- {0.42163699339010208, 1.2649110555648782}
- {0, 1.3333333730697607}
- {-0.42163733062650977, 1.2649109363555886}
- {-0.73960021696883871, 1.1094003915786723}
- {-1.1094003915786743, 0.73960034921966922}
- {-1.2649110555648804, 0.42163676720637744}
- {-1.3333333730697632, -6.3578289655197295e-07}
- {-1.2649109363555908, -0.4216371798373757}
- {-1.1094005107879639, -0.73960016419084695}
-
- Style
-
- fill
-
- Color
-
- b
- 0.99244200000000005
- g
- 0.91966099999999995
- r
- 0.82805899999999999
-
- FillType
- 2
- GradientAngle
- 90
- GradientColor
-
- b
- 0.994565
- g
- 0.699277
- r
- 0.416525
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.77173899999999995
- g
- 0.52176800000000001
- r
- 0.47711300000000001
-
- CornerRadius
- 9
-
-
- Text
-
- Text
- {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf340
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc\partightenfactor0
-
-\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-agent properties\
-openstack_properties}
-
-
-
- Bounds
- {{23, 148.40000857412815}, {496.83998838067055, 247}}
- Class
- ShapedGraphic
- ID
- 4
- Style
-
- fill
-
- Color
-
- b
- 0.95021500000000003
- g
- 0.95021500000000003
- r
- 0.95021500000000003
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.48913000000000001
- g
- 0.48913000000000001
- r
- 0.48913000000000001
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- Bounds
- {{23, 419.03999063372612}, {496.83998838067055, 231.96001222729683}}
- Class
- ShapedGraphic
- ID
- 296
- Style
-
- fill
-
- Color
-
- b
- 0.95021500000000003
- g
- 0.95021500000000003
- r
- 0.95021500000000003
-
-
- shadow
-
- Draws
- NO
-
- stroke
-
- Color
-
- b
- 0.48913000000000001
- g
- 0.48913000000000001
- r
- 0.48913000000000001
-
- CornerRadius
- 9
- Pattern
- 1
-
-
-
-
- GridInfo
-
- GuidesLocked
- NO
- GuidesVisible
- YES
- HPages
- 1
- ImageCounter
- 1
- KeepToScale
-
- Layers
-
-
- Lock
- NO
- Name
- Layer 1
- Print
- YES
- View
- YES
-
-
- LayoutInfo
-
- Animate
- NO
- circoMinDist
- 18
- circoSeparation
- 0.0
- layoutEngine
- dot
- neatoLineLength
- 0.20000000298023224
- neatoSeparation
- 0.0
- twopiSeparation
- 0.0
-
- LinksVisible
- NO
- MagnetsVisible
- NO
- MasterSheets
-
- ModificationDate
- 2016-03-09 14:24:06 +0000
- Modifier
- Veli, Beyhan
- NotesVisible
- NO
- Orientation
- 2
- OriginVisible
- NO
- PageBreaks
- YES
- PrintInfo
-
- NSBottomMargin
-
- float
- 41
-
- NSHorizonalPagination
-
- coded
- BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
-
- NSLeftMargin
-
- float
- 18
-
- NSPaperSize
-
- size
- {612, 792}
-
- NSPrintReverseOrientation
-
- coded
- BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
-
- NSRightMargin
-
- float
- 18
-
- NSTopMargin
-
- float
- 18
-
-
- PrintOnePage
-
- ReadOnly
- NO
- RowAlign
- 1
- RowSpacing
- 36
- SheetTitle
- Canvas 1
- SmartAlignmentGuidesActive
- YES
- SmartDistanceGuidesActive
- YES
- UniqueID
- 1
- UseEntirePage
-
- VPages
- 1
- WindowInfo
-
- CurrentSheet
- 0
- Expanded_Canvases
-
- Frame
- {{114, 72}, {1326, 805}}
- ShowInfo
-
- ShowRuler
-
- Sidebar
-
- SidebarWidth
- 200
- TopSlabHeight
- 250
- VisibleRegion
- {{-110, 86}, {797, 647}}
- Zoom
- 1
- ZoomValues
-
-
- Canvas 1
- 1
- 1
-
-
-
-
-
diff --git a/src/bosh_openstack_cpi/docs/images/openstack_cpi_initialize.png b/src/bosh_openstack_cpi/docs/images/openstack_cpi_initialize.png
deleted file mode 100644
index abe7fc82b..000000000
Binary files a/src/bosh_openstack_cpi/docs/images/openstack_cpi_initialize.png and /dev/null differ
diff --git a/src/bosh_openstack_cpi/lib/bosh_openstack_cpi.rb b/src/bosh_openstack_cpi/lib/bosh_openstack_cpi.rb
deleted file mode 100644
index 37a2ad00a..000000000
--- a/src/bosh_openstack_cpi/lib/bosh_openstack_cpi.rb
+++ /dev/null
@@ -1 +0,0 @@
-require 'cloud/openstack'
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack.rb b/src/bosh_openstack_cpi/lib/cloud/openstack.rb
deleted file mode 100644
index 269a553d2..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-module Bosh
- module OpenStackCloud; end
-end
-
-require 'fog/openstack'
-require 'httpclient'
-require 'json'
-require 'tmpdir'
-require 'securerandom'
-require 'membrane'
-require 'netaddr'
-
-require 'common/common'
-require 'common/exec'
-require 'common/thread_pool'
-require 'common/thread_formatter'
-
-require 'bosh/cpi/registry_client'
-require 'bosh/cpi/redactor'
-require 'cloud'
-require 'cloud/openstack/helpers'
-require 'cloud/openstack/cloud'
-require 'cloud/openstack/cpi_lambda'
-require 'cloud/openstack/openstack'
-require 'cloud/openstack/tag_manager'
-
-require 'cloud/openstack/network_configurator'
-require 'cloud/openstack/loadbalancer_configurator'
-require 'cloud/openstack/resource_pool'
-require 'cloud/openstack/security_groups'
-require 'cloud/openstack/floating_ip'
-require 'cloud/openstack/network'
-require 'cloud/openstack/private_network'
-require 'cloud/openstack/dynamic_network'
-require 'cloud/openstack/manual_network'
-require 'cloud/openstack/vip_network'
-require 'cloud/openstack/volume_configurator'
-require 'cloud/openstack/response_message'
-require 'cloud/openstack/request_message'
-require 'cloud/openstack/excon_logging_instrumentor'
-require 'cloud/openstack/availability_zone_provider'
-require 'cloud/openstack/stemcell'
-require 'cloud/openstack/stemcell_creator'
-require 'cloud/openstack/instance_type_mapper'
-require 'cloud/openstack/server'
-require 'cloud/openstack/vm_factory'
-require 'cloud/openstack/vm_creator'
-require 'cloud/openstack/noop_registry'
-
-module Bosh
- module Clouds
- OpenStack = Bosh::OpenStackCloud::Cloud
- Openstack = OpenStack # Alias needed for Bosh::Clouds::Provider.create method
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/availability_zone_provider.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/availability_zone_provider.rb
deleted file mode 100644
index a954baa2c..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/availability_zone_provider.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-module Bosh::OpenStackCloud
- class AvailabilityZoneProvider
- include Helpers
-
- def initialize(openstack, ignore_server_availability_zone)
- @openstack = openstack
- @ignore_server_availability_zone = ignore_server_availability_zone
- end
-
- def use_multiple_azs?(cloud_properties)
- single_az = cloud_properties.key?('availability_zone')
- multiple_azs = cloud_properties.key?('availability_zones')
- cloud_error('Invalid cloud_properties: only one property of "availability_zone" and "availability_zones" allowed.') if single_az && multiple_azs
- cloud_error('Cannot use multiple azs without openstack.ignore_server_availability_zone') if use_server_availability_zone? && multiple_azs
- return true if multiple_azs
- false
- end
-
- def select_azs(cloud_properties)
- multiple_azs = cloud_properties['availability_zones']
- multiple_azs.shuffle
- end
-
- def select(volume_ids, resource_pool_az)
- return resource_pool_az if array_empty?(volume_ids) || @ignore_server_availability_zone
-
- volumes = volumes(volume_ids)
- volume_azs = volumes.map(&:availability_zone)
- if resource_pool_az
- all_azs = volume_azs + [resource_pool_az]
- same_availability_zone?(all_azs) ? resource_pool_az : fail_for_different_azs(resource_pool_az, volumes)
- else
- same_availability_zone?(volume_azs) ? first_volume_az(volume_azs) : fail_for_different_azs(resource_pool_az, volumes)
- end
- end
-
- def use_server_availability_zone?
- !@ignore_server_availability_zone
- end
-
- private
-
- def first_volume_az(volume_azs)
- volume_azs.first.nil? || volume_azs.first.empty? ? nil : volume_azs.first
- end
-
- def fail_for_different_azs(resource_pool_az, volumes)
- cloud_error format("can't use multiple availability zones: %s, %s. " +
- "Enable 'openstack.ignore_server_availability_zone' to allow VMs and disks to be in different AZs, or use the same AZ for both.",
- resource_pool_az_description(resource_pool_az), disk_az_description(volumes))
- end
-
- def array_empty?(array)
- array.nil? || array.empty?
- end
-
- def same_availability_zone?(azs)
- uniq_azs = azs.uniq
- uniq_azs.size == 1
- end
-
- def volumes(volume_ids)
- fog_volume_map = @openstack.with_openstack { @openstack.volume.volumes }
- volume_ids.map { |vid| @openstack.with_openstack(retryable: true) { fog_volume_map.get(vid) } }
- end
-
- def resource_pool_az_description(resource_pool_az)
- if resource_pool_az
- format("VM is created in AZ '%s'", resource_pool_az)
- else
- 'VM is created in default AZ'
- end
- end
-
- def disk_az_description(volumes)
- volumes.map do |volume|
- format("disk '%s' is in AZ '%s'", volume.id, volume.availability_zone)
- end.join(', ')
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/cloud.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/cloud.rb
deleted file mode 100644
index 0fed01bbb..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/cloud.rb
+++ /dev/null
@@ -1,873 +0,0 @@
-module Bosh::OpenStackCloud
- ##
- # BOSH OpenStack CPI
- class Cloud < Bosh::Cloud
- include Helpers
-
- OPTION_KEYS = %w[openstack registry agent use_dhcp].freeze
-
- BOSH_APP_DIR = '/var/vcap/bosh'.freeze
- FIRST_DEVICE_NAME_LETTER = 'b'.freeze
- REGISTRY_KEY_TAG = :registry_key
-
- attr_reader :state_timeout
- attr_reader :openstack
- attr_accessor :logger
-
- ##
- # Creates a new BOSH OpenStack CPI
- #
- # @param [Hash] options CPI options
- # @option options [Hash] openstack OpenStack specific options
- # @option options [Hash] agent agent options
- # @option options [Hash] registry agent options
- # @option cpi_api_version CPI API Version as requested by BOSH director
- def initialize(options, cpi_api_version)
- super()
-
- @cpi_api_version = cpi_api_version || 1
- @options = normalize_options(options)
-
- validate_options
-
- @logger = Bosh::Clouds::Config.logger
-
- @agent_properties = @options.fetch('agent', {})
- openstack_properties = @options['openstack']
- @default_key_name = openstack_properties['default_key_name']
- @default_security_groups = openstack_properties['default_security_groups']
- @default_volume_type = openstack_properties['default_volume_type']
- @stemcell_public_visibility = openstack_properties['stemcell_public_visibility']
- @boot_from_volume = openstack_properties['boot_from_volume']
- @use_dhcp = openstack_properties['use_dhcp']
- @human_readable_vm_names = openstack_properties['human_readable_vm_names']
- @use_config_drive = !!openstack_properties.fetch('config_drive', false)
- @config_drive = openstack_properties['config_drive']
-
- @openstack = Bosh::OpenStackCloud::Openstack.new(@options['openstack'])
-
- @az_provider = Bosh::OpenStackCloud::AvailabilityZoneProvider.new(
- @openstack,
- openstack_properties['ignore_server_availability_zone'],
- )
-
- @metadata_lock = Mutex.new
-
- @instance_type_mapper = Bosh::OpenStackCloud::InstanceTypeMapper.new
- end
-
- def compute
- @openstack.compute
- end
-
- def glance
- @openstack.image
- end
-
- def volume
- @openstack.volume
- end
-
- def auth_url
- @openstack.auth_url
- end
-
- def network
- @openstack.network
- end
-
- ##
- # Creates a new OpenStack Image using stemcell image. It requires access
- # to the OpenStack Glance service.
- #
- # @param [String] image_path Local filesystem path to a stemcell image
- # @param [Hash] cloud_properties CPI-specific properties
- # @option cloud_properties [String] name Stemcell name
- # @option cloud_properties [String] version Stemcell version
- # @option cloud_properties [String] infrastructure Stemcell infrastructure
- # @option cloud_properties [String] disk_format Image disk format
- # @option cloud_properties [String] container_format Image container format
- # @option cloud_properties [optional, String] kernel_file Name of the
- # kernel image file provided at the stemcell archive
- # @option cloud_properties [optional, String] ramdisk_file Name of the
- # ramdisk image file provided at the stemcell archive
- # @return [String] OpenStack image UUID of the stemcell
- def create_stemcell(image_path, cloud_properties)
- with_thread_name("create_stemcell(#{image_path}...)") do
- stemcell_creator = StemcellCreator.new(@logger, @openstack, cloud_properties)
- stemcell = stemcell_creator.create(image_path, @stemcell_public_visibility)
- stemcell.id
- end
- end
-
- ##
- # Deletes a stemcell
- #
- # @param [String] stemcell_id OpenStack image UUID of the stemcell to be
- # deleted
- # @return [void]
- def delete_stemcell(stemcell_id)
- with_thread_name("delete_stemcell(#{stemcell_id})") do
- @logger.info("Deleting stemcell `#{stemcell_id}'...")
-
- stemcell = Stemcell.create(@logger, @openstack, stemcell_id)
- stemcell.delete
- end
- end
-
- ##
- # Creates an OpenStack server and waits until it's in running state
- #
- # @param [String] agent_id UUID for the agent that will be used later on by
- # the director to locate and talk to the agent
- # @param [String] stemcell_id OpenStack image UUID that will be used to
- # power on new server
- # @param [Hash] cloud_properties cloud specific properties describing the
- # resources needed for this VM
- # @param [Hash] network_spec list of networks and their settings needed for
- # this VM
- # @param [optional, Array] disk_locality List of disks that might be
- # attached to this server in the future, can be used as a placement
- # hint (i.e. server will only be created if resource pool availability
- # zone is the same as disk availability zone)
- # @param [optional, Hash] environment Data to be merged into agent settings
- # @return [String] OpenStack server UUID
- def create_vm(agent_id, stemcell_id, cloud_properties,
- network_spec = nil, disk_locality = nil, environment = nil)
- with_thread_name("create_vm(#{agent_id}, ...)") do
- @logger.info('Creating new server...')
- @logger.debug("Using scheduler hints: `#{cloud_properties['scheduler_hints']}'") if cloud_properties['scheduler_hints']
- registry_key = "vm-#{generate_unique_name}"
- create_vm_params = {
- name: registry_key,
- os_scheduler_hints: cloud_properties['scheduler_hints'],
- config_drive: @use_config_drive,
- }
- server = Server.new(@agent_properties, @human_readable_vm_names, @logger, @openstack, registry, @use_dhcp)
-
- openstack_properties = OpenStruct.new(
- boot_from_volume: @boot_from_volume,
- default_key_name: @default_key_name,
- default_security_groups: @default_security_groups,
- )
-
- vm_factory = VmFactory.new(@openstack, server, create_vm_params, disk_locality, @az_provider, openstack_properties)
- network_configurator = NetworkConfigurator.new(network_spec, cloud_properties['allowed_address_pairs'])
- instance_id = vm_factory.create_vm(network_configurator, agent_id, environment, stemcell_id, cloud_properties)
-
- if @cpi_api_version >= 2
- [instance_id, network_configurator.network_spec]
- else
- instance_id
- end
- end
- end
-
- ##
- # Terminates an OpenStack server and waits until it reports as terminated
- #
- # @param [String] server_id OpenStack server UUID
- # @return [void]
- def delete_vm(server_id)
- with_thread_name("delete_vm(#{server_id})") do
- @logger.info("Deleting server `#{server_id}'...")
- server = openstack_server(server_id)
- if server
- server_tags = metadata_to_tags(server.metadata)
- @logger.debug("Server tags: `#{server_tags}' found for server #{server_id}")
- Server.new(@agent_properties, @human_readable_vm_names, @logger, @openstack, registry, @use_dhcp)
- .destroy(server, server_tags)
- else
- @logger.info("Server `#{server_id}' not found. Skipping.")
- end
- end
- end
-
- ##
- # Checks if an OpenStack server exists
- #
- # @param [String] server_id OpenStack server UUID
- # @return [Boolean] True if the vm exists
- def has_vm?(server_id)
- with_thread_name("has_vm?(#{server_id})") do
- server = openstack_server(server_id)
- !server.nil? && !%i[terminated deleted].include?(server.state.downcase.to_sym)
- end
- end
-
- ##
- # Reboots an OpenStack Server
- #
- # @param [String] server_id OpenStack server UUID
- # @return [void]
- def reboot_vm(server_id)
- with_thread_name("reboot_vm(#{server_id})") do
- server = openstack_server(server_id)
- cloud_error("Server `#{server_id}' not found") unless server
-
- soft_reboot(server)
- end
- end
-
- ##
- # Configures networking on existing OpenStack server
- #
- # @param [String] server_id OpenStack server UUID
- # @param [Hash] network_spec Raw network spec passed by director
- # @return [void]
- # @raise [Bosh::Clouds:NotSupported] If there's a network change that requires the recreation of the VM
- def configure_networks(server_id, network_spec)
- with_thread_name("configure_networks(#{server_id}, ...)") do
- raise Bosh::Clouds::NotSupported,
- format('network configuration change requires VM recreation: %s', network_spec)
- end
- end
-
- ##
- # Creates a new OpenStack volume
- #
- # @param [Integer] size disk size in MiB
- # @param [optional, String] server_id OpenStack server UUID of the VM that
- # this disk will be attached to
- # @return [String] OpenStack volume UUID
- def create_disk(size, cloud_properties, server_id = nil)
- volume_service_client = @openstack.volume
- with_thread_name("create_disk(#{size}, #{cloud_properties}, #{server_id})") do
- raise ArgumentError, 'Disk size needs to be an integer' unless size.is_a?(Integer)
- cloud_error('Minimum disk size is 1 GiB') if size < 1024
-
- unique_name = generate_unique_name
- volume_params = {
- display_name: "volume-#{unique_name}",
- display_description: '',
- name: "volume-#{unique_name}",
- description: '',
- size: mib_to_gib(size),
- }
-
- if cloud_properties.key?('type')
- volume_params[:volume_type] = cloud_properties['type']
- elsif !@default_volume_type.nil?
- volume_params[:volume_type] = @default_volume_type
- end
-
- if server_id && @az_provider.use_server_availability_zone?
- server = openstack_server(server_id)
- volume_params[:availability_zone] = server.availability_zone if server&.availability_zone
- end
-
- @logger.info('Creating new volume...')
- new_volume = @openstack.with_openstack { volume_service_client.volumes.create(volume_params) }
-
- @logger.info("Creating new volume `#{new_volume.id}'...")
- @openstack.wait_resource(new_volume, :available)
-
- new_volume.id.to_s
- end
- end
-
- ##
- # Check whether an OpenStack volume exists or not
- #
- # @param [String] disk_id OpenStack volume UUID
- # @return [bool] whether the specific disk is there or not
- def has_disk?(disk_id)
- with_thread_name("has_disk?(#{disk_id})") do
- @logger.info("Check the presence of disk with id `#{disk_id}'...")
- volume = openstack_volume(disk_id)
-
- !volume.nil?
- end
- end
-
- ##
- # Deletes an OpenStack volume
- #
- # @param [String] disk_id OpenStack volume UUID
- # @return [void]
- # @raise [Bosh::Clouds::CloudError] if disk is not in available state
- def delete_disk(disk_id)
- with_thread_name("delete_disk(#{disk_id})") do
- @logger.info("Deleting volume `#{disk_id}'...")
- volume = openstack_volume(disk_id)
- if volume
- state = volume.status
- cloud_error("Cannot delete volume `#{disk_id}', state is #{state}") if state.to_sym != :available
-
- @openstack.with_openstack(retryable: true, ignore_not_found: true) { volume.destroy }
- @openstack.wait_resource(volume, :deleted, :status, true)
- else
- @logger.info("Volume `#{disk_id}' not found. Skipping.")
- end
- end
- end
-
- ##
- # Attaches an OpenStack volume to an OpenStack server
- #
- # @param [String] server_id OpenStack server UUID
- # @param [String] disk_id OpenStack volume UUID
- # @return [void]
- def attach_disk(server_id, disk_id)
- with_thread_name("attach_disk(#{server_id}, #{disk_id})") do
- server = openstack_server(server_id)
- cloud_error("Server `#{server_id}' not found") unless server
-
- volume = openstack_volume(disk_id)
- cloud_error("Volume `#{disk_id}' not found") unless volume
-
- device_name = attach_volume(server, volume)
-
- update_agent_settings(server) do |settings|
- settings['disks'] ||= {}
- settings['disks']['persistent'] ||= {}
- settings['disks']['persistent'][disk_id] = device_name
- end
-
- device_name if @cpi_api_version >= 2
- end
- end
-
- ##
- # Detaches an OpenStack volume from an OpenStack server
- #
- # @param [String] server_id OpenStack server UUID
- # @param [String] disk_id OpenStack volume UUID
- # @return [void]
- def detach_disk(server_id, disk_id)
- with_thread_name("detach_disk(#{server_id}, #{disk_id})") do
- server = openstack_server(server_id)
- cloud_error("Server `#{server_id}' not found") unless server
-
- volume = openstack_volume(disk_id)
- if volume.nil?
- @logger.info("Disk `#{disk_id}' not found while trying to detach it from vm `#{server_id}'...")
- else
- detach_volume(server, volume)
- end
-
- update_agent_settings(server) do |settings|
- settings['disks'] ||= {}
- settings['disks']['persistent'] ||= {}
- settings['disks']['persistent'].delete(disk_id)
- end
- end
- end
-
- ##
- # Takes a snapshot of an OpenStack volume
- #
- # @param [String] disk_id OpenStack volume UUID
- # @param [Hash] metadata Metadata key/value pairs to add to snapshot
- # @return [String] OpenStack snapshot UUID
- # @raise [Bosh::Clouds::CloudError] if volume is not found
- def snapshot_disk(disk_id, metadata)
- with_thread_name("snapshot_disk(#{disk_id})") do
- metadata = Hash[metadata.map { |key, value| [key.to_s, value] }]
- volume = openstack_volume(disk_id)
- cloud_error("Volume `#{disk_id}' not found") unless volume
-
- devices = []
- volume.attachments.each { |attachment| devices << attachment['device'] unless attachment.empty? }
-
- description = %w[deployment job index].collect { |key| metadata[key] }
- description << devices.first.split('/').last unless devices.empty?
- name = "snapshot-#{generate_unique_name}"
- snapshot_params = {
- display_name: name,
- display_description: description.join('/'),
- name:,
- description: description.join('/'),
- volume_id: volume.id,
- force: true,
- }
-
- @logger.info("Creating new snapshot for volume `#{disk_id}'...")
- snapshot = @openstack.volume.snapshots.new(snapshot_params)
- @openstack.with_openstack {
- snapshot.save
- }
-
- @logger.info("Creating new snapshot `#{snapshot.id}' for volume `#{disk_id}'...")
- @openstack.wait_resource(snapshot, :available)
-
- metadata.merge!(
- 'director' => metadata['director_name'],
- 'instance_index' => metadata['index'].to_s,
- 'instance_name' => metadata['job'] + '/' + metadata['instance_id'],
- )
-
- metadata.delete('director_name')
- metadata.delete('index')
- metadata.delete('job')
-
- @logger.info("Creating metadata for snapshot `#{snapshot.id}'...")
- @openstack.with_openstack {
- TagManager.tag_snapshot(snapshot, metadata)
- }
-
- snapshot.id.to_s
- end
- end
-
- ##
- # Deletes an OpenStack volume snapshot
- #
- # @param [String] snapshot_id OpenStack snapshot UUID
- # @return [void]
- # @raise [Bosh::Clouds::CloudError] if snapshot is not in available state
- def delete_snapshot(snapshot_id)
- with_thread_name("delete_snapshot(#{snapshot_id})") do
- @logger.info("Deleting snapshot `#{snapshot_id}'...")
- volume = @openstack.with_openstack { @openstack.volume }
- snapshot = @openstack.with_openstack(retryable: true) { volume.snapshots.get(snapshot_id) }
- if snapshot
- state = snapshot.status
- cloud_error("Cannot delete snapshot `#{snapshot_id}', state is #{state}") if state.to_sym != :available
-
- @openstack.with_openstack(retryable: true, ignore_not_found: true) { snapshot.destroy }
- @openstack.wait_resource(snapshot, :deleted, :status, true)
- else
- @logger.info("Snapshot `#{snapshot_id}' not found. Skipping.")
- end
- end
- end
-
- ##
- # Set metadata for an OpenStack server
- #
- # @param [String] server_id OpenStack server UUID
- # @param [Hash] metadata Metadata key/value pairs
- # @return [void]
- def set_vm_metadata(server_id, metadata)
- with_thread_name("set_vm_metadata(#{server_id}, ...)") do
- server = openstack_server(server_id)
- cloud_error("Server `#{server_id}' not found") unless server
- @openstack.with_openstack { TagManager.tag_server(server, metadata) }
-
- apply_human_readable_name(metadata, server_id) if human_readable_name?(server, server_id)
- end
- end
-
- ##
- # Set metadata for an OpenStack disk
- #
- # @param [String] disk_id OpenStack disk UUID
- # @param [Hash] metadata Metadata key/value pairs
- # @return [void]
- def set_disk_metadata(disk_id, metadata)
- with_thread_name("set_disk_metadata(#{disk_id}, ...)") do
- volume = openstack_volume(disk_id)
- cloud_error("Disk `#{disk_id}' not found") unless volume
- @openstack.with_openstack { TagManager.tag_volume(@openstack.volume, disk_id, metadata) }
- end
- end
-
- # Map a set of cloud agnostic VM properties (cpu, ram, ephemeral_disk_size) to
- # a set of OpenStack specific cloud_properties
- # @param [Hash] requirements requested cpu, ram, and ephemeral_disk_size
- # @return [Hash] OpenStack specific cloud_properties describing instance (e.g. instance_type)
- def calculate_vm_cloud_properties(requirements)
- required_keys = %w[cpu ram ephemeral_disk_size]
- missing_keys = required_keys.reject { |key| requirements[key] }
- unless missing_keys.empty?
- missing_keys.map! { |k| "'#{k}'" }
- raise "Missing VM cloud properties: #{missing_keys.join(', ')}"
- end
-
- @instance_type_mapper.map(
- requirements:,
- flavors: compute.flavors,
- boot_from_volume: @boot_from_volume,
- )
- end
-
- ##
- # Updates the agent settings
- #
- # @param [Fog::OpenStack::Compute::Server] server OpenStack server
- def update_agent_settings(server)
- raise ArgumentError, 'Block is not provided' unless block_given?
- registry_key = registry_key_for(server)
- unless cpi_without_registry?
- @logger.info("Updating settings for server '#{server.id}' with registry key '#{registry_key}'...")
- end
- settings = registry.read_settings(registry_key)
- yield settings
- registry.update_settings(registry_key, settings)
- end
-
- # Information about Openstack CPI, currently supported stemcell formats
- # @return [Hash] Openstack CPI properties
- def info
- { 'api_version' => 2, 'stemcell_formats' => ['openstack-raw', 'openstack-qcow2', 'openstack-light'] }
- end
-
- ##
- # Resizes an existing OpenStack volume
- #
- # @param [String] disk_id volume Cloud ID
- # @param [Integer] new_size disk size in MiB
- def resize_disk(disk_id, new_size)
- new_size_gib = mib_to_gib(new_size)
-
- with_thread_name("resize_disk(#{disk_id}, #{new_size_gib})") do
- @logger.info("Resizing volume `#{disk_id}'...")
- volume = openstack_volume(disk_id)
- cloud_error("Cannot resize volume because volume with #{disk_id} not found") unless volume
- actual_size_gib = volume.size
- if actual_size_gib == new_size_gib
- @logger.info("Skipping resize of disk #{disk_id} because current value #{actual_size_gib} GiB" \
- " is equal new value #{new_size_gib} GiB")
- elsif actual_size_gib > new_size_gib
- not_supported_error("Cannot resize volume to a smaller size from #{actual_size_gib} GiB to #{new_size_gib} GiB")
- else
- attachments = volume.attachments
- unless attachments.empty?
- cloud_error("Cannot resize volume '#{disk_id}' it still has #{attachments.size} attachment(s)")
- end
- @openstack.with_openstack { volume.extend(new_size_gib) }
- @logger.info("Resizing #{disk_id} from #{actual_size_gib} GiB to #{new_size_gib} GiB")
- @openstack.wait_resource(volume, :available)
- @logger.info("Disk #{disk_id} resized from #{actual_size_gib} GiB to #{new_size_gib} GiB")
- end
- end
-
- nil
- end
-
- def registry
- return @registry_instance if @registry_instance
-
- if cpi_without_registry?
- @registry_instance = Bosh::OpenStackCloud::NoopRegistry.new
- else
- begin
- registry_properties = @options.fetch('registry')
- registry_endpoint = registry_properties.fetch('endpoint')
- registry_user = registry_properties.fetch('user')
- registry_password = registry_properties.fetch('password')
- rescue KeyError => e
- raise ArgumentError, "Invalid CPI properties. Used CPI API version is #{@cpi_api_version} and stemcell API "\
- "version is #{stemcell_api_version}. Since at least one API version is 1, the registry has to be configured. "\
- "Error: #{e.message}"
- end
- @registry_instance = Bosh::Cpi::RegistryClient.new(registry_endpoint, registry_user, registry_password)
- end
- end
-
- private
-
- def apply_human_readable_name(metadata, server_id)
- name = metadata['name']
- job = metadata['job']
- index = metadata['index']
- compiling = metadata['compiling']
- if name
- @logger.debug("Rename VM with id '#{server_id}' to '#{name}'")
- update_servername(server_id, name.to_s)
- elsif job && index
- @logger.debug("Rename VM with id '#{server_id}' to '#{job}/#{index}'")
- update_servername(server_id, "#{job}/#{index}")
- elsif compiling
- @logger.debug("Rename VM with id '#{server_id}' to 'compiling/#{compiling}'")
- update_servername(server_id, "compiling/#{compiling}")
- end
- end
-
- def update_servername(server_id, name)
- @openstack.with_openstack { @openstack.compute.update_server(server_id, 'name' => name) }
- end
-
- def human_readable_name?(server, server_id)
- return true if (@human_readable_vm_names && cpi_without_registry?) ||
- @openstack.with_openstack(retryable: true) { server.metadata.get(REGISTRY_KEY_TAG) }
-
- @logger.debug("VM with id '#{server_id}' has no 'registry_key' tag")
- false
- end
-
- def cpi_without_registry?
- @cpi_api_version >= 2 && stemcell_api_version >= 2
- end
-
- def openstack_volume(disk_id)
- volumes = @openstack.with_openstack { @openstack.volume.volumes }
- @openstack.with_openstack(retryable: true) { volumes.get(disk_id) }
- end
-
- def openstack_server(server_id)
- servers = @openstack.with_openstack { @openstack.compute.servers }
- @openstack.with_openstack(retryable: true) { servers.get(server_id) }
- end
-
- def mib_to_gib(size)
- (size / 1024.0).ceil
- end
-
- def registry_key_for(server)
- registry_key_metadatum = @openstack.with_openstack(retryable: true) { server.metadata.get(REGISTRY_KEY_TAG) }
- registry_key_metadatum ? registry_key_metadatum.value : server.name
- end
-
- ##
- # Generates an unique name
- #
- # @return [String] Unique name
- def generate_unique_name
- SecureRandom.uuid
- end
-
- ##
- # Soft reboots an OpenStack server
- #
- # @param [Fog::OpenStack::Compute::Server] server OpenStack server
- # @return [void]
- def soft_reboot(server)
- @logger.info("Soft rebooting server `#{server.id}'...")
- @openstack.with_openstack { server.reboot }
- @openstack.wait_resource(server, :active, :state)
- end
-
- ##
- # Hard reboots an OpenStack server
- #
- # @param [Fog::OpenStack::Compute::Server] server OpenStack server
- # @return [void]
- def hard_reboot(server)
- @logger.info("Hard rebooting server `#{server.id}'...")
- @openstack.with_openstack { server.reboot('HARD') }
- @openstack.wait_resource(server, :active, :state)
- end
-
- ##
- # Attaches an OpenStack volume to an OpenStack server
- #
- # @param [Fog::OpenStack::Compute::Server] server OpenStack server
- # @param [Fog::OpenStack::Compute::Volume] volume OpenStack volume
- # @return [String] Device name
- def attach_volume(server, volume)
- @logger.info("Attaching volume `#{volume.id}' to server `#{server.id}'...")
- volume_attachments = @openstack.with_openstack(retryable: true) { server.volume_attachments }
- device = volume_attachments.find { |a| a['volumeId'] == volume.id }
-
- if device.nil?
- device_name = select_device_name(volume_attachments, first_device_name_letter(server))
- cloud_error('Server has too many disks attached') if device_name.nil?
-
- @logger.info("Attaching volume `#{volume.id}' to server `#{server.id}', device name is `#{device_name}'")
- @openstack.with_openstack { server.attach_volume(volume.id, device_name) }
- @openstack.wait_resource(volume, :'in-use')
- else
- device_name = device['device']
- @logger.info("Volume `#{volume.id}' is already attached to server `#{server.id}' in `#{device_name}'. Skipping.")
- end
-
- device_name
- end
-
- ##
- # Select the first available device name
- #
- # @param [Array] volume_attachments Volume attachments
- # @param [String] first_device_name_letter First available letter for device names
- # @return [String] First available device name or nil is none is available
- def select_device_name(volume_attachments, first_device_name_letter)
- (first_device_name_letter..'z').each do |char|
- # Some kernels remap device names (from sd* to vd* or xvd*).
- device_names = ["/dev/sd#{char}", "/dev/vd#{char}", "/dev/xvd#{char}"]
- # Bosh Agent will lookup for the proper device name if we set it initially to sd*.
- return "/dev/sd#{char}" if volume_attachments.select { |v| device_names.include?(v['device']) }.empty?
- @logger.warn("`/dev/sd#{char}' is already taken")
- end
-
- nil
- end
-
- ##
- # Returns the first letter to be used on device names
- #
- # @param [Fog::OpenStack::Compute::Server] server OpenStack server
- # @return [String] First available letter
- def first_device_name_letter(server)
- letter = FIRST_DEVICE_NAME_LETTER.dup
- return letter if server.flavor.nil?
- return letter unless server.flavor.key?('id')
- flavors = @openstack.compute.flavors
- flavor = @openstack.with_openstack(retryable: true) { flavors.find { |f| f.id == server.flavor['id'] } }
- return letter if flavor.nil?
-
- letter.succ! if flavor_has_ephemeral_disk?(flavor)
- letter.succ! if flavor_has_swap_disk?(flavor)
- letter.succ! if @config_drive == 'disk'
- letter
- end
-
- ##
- # Detaches an OpenStack volume from an OpenStack server
- #
- # @param [Fog::OpenStack::Compute::Server] server OpenStack server
- # @param [Fog::OpenStack::Compute::Volume] volume OpenStack volume
- # @return [void]
- def detach_volume(server, volume)
- @logger.info("Detaching volume `#{volume.id}' from `#{server.id}'...")
- volume_attachments = @openstack.with_openstack(retryable: true) { server.volume_attachments }
- attachment = volume_attachments.find { |a| a['volumeId'] == volume.id }
- if attachment
- @openstack.with_openstack { server.detach_volume(volume.id) }
- @openstack.wait_resource(volume, :available)
- else
- @logger.info("Disk `#{volume.id}' is not attached to server `#{server.id}'. Skipping.")
- end
- end
-
- ##
- # Checks if the OpenStack flavor has ephemeral disk
- #
- # @param [Fog::OpenStack::Compute::Flavor] OpenStack flavor
- # @return [Boolean] true if flavor has ephemeral disk, false otherwise
- def flavor_has_ephemeral_disk?(flavor)
- flavor.ephemeral && flavor.ephemeral.to_i > 0
- end
-
- ##
- # Checks if the OpenStack flavor has swap disk
- #
- # @param [Fog::OpenStack::Compute::Flavor] OpenStack flavor
- # @return [Boolean] true if flavor has swap disk, false otherwise
- def flavor_has_swap_disk?(flavor)
- flavor.swap.nil? || flavor.swap.to_i <= 0 ? false : true
- end
-
- ##
- # Checks if options passed to CPI are valid and can actually
- # be used to create all required data structures etc.
- #
- # @return [void]
- # @raise [ArgumentError] if options are not valid
- def validate_options
- raise ArgumentError, "Invalid OpenStack cloud properties: No 'openstack' properties specified." unless @options['openstack']
-
- auth_url = @options['openstack']['auth_url']
- user_domain_name = @options['openstack']['user_domain_name']
- project_domain_name = @options['openstack']['project_domain_name']
- project_id = @options['openstack']['project_id']
- username = @options['openstack']['username']
- api_key = @options['openstack']['api_key']
- application_credential_id = @options['openstack']['application_credential_id']
- application_credential_secret = @options['openstack']['application_credential_secret']
- validate_cloud_properties(username, api_key, application_credential_id, application_credential_secret)
-
- schema = Membrane::SchemaParser.parse do
- openstack_options_schema = {
- 'openstack' => {
- 'auth_url' => String,
- optional('region') => String,
- optional('endpoint_type') => String,
- optional('state_timeout') => Numeric,
- optional('stemcell_public_visibility') => bool,
- optional('connection_options') => Hash,
- optional('boot_from_volume') => bool,
- optional('default_key_name') => String,
- optional('default_security_groups') => [String],
- optional('default_volume_type') => String,
- optional('wait_resource_poll_interval') => Integer,
- optional('config_drive') => enum('disk', 'cdrom'),
- optional('human_readable_vm_names') => bool,
- optional('use_dhcp') => bool,
- optional('use_nova_networking') => bool,
- optional('vm') => Hash,
- },
- optional('registry') => {
- 'endpoint' => String,
- 'user' => String,
- 'password' => String,
- },
- optional('agent') => Hash,
- }
-
- if username
- openstack_options_schema['openstack']['username'] = String
- openstack_options_schema['openstack']['api_key'] = String
- else
- openstack_options_schema['openstack']['application_credential_id'] = String
- openstack_options_schema['openstack']['application_credential_secret'] = String
- end
-
- if Bosh::OpenStackCloud::Openstack.is_v3(auth_url)
- if project_id
- openstack_options_schema['openstack']['project_id'] = String
- else
- openstack_options_schema['openstack']['project'] = String
- end
- if user_domain_name || project_domain_name
- openstack_options_schema['openstack']['user_domain_name'] = String
- openstack_options_schema['openstack']['project_domain_name'] = String
- else
- openstack_options_schema['openstack']['domain'] = String
- end
- else
- openstack_options_schema['openstack']['tenant'] = String
- openstack_options_schema['openstack'][optional('domain')] = String
- end
- openstack_options_schema
- end
- schema.validate(@options)
- rescue Membrane::SchemaValidationError => e
- raise ArgumentError, "Invalid OpenStack cloud properties: #{e.inspect}"
- end
-
- def validate_cloud_properties(username, api_key, application_credential_id, application_credential_secret)
- return if valid_credentials?(username, api_key, application_credential_id, application_credential_secret)
- raise ArgumentError, 'Invalid OpenStack cloud properties: username and api_key or application_credential_id and application_credential_secret is required'
- end
-
- def valid_credentials?(username, api_key, application_credential_id, application_credential_secret)
- valid_user_credentials?(username, api_key, application_credential_id, application_credential_secret) ||
- valid_app_credentials?(username, api_key, application_credential_id, application_credential_secret)
- end
-
- def valid_user_credentials?(username, api_key, application_credential_id, application_credential_secret)
- username && api_key && !application_credential_id && !application_credential_secret
- end
-
- def valid_app_credentials?(username, api_key, application_credential_id, application_credential_secret)
- !username && !api_key && application_credential_id && application_credential_secret
- end
-
- def stemcell_api_version
- @options.dig('openstack', 'vm', 'stemcell', 'api_version') || 1
- end
-
- def normalize_options(options)
- raise ArgumentError, "Invalid OpenStack cloud properties: Hash expected, received #{options}" unless options.is_a?(Hash)
- # we only care about two top-level fields
- options = hash_filter(options.dup) { |key| OPTION_KEYS.include?(key) }
- # nil values should be treated the same as missing keys (makes validating optional fields easier)
- delete_entries_with_nil_keys(options)
- end
-
- def hash_filter(hash)
- copy = {}
- hash.each do |key, value|
- copy[key] = value if yield(key)
- end
- copy
- end
-
- def delete_entries_with_nil_keys(options)
- options.each do |key, value|
- if value.nil?
- options.delete(key)
- elsif value.is_a?(Hash)
- options[key] = delete_entries_with_nil_keys(value.dup)
- end
- end
- options
- end
-
- def metadata_to_tags(fog_metadata)
- fog_metadata.map { |metadatum| [metadatum.key, metadatum.value] }.to_h
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/cpi_lambda.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/cpi_lambda.rb
deleted file mode 100644
index 1b34328c6..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/cpi_lambda.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-module Bosh::OpenStackCloud
- class CpiLambda
- def self.create(cpi_config, cpi_log, ca_cert_from_config, ca_cert_from_context)
- lambda do |context, api_version|
- unless cpi_config.key?('cloud') && cpi_config['cloud'].key?('properties')
- raise 'Could not find cloud properties in the configuration'
- end
-
- cloud_properties = cpi_config['cloud']['properties']
- cloud_properties['cpi_log'] = cpi_log
-
- # If 'ca_cert' is set in job config we render non-empty `config/openstack.crt` (excon needs it as a file)
- connection_options = cloud_properties['openstack']['connection_options']
- connection_options['ssl_ca_file'] = ca_cert_from_config if connection_options&.delete('ca_cert')
-
- # allow openstack config to be overwritten dynamically by context
- cloud_properties['openstack'].merge!(context)
-
- # write ca cert to disk if given in context
- connection_options = cloud_properties['openstack']['connection_options']
- if connection_options && (ca_cert = connection_options.delete('ca_cert'))
- File.write(ca_cert_from_context, ca_cert)
- connection_options['ssl_ca_file'] = ca_cert_from_context
- end
-
- request_id = context['request_id']
- Bosh::Clouds::Config.logger.set_request_id(request_id) if request_id
-
- Bosh::Clouds::Openstack.new(cloud_properties, api_version)
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/dynamic_network.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/dynamic_network.rb
deleted file mode 100644
index 951368a2e..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/dynamic_network.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-module Bosh::OpenStackCloud
- ##
- # Represents OpenStack dynamic network: where IaaS sets VM's IP
- class DynamicNetwork < PrivateNetwork
- def prepare(_openstack, _security_group_ids)
- cloud_error("Network with id '#{net_id}' is a dynamic network. VRRP is not supported for dynamic networks") if @allowed_address_pairs
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/excon_logging_instrumentor.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/excon_logging_instrumentor.rb
deleted file mode 100644
index 5362eb331..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/excon_logging_instrumentor.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-module Bosh::OpenStackCloud
- class ExconLoggingInstrumentor
- REDACTED = ''.freeze
-
- class << self
- def instrument(name, params = {})
- redacted_params = redact(params)
- logger = Bosh::Clouds::Config.logger
-
- if name == 'excon.response'
- message = ResponseMessage.new(redacted_params).format
- logger.debug("#{name} #{message}")
-
- elsif name == 'excon.request'
- message = RequestMessage.new(redacted_params).format
- logger.debug("#{name} #{message}")
-
- elsif name == 'excon.error' && redacted_params[:error].respond_to?(:response)
- message = ResponseMessage.new(redacted_params[:error].response.data).format
- logger.debug("#{name} #{message}")
-
- else
- logger.debug("#{name} #{redacted_params}")
- end
-
- yield if block_given?
- end
-
- def redact(params)
- redacted_params = params.dup
- redact_body(redacted_params, 'auth.passwordCredentials.password')
- redact_body(redacted_params, 'server.user_data')
- redact_body(redacted_params, 'auth.identity.password.user.password')
- redact_body(redacted_params, 'auth.identity.application_credential.secret')
- redact_headers(redacted_params, 'X-Auth-Token')
- redacted_params
- end
-
- private
-
- def redact_body(params, json_path)
- return unless params.key?(:body) && params[:body].is_a?(String)
- return unless params.key?(:headers) && params[:headers]['Content-Type'] == 'application/json'
-
- begin
- json_content = JSON.parse(params[:body])
- rescue JSON::ParserError
- return
- end
- json_content = Bosh::Cpi::Redactor.redact!(json_content, json_path)
- params[:body] = JSON.dump(json_content)
- end
-
- def redact_headers(params, property)
- return unless params.key?(:headers)
- return unless params[:headers].key?(property)
-
- headers = params[:headers] = params[:headers].dup
-
- headers.store(property, REDACTED)
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/floating_ip.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/floating_ip.rb
deleted file mode 100644
index c9959c540..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/floating_ip.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-module Bosh::OpenStackCloud
- class FloatingIp
- include Helpers
-
- def self.reassociate(openstack, ip, server, network_id)
- if openstack.use_nova_networking?
- nova_reassociate(openstack, ip, server)
- else
- floating_ip = get_floating_ip(openstack, ip)
-
- if port_attached?(floating_ip)
- old_port = openstack.with_openstack(retryable: true) { openstack.network.get_port(floating_ip['port_id']).body['port'] }
- old_server = openstack.with_openstack(retryable: true) { openstack.compute.get_server_details(old_port['device_id']).body['server'] }
- disassociate(openstack, floating_ip, old_server['name'], old_server['id'])
- end
-
- port_id = get_port_id(openstack, server.id, network_id)
- Bosh::Clouds::Config.logger.info("Associating floating IP '#{ip}' with server '#{server.name} (#{server.id})'")
- openstack.network.associate_floating_ip(floating_ip['id'], port_id)
- end
- end
-
-
- def self.port_attached?(floating_ip)
- return false if floating_ip['port_id'].nil? || floating_ip['port_id'].empty?
-
- true
- end
-
- def self.disassociate(openstack, floating_ip, server_name, server_id)
- Bosh::Clouds::Config.logger.info("Disassociating floating IP '#{floating_ip['floating_ip_address']}' from server '#{server_name} (#{server_id})'")
- openstack.network.disassociate_floating_ip(floating_ip['id'])
- end
-
- def self.get_port_id(openstack, server_id, network_id)
- port = openstack.with_openstack(retryable: true) { openstack.network.ports.all(device_id: server_id, network_id:).first }
- cloud_error("Server has no port in network '#{network_id}'") unless port
- port.id
- end
-
- def self.get_floating_ip(openstack, ip)
- floating_ips = openstack.with_openstack(retryable: true) { openstack.network.list_floating_ips('floating_ip_address' => ip).body['floatingips'] }
- if floating_ips.length > 1
- cloud_error("Floating IP '#{ip}' found in multiple networks: #{floating_ips.map { |floating_ip| "'#{floating_ip['floating_network_id']}'" }.join(', ')}")
- elsif floating_ips.empty?
- cloud_error("Floating IP '#{ip}' not allocated")
- end
- floating_ips.first
- end
-
- def self.nova_reassociate(openstack, ip, server)
- address = openstack.with_openstack(retryable: true) { openstack.compute.addresses.find { |a| a.ip == ip } }
- if address
- unless address.instance_id.nil?
- Bosh::Clouds::Config.logger.info("Disassociating floating IP '#{ip}' from server '#{address.instance_id}'")
- address.server = nil
- end
-
- Bosh::Clouds::Config.logger.info("Associating floating IP '#{ip}' with server '#{server.id}'")
- address.server = server
- else
- cloud_error("Floating IP #{ip} not allocated")
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/helpers.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/helpers.rb
deleted file mode 100644
index 56a8ef074..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/helpers.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-module Bosh::OpenStackCloud
- module Helpers
- def self.included(base)
- base.extend(Helpers)
- end
-
- ##
- # Raises CloudError exception
- #
- # @param [String] message Message about what went wrong
- # @param [Exception] exception Exception to be logged (optional)
- def cloud_error(message, exception = nil)
- raise_error(Bosh::Clouds::CloudError, exception, message)
- end
-
- def not_supported_error(message, exception = nil)
- raise_error(Bosh::Clouds::NotSupported, exception, message)
- end
-
- def fail_on_error(*error_wrappers)
- error_wrappers = error_wrappers.compact
- return if error_wrappers.empty?
-
- error_wrappers.each do |error_wrapper|
- @logger.error(error_wrapper.error)
- @logger.error(error_wrapper.error.backtrace)
- end
-
- message = error_wrappers.map(&:message).join("\n")
- prefix = error_wrappers.size > 1 ? "Multiple cloud errors occurred:\n" : ''
-
- raise Bosh::Clouds::CloudError, prefix + message
- end
-
- def catch_error(prefix = nil)
- return nil unless block_given?
- begin
- yield
- rescue StandardError => e
- return ErrorWrapper.new(e, prefix)
- end
-
- nil
- end
-
- private
-
- class ErrorWrapper
- attr_reader :error, :prefix
-
- def initialize(error, prefix=nil)
- @error = error
- @prefix = prefix
- end
-
- def message
- if prefix
- "#{prefix}: #{error.message}"
- else
- error.message
- end
- end
- end
-
-
- def raise_error(error_class, exception, message)
- @logger&.error(message)
- @logger.error(exception) if @logger && exception
- raise error_class, message
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/instance_type_mapper.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/instance_type_mapper.rb
deleted file mode 100644
index 0368d138a..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/instance_type_mapper.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-module Bosh::OpenStackCloud
- class InstanceTypeMapper
- OS_OVERHEAD_IN_GB = 3
- NO_DISK = 0
-
- def map(requirements:, flavors:, boot_from_volume: false)
- normalized_requirements = convert_disk_to_GB(requirements)
-
- possible_flavors = find_possible_flavors(normalized_requirements, flavors, boot_from_volume)
- if possible_flavors.empty?
- raise ["Unable to meet requested VM requirements: #{requirements['cpu']} CPU, #{requirements['ram']} MB RAM, #{requirements['ephemeral_disk_size'] / 1024.0} GB Disk.\n",
- "Available flavors:\n",
- flavors.map { |flavor| "#{flavor.name}: #{flavor.vcpus} CPU, #{flavor.ram} MB RAM, #{flavor.disk} GB Disk\n" }].join
- end
-
- closest_match = possible_flavors.min_by do |flavor|
- [flavor.vcpus, flavor.ram, flavor.disk + flavor.ephemeral, flavor.disk]
- end
-
- vm_cloud_properties(normalized_requirements, closest_match, boot_from_volume)
- end
-
- private
-
- def find_possible_flavors(requirements, flavors, boot_from_volume)
- valid_flavors = flavors.select do |flavor|
- flavor.vcpus >= requirements['cpu'] &&
- flavor.ram >= requirements['ram'] &&
- flavor.disabled != true
- end
-
- if boot_from_volume
- boot_from_volume_flavors(valid_flavors)
- else
- boot_default_flavors(requirements, valid_flavors)
- end
- end
-
- def boot_from_volume_flavors(valid_flavors)
- valid_flavors.select { |flavor| flavor.ephemeral == NO_DISK }
- end
-
- def boot_default_flavors(requirements, valid_flavors)
- flavors_meeting_ephemeral_requirement = valid_flavors.select do |flavor|
- flavor.ephemeral >= requirements['ephemeral_disk_size'].ceil &&
- flavor.disk >= OS_OVERHEAD_IN_GB
- end
- return flavors_meeting_ephemeral_requirement unless flavors_meeting_ephemeral_requirement.empty?
-
- flavors_meeting_root_requirement = valid_flavors.select do |flavor|
- flavor.ephemeral == NO_DISK &&
- flavor.disk >= requirements['ephemeral_disk_size'].ceil + OS_OVERHEAD_IN_GB
- end
-
- flavors_meeting_root_requirement
- end
-
- def convert_disk_to_GB(requirements)
- normalized = requirements.clone
- normalized['ephemeral_disk_size'] = requirements['ephemeral_disk_size'] / 1024.0
- normalized
- end
-
- def vm_cloud_properties(requirements, closest_match, boot_from_volume)
- properties = {
- 'instance_type' => closest_match.name,
- }
-
- if boot_from_volume && root_disk_size(closest_match) < required_boot_volume_size(requirements)
- properties.merge(
- 'root_disk' => {
- 'size' => required_boot_volume_size(requirements),
- },
- )
- else
- properties
- end
- end
-
- def required_boot_volume_size(requirements)
- OS_OVERHEAD_IN_GB + requirements['ephemeral_disk_size']
- end
-
- def root_disk_size(flavor)
- flavor.disk
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/loadbalancer_configurator.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/loadbalancer_configurator.rb
deleted file mode 100644
index 2dfa99c36..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/loadbalancer_configurator.rb
+++ /dev/null
@@ -1,224 +0,0 @@
-module Bosh::OpenStackCloud
- class LoadbalancerConfigurator
- def initialize(openstack, logger)
- @openstack = openstack
- @logger = logger
- end
-
- def create_pool_memberships(server, network_spec, pools)
- pools
- .map { |pool| add_vm_to_pool(server, network_spec, pool) }
- .each_with_index
- .map do |membership, index|
- ["lbaas_pool_#{index + 1}", "#{membership.pool_id}/#{membership.membership_id}"]
- end
- .to_h
- end
-
- def add_vm_to_pool(server, network_spec, pool_spec)
- validate_configuration(pool_spec)
- openstack_pool_id = openstack_pool_id(pool_spec['name'])
- ip = NetworkConfigurator.gateway_ip(network_spec, @openstack, server)
- subnet_id = matching_subnet_id(network_spec, ip)
- membership_id = create_membership(openstack_pool_id, ip, pool_spec['port'], subnet_id)
- LoadbalancerPoolMembership.new(pool_spec['name'], pool_spec['port'], openstack_pool_id, membership_id)
- rescue Bosh::Clouds::VMCreationFailed => e
- message = "VM with id '#{server.id}' cannot be attached to load balancer pool '#{pool_spec['name']}'. Reason: #{e.message}"
- raise Bosh::Clouds::VMCreationFailed.new(false), message
- end
-
- def create_membership(pool_id, ip, port, subnet_id)
- @openstack.with_openstack do
- membership_id = nil
- begin
- @logger.debug("Creating load balancer pool membership with pool id '#{pool_id}', ip '#{ip}', and port '#{port}'.")
- membership_id = retry_on_conflict_pending_update(pool_id) {
- @openstack.network.create_lbaas_pool_member(pool_id, ip, port, subnet_id:).body['member']['id']
- }
- rescue Excon::Error::Conflict
- lbaas_pool_members = @openstack.with_openstack(retryable: true) { @openstack.network.list_lbaas_pool_members(pool_id) }
- membership_id =
- lbaas_pool_members
- .body.fetch('members', [])
- .detect(
- raise_if_not_found(pool_id, ip, port),
- &matching_member(ip, port, subnet_id)
- )
- .fetch('id')
-
- @logger.info("Load balancer pool membership with pool id '#{pool_id}', ip '#{ip}', and port '#{port}' already exists. The membership has the id '#{membership_id}'.")
- rescue LoadBalancerResource::NotFound, LoadBalancerResource::NotSupportedConfiguration => e
- raise Bosh::Clouds::VMCreationFailed.new(false), e.message
- rescue StandardError => e
- raise Bosh::Clouds::CloudError, "Creating load balancer pool membership with pool_id '#{pool_id}' and membership_id '#{membership_id}' failed. Reason: #{e.class} #{e.message}"
- end
- membership_id
- end
- end
-
- def raise_if_not_found(pool_id, ip, port)
- -> { raise Bosh::Clouds::CloudError, "Load balancer pool membership with pool id '#{pool_id}', ip '#{ip}', and port '#{port}' supposedly exists, but cannot be found." }
- end
-
- def matching_member(ip, port, subnet_id)
- ->(member) { member['address'] == ip && member['protocol_port'] == port && member['subnet_id'] == subnet_id }
- end
-
- def cleanup_memberships(server_metadata)
- server_metadata
- .select { |key, _| key.start_with?('lbaas_pool_') }
- .map { |_, value| value.split('/') }
- .each { |pool_id, membership_id| remove_vm_from_pool(pool_id, membership_id) }
- end
-
- def remove_vm_from_pool(pool_id, membership_id)
- @openstack.with_openstack(retryable: true) do
- begin
- @logger.debug("Deleting load balancer pool membership with pool id '#{pool_id}' and membership id '#{membership_id}'.")
- retry_on_conflict_pending_update(pool_id) {
- @openstack.network.delete_lbaas_pool_member(pool_id, membership_id)
- }
- rescue Fog::OpenStack::Network::NotFound
- @logger.debug("Skipping deletion of load balancer pool membership. Member with pool_id '#{pool_id}' and membership_id '#{membership_id}' does not exist.")
- rescue LoadBalancerResource::NotFound => e
- @logger.debug("Skipping deletion of load balancer pool membership because load balancer resource cannot be found. #{e.message}")
- rescue StandardError => e
- raise Bosh::Clouds::CloudError, "Deleting load balancer pool membership with pool_id '#{pool_id}' and membership_id '#{membership_id}' failed. Reason: #{e.class} #{e.message}"
- end
- end
- end
-
- def retry_on_conflict_pending_update(pool_id)
- action_result = nil
- start_time = Time.now
- attempts = 0
-
- loadbalancer_id = loadbalancer_id(pool_id)
- resource = LoadBalancerResource.new(loadbalancer_id, @openstack)
-
- loop do
- @openstack.wait_resource(resource, :active, :provisioning_status)
- attempts += 1
- action_result = yield
- break
- rescue Excon::Error::Conflict => e
- neutron_error = @openstack.parse_openstack_response(e.response, 'NeutronError')
- if neutron_error&.fetch('message', '')&.include? 'PENDING_UPDATE'
- @logger.debug("Changing load balancer resource failed with '#{e.message}', unsuccessful attempts: '#{attempts}'")
- if Time.now - start_time >= @openstack.state_timeout
- @openstack.cloud_error("Failed after #{Time.now - start_time}s with #{attempts} attempts with '#{e.message}'")
- end
- else
- raise e
- end
- end
- @openstack.wait_resource(resource, :active, :provisioning_status)
-
- action_result
- end
-
- def loadbalancer_id(pool_id)
- pool_response = @openstack.with_openstack(retryable: true) do
- begin
- @openstack.network.get_lbaas_pool(pool_id)
- rescue Fog::OpenStack::Network::NotFound => e
- raise LoadBalancerResource::NotFound, "Load balancer ID could not be determined because pool with ID '#{pool_id}' was not found. Reason: #{e.message}"
- end
- end
- loadbalancers = pool_response.body['pool']['loadbalancers'] ||
- retrieve_loadbalancers_via_listener(
- pool_response.body['pool']['listeners'],
- pool_id,
- )
- extract_loadbalancer_id(loadbalancers, pool_id)
- end
-
- private
-
- def retrieve_loadbalancers_via_listener(listeners, pool_id)
- if listeners.empty?
- raise LoadBalancerResource::NotFound, "No listeners associated with load balancer pool '#{pool_id}'"
- elsif listeners.size > 1
- raise LoadBalancerResource::NotSupportedConfiguration, "More than one listener is associated with load balancer pool '#{pool_id}'. It is not possible to verify the status of the load balancer responsible for the pool membership."
- end
-
- listener_response = @openstack.with_openstack(retryable: true) { @openstack.network.get_lbaas_listener(listeners[0]['id']) }
- listener_response.body['listener']['loadbalancers']
- end
-
- def extract_loadbalancer_id(loadbalancers, pool_id)
- if loadbalancers.empty?
- raise LoadBalancerResource::NotFound, "No load balancers associated with load balancer pool '#{pool_id}'"
- elsif loadbalancers.size > 1
- raise LoadBalancerResource::NotSupportedConfiguration, "More than one load balancer is associated with load balancer pool '#{pool_id}'. It is not possible to verify the status of the load balancer responsible for the pool membership."
- end
-
- loadbalancers[0]['id']
- end
-
- def matching_subnet_id(network_spec, ip)
- subnet_ids = NetworkConfigurator.matching_gateway_subnet_ids_for_ip(network_spec, @openstack, ip)
- if subnet_ids.size > 1
- raise Bosh::Clouds::VMCreationFailed.new(false), "In network '#{NetworkConfigurator.get_gateway_network_id(network_spec)}' more than one subnet CIDRs match the IP '#{ip}'"
- end
- if subnet_ids.empty?
- raise Bosh::Clouds::VMCreationFailed.new(false), "Network '#{NetworkConfigurator.get_gateway_network_id(network_spec)}' does not contain any subnet to match the IP '#{ip}'"
- end
- subnet_ids.first
- end
-
- def validate_configuration(pool_spec)
- raise Bosh::Clouds::VMCreationFailed.new(false), 'Load balancer pool defined without a name' unless pool_spec['name']
-
- unless pool_spec['port']
- raise Bosh::Clouds::VMCreationFailed.new(false), "Load balancer pool '#{pool_spec['name']}' has no port definition"
- end
- end
-
- class LoadbalancerPoolMembership
- attr_reader :name, :port, :membership_id, :pool_id
-
- def initialize(name, port, pool_id, membership_id)
- @name = name
- @port = port
- @pool_id = pool_id
- @membership_id = membership_id
- end
- end
-
- def openstack_pool_id(pool_name)
- pools = @openstack.with_openstack(retryable: true) {
- @openstack.network.list_lbaas_pools('name' => pool_name).body['pools']
- }
-
- if pools.empty?
- raise Bosh::Clouds::VMCreationFailed.new(false), "Load balancer pool '#{pool_name}' does not exist"
- elsif pools.size > 1
- raise Bosh::Clouds::VMCreationFailed.new(false), "Load balancer pool '#{pool_name}' exists multiple times. Make sure to use unique naming."
- end
- pools.first['id']
- end
-
- class LoadBalancerResource
- attr_reader :id
-
- def initialize(loadbalancer_id, openstack)
- @id = loadbalancer_id
- @openstack = openstack
- end
-
- def reload
- true
- end
-
- def provisioning_status
- @openstack.with_openstack(retryable: true) do
- @openstack.network.get_lbaas_loadbalancer(@id).body['loadbalancer']['provisioning_status']
- end
- end
-
- class NotFound < StandardError; end
- class NotSupportedConfiguration < StandardError; end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/manual_network.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/manual_network.rb
deleted file mode 100644
index 76373a180..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/manual_network.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-module Bosh::OpenStackCloud
- ##
- # Represents OpenStack manual network: where user sets VM's IP
- class ManualNetwork < PrivateNetwork
- ##
- # Creates a new manual network
- #
- # @param [String] name Network name
- # @param [Hash] spec Raw network spec
- def initialize(name, spec)
- super
- @vrrp_port_check = @spec
- .fetch('cloud_properties', {})
- .fetch('vrrp_port_check', true)
- end
-
- ##
- # Returns the private IP address
- #
- # @return [String] ip address
- def private_ip
- @ip
- end
-
- ##
- # Returns the vrrp port check
- # true: port check enabled
- # false: port check disabled
- def vrrp_port_check_enabled?
- @vrrp_port_check
- end
-
- def prepare(openstack, security_group_ids)
- if openstack.use_nova_networking?
- @nic['v4_fixed_ip'] = @ip
- else
- @logger.debug("Creating port for IP #{@ip} in network #{net_id}")
- port = create_port_for_manual_network(openstack, net_id, security_group_ids)
- @logger.debug("Port with ID #{port.id} and MAC address #{port.mac_address} created")
- @nic['port_id'] = port.id
- @spec['mac'] = port.mac_address
- end
- end
-
- def cleanup(openstack)
- unless openstack.use_nova_networking?
- ports = openstack.with_openstack { openstack.network.ports }
- port = openstack.with_openstack(retryable: true) { ports.get(@nic['port_id']) }
- openstack.with_openstack(retryable: true, ignore_not_found: true) { port&.destroy }
- end
- end
-
- private
-
- def create_port_for_manual_network(openstack, net_id, security_group_ids)
- port_properties = {
- network_id: net_id,
- fixed_ips: [{ ip_address: @ip }],
- security_groups: security_group_ids,
- }
- if @allowed_address_pairs
- @logger.debug("VRRP port check for #{@allowed_address_pairs} is #{vrrp_port_check_enabled?}")
- cloud_error("Configured VRRP port with ip '#{@allowed_address_pairs}' does not exist.") unless vrrp_port?(openstack)
- port_properties[:allowed_address_pairs] = [{ ip_address: @allowed_address_pairs }]
- end
- openstack.with_openstack do
- retried = false
- begin
- openstack.network.ports.create(port_properties)
- rescue Excon::Error::Conflict => e
- raise e if retried
- delete_conflicting_unused_ports(openstack, net_id)
- @logger.info("Retrying to create port for IP #{@ip} in network #{net_id}")
- retried = true
- retry
- end
- end
- end
-
- def delete_conflicting_unused_ports(openstack, net_id)
- ports = openstack.with_openstack(retryable: true) do
- openstack.network.ports.all(fixed_ips: ["ip_address=#{@ip}", "network_id=#{net_id}"])
- end
- detached_port_ids = ports.select { |p| p.status == 'DOWN' && p.device_id.empty? && p.device_owner.empty? }.map(&:id)
- @logger.warn("IP #{@ip} already allocated: Deleting conflicting unused ports with ids=#{detached_port_ids}")
- NetworkConfigurator.cleanup_ports(openstack, detached_port_ids)
- end
-
- def vrrp_port?(openstack)
- return true unless vrrp_port_check_enabled?
-
- vrrp_port = openstack.with_openstack(retryable: true) do
- openstack.network.ports.all(fixed_ips: "ip_address=#{@allowed_address_pairs}")
- end
- !(vrrp_port.nil? || vrrp_port.empty?)
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/network.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/network.rb
deleted file mode 100644
index f6ad9c5d7..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/network.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-module Bosh::OpenStackCloud
- ##
- # Represents OpenStack network.
- class Network
- include Helpers
-
- attr_reader :name, :spec
-
- ##
- # Creates a new network
- #
- # @param [String] name Network name
- # @param [Hash] spec Raw network spec
- def initialize(name, spec)
- raise ArgumentError, "Invalid spec, Hash expected, #{spec.class} provided" unless spec.is_a?(Hash)
-
- @logger = Bosh::Clouds::Config.logger
- @spec = spec
- @name = name
- @ip = spec['ip']
- @cloud_properties = spec['cloud_properties']
- end
-
- ##
- # Configures given server
- #
- # @param [Bosh::OpenStackCloud::Openstack] openstack
- # @param [Fog::OpenStack::Compute::Server] server OpenStack server to configure
- def configure(openstack, server); end
-
- def prepare(openstack, security_groups); end
-
- def cleanup(openstack); end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/network_configurator.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/network_configurator.rb
deleted file mode 100644
index ddddeb76b..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/network_configurator.rb
+++ /dev/null
@@ -1,263 +0,0 @@
-module Bosh::OpenStackCloud
- ##
- # Represents OpenStack server network config. OpenStack server has single NIC
- # with a dynamic or manual IP's address and (optionally) a single floating
- # IP address which server itself is not aware of (vip). Thus we should
- # perform a number of sanity checks for the network spec provided by director
- # to make sure we don't apply something OpenStack doesn't understand how to
- # deal with.
- class NetworkConfigurator
- include Helpers
-
- attr_reader :network_spec, :networks, :picked_security_groups
-
- ##
- # Creates new network spec
- #
- # @param [Hash] spec Raw network spec passed by director
- def initialize(spec, allowed_address_pairs = nil)
- raise ArgumentError, "Invalid spec, Hash expected, #{spec.class} provided" unless spec.is_a?(Hash)
-
- @network_spec = spec
- @logger = Bosh::Clouds::Config.logger
- @networks = []
- @vip_network = nil
- @security_groups = []
- @picked_security_groups = []
- @net_ids = []
- @dynamic_network = nil
-
- spec.each_pair do |name, network_spec|
- initialize_network(name, network_spec)
- end
-
- cloud_error('At least one dynamic or manual network should be defined') if @networks.empty?
- add_vrrp_ip_to_default_network(allowed_address_pairs) if allowed_address_pairs
- end
-
- def check_preconditions(use_nova_networking, config_drive, use_dhcp)
- return unless multiple_private_networks?
-
- if use_nova_networking
- error_message = "Multiple manual networks can only be used with 'openstack.use_nova_networking=false'. Multiple networks require Neutron."
- raise Bosh::Clouds::VMCreationFailed.new(false), error_message
- end
-
- if use_dhcp || !config_drive
- error_message = "Multiple manual networks can only be used with 'openstack.use_dhcp=false' and 'openstack.config_drive=cdrom|disk'"
- raise Bosh::Clouds::VMCreationFailed.new(false), error_message
- end
- end
-
- def pick_groups(openstack, default_security_groups, resource_pool_groups)
- @picked_security_groups = SecurityGroups.new(openstack).select_and_retrieve(
- default_security_groups,
- security_groups,
- resource_pool_groups,
- )
- @logger.debug("Using security groups: `#{@picked_security_groups.map(&:name).join(', ')}'")
- end
-
- def prepare(openstack)
- security_group_ids = picked_security_groups.map(&:id)
- @networks.each do |network|
- network.prepare(openstack, security_group_ids)
- end
- end
-
- def cleanup(openstack)
- @networks.each do |network|
- network.cleanup(openstack)
- end
- end
-
- ##
- # Setup network configuration for one network spec.
- #
- # @param [String] name
- # @param [Hash] network_spec
- def initialize_network(name, network_spec)
- network_type = NetworkConfigurator.network_type(network_spec)
-
- case network_type
- when 'dynamic'
- cloud_error('Only one dynamic network per instance should be defined') if @dynamic_network
- net_id = NetworkConfigurator.extract_net_id(network_spec)
- cloud_error("Dynamic network with id #{net_id} is already defined") if @net_ids.include?(net_id)
- network = DynamicNetwork.new(name, network_spec)
- @security_groups += extract_security_groups(network_spec)
- @networks << network
- @net_ids << net_id
- @dynamic_network = network
- when 'manual'
- net_id = NetworkConfigurator.extract_net_id(network_spec)
- cloud_error('Manual network must have net_id') if net_id.nil?
- cloud_error("Manual network with id #{net_id} is already defined") if @net_ids.include?(net_id)
- network = ManualNetwork.new(name, network_spec)
- @security_groups += extract_security_groups(network_spec)
- @networks << network
- @net_ids << net_id
- when 'vip'
- cloud_error('Only one VIP network per instance should be defined') if @vip_network
- @vip_network = VipNetwork.new(name, network_spec)
- @security_groups += extract_security_groups(network_spec)
- else
- cloud_error("Invalid network type `#{network_type}': OpenStack " \
- "CPI can only handle `dynamic', 'manual' or `vip' " \
- 'network types')
- end
-
- @security_groups.uniq!
- end
-
- def self.get_gateway_network(network_spec)
- private_network_specs = private_network_specs(network_spec)
- spec = if private_network_specs.size == 1
- private_network_specs.first
- else
- private_network_specs.select do |spec|
- spec['default']&.include?('gateway')
- end.first
- end
- spec
- end
-
- def self.get_gateway_network_id(network_spec)
- network = get_gateway_network(network_spec)
- extract_net_id(network)
- end
-
- def self.matching_gateway_subnet_ids_for_ip(network_spec, openstack, ip)
- network_id = get_gateway_network_id(network_spec)
- network_subnets = openstack.with_openstack(retryable: true) { openstack.network.list_subnets('network_id' => network_id).body['subnets'] }
- network_subnets.select do |subnet|
- NetAddr.parse_net(subnet['cidr']).contains(NetAddr.parse_ip(ip))
- end.map { |subnet| subnet['id'] }
- end
-
- def self.gateway_ip(network_spec, openstack, server)
- network = get_gateway_network(network_spec)
- network_type = network_type(network)
-
- if network_type == 'manual'
- network['ip']
- elsif network_type == 'dynamic'
- if private_network_specs(network_spec).size > 1
- raise Bosh::Clouds::VMCreationFailed.new(false), 'Gateway IP address could not be determined. Gateway network is dynamic, but additional private networks exist.'
- end
-
- openstack.with_openstack(retryable: true) {
- return server.addresses.values.first.dig(0, 'addr')
- }
- end
- end
-
- def self.network_type(network)
- # in case of a manual network bosh doesn't provide a type.
- network.fetch('type', 'manual')
- end
-
- def self.private_network_specs(network_spec)
- network_spec.values.reject { |spec| spec['type'] == 'vip' }
- end
-
- ##
- # Extracts the network ID from the network configuration
- #
- # @param [Hash] network_spec Network specification
- # @return [Hash] network ID
- def self.extract_net_id(network_spec)
- if network_spec && network_spec['cloud_properties']
- cloud_properties = network_spec['cloud_properties']
- return cloud_properties['net_id'] if cloud_properties&.key?('net_id')
- end
- nil
- end
-
- ##
- # Applies network configuration to the vm
- #
- # @param [Bosh::OpenStackCloud::Openstack] openstack
- # @param [Fog::OpenStack::Compute::Server] server OpenStack server to
- # configure
- def configure(openstack, server)
- @networks.each do |network|
- network.configure(openstack, server)
- end
-
- @vip_network&.configure(openstack, server, NetworkConfigurator.get_gateway_network_id(@network_spec))
- end
-
- ##
- # Returns the sorted security groups for this network configuration
- #
- # @return [Array] security groups
- def security_groups
- @security_groups.sort
- end
-
- ##
- # Returns the nics for this network configuration
- #
- # @return [Array] nics
- def nics
- @networks.each_with_object([]) do |network, memo|
- nic = network.nic
- memo << nic if nic.any?
- end
- end
-
- def self.port_ids(openstack, server_id)
- return [] if openstack.use_nova_networking?
- ports = openstack.with_openstack(retryable: true) do
- openstack.network.ports.all(device_id: server_id)
- end
- ports.map(&:id)
- end
-
- def self.cleanup_ports(openstack, port_ids)
- return if openstack.use_nova_networking?
- port_ids.each do |port_id|
- port = openstack.with_openstack(retryable: true) { openstack.network.ports.get(port_id) }
- if port
- Bosh::Clouds::Config.logger.debug("Deleting port #{port_id}")
- openstack.with_openstack(retryable: true, ignore_not_found: true) { port.destroy }
- end
- end
- end
-
- private
-
- def add_vrrp_ip_to_default_network(allowed_address_pairs)
- @networks.each do |network|
- network.allowed_address_pairs = allowed_address_pairs if default_network?(network)
- end
- end
-
- def default_network?(network)
- default_network_spec = NetworkConfigurator.get_gateway_network(@network_spec)
- network.spec == default_network_spec
- end
-
- def multiple_private_networks?
- @networks.length > 1
- end
-
- ##
- # Extracts the security groups from the network configuration
- #
- # @param [Hash] network_spec Network specification
- # @return [Array] security groups
- # @raise [ArgumentError] if the security groups in the network_spec is not an Array
- def extract_security_groups(network_spec)
- if network_spec && network_spec['cloud_properties']
- cloud_properties = network_spec['cloud_properties']
- if cloud_properties&.key?('security_groups')
- raise ArgumentError, 'security groups must be an Array' unless cloud_properties['security_groups'].is_a?(Array)
- return cloud_properties['security_groups']
- end
- end
- []
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/noop_registry.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/noop_registry.rb
deleted file mode 100644
index 579d16572..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/noop_registry.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-module Bosh::OpenStackCloud
- class NoopRegistry
- include Helpers
-
- def initialize(endpoint = nil, user = nil, password = nil) end
-
- def update_settings(instance_id, settings) end
-
- def read_settings(_instance_id)
- {}
- end
-
- def delete_settings(instance_id) end
-
- def endpoint
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/openstack.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/openstack.rb
deleted file mode 100644
index 1ce64bff6..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/openstack.rb
+++ /dev/null
@@ -1,341 +0,0 @@
-require 'common/common'
-
-module Bosh::OpenStackCloud
- class Openstack
- include Helpers
-
- DEFAULT_STATE_TIMEOUT = 300 # Default timeout for target state (in seconds)
- MAX_RETRIES = 10 # Max number of retries
- DEFAULT_RETRY_TIMEOUT = 3 # Default timeout before retrying a call (in seconds)
-
- attr_reader :auth_url, :params, :is_v3, :state_timeout
-
- def self.is_v3(auth_url)
- auth_url.match(/\/v3(?=\/|$)/) || !auth_url.match(/\/v2.0(?=\/|$)/)
- end
-
- def initialize(options, retry_options_overwrites = {}, extra_connection_options = { 'instrumentor' => Bosh::OpenStackCloud::ExconLoggingInstrumentor })
- @logger = Bosh::Clouds::Config.logger
- @is_v3 = Openstack.is_v3(options['auth_url'])
-
- @auth_url = build_auth_url(options['auth_url'])
-
- @use_nova_networking = options.fetch('use_nova_networking', false)
- if @use_nova_networking
- @logger.debug("Property 'use_nova_networking' is set to true. Using Nova networking APIs instead of Neutron APIs.")
- end
-
- options['connection_options'] ||= {}
-
- @extra_connection_options = extra_connection_options
- @state_timeout = options['state_timeout'] || DEFAULT_STATE_TIMEOUT
- @wait_resource_poll_interval = options['wait_resource_poll_interval']
-
- @params = openstack_params(options)
- @retry_options = {
- sleep: 1,
- tries: 5,
- on: [Excon::Error::GatewayTimeout, Excon::Error::Socket],
- }.merge(retry_options_overwrites)
- end
-
- def with_openstack(retryable: false, ignore_not_found: false)
- retries = 0
- retryable_errors = [Excon::Error::Timeout,
- Excon::Error::Socket,
- Excon::Error::ServiceUnavailable,
- Excon::Error::InternalServerError]
- begin
- yield
- rescue Excon::Error::RequestEntityTooLarge => e
- overlimit = parse_openstack_response(e.response, 'overLimit', 'overLimitFault')
-
- raise_openstack_error(e, format_error(e, e.response.body)) unless overlimit
- raise_openstack_error(e, format_error(e, overlimit['message'])) unless retries < MAX_RETRIES
-
- wait_time = overlimit['retryAfter'] || e.response.headers['Retry-After'] || DEFAULT_RETRY_TIMEOUT
- overlimit_msg = "Over Limit: #{overlimit['message']} - #{overlimit['details']}"
- log_retry_error(e, retries, overlimit_msg, wait_time)
- sleep(wait_time.to_i)
- retries += 1
- retry
- rescue Fog::Errors::NotFound => e
- raise_openstack_error(e) unless ignore_not_found
- @logger.debug("Suppressed 'not found' error message: #{e.message}")
- rescue Excon::Error::BadRequest, Excon::Error::Conflict, Excon::Error::Forbidden => e
- raise_openstack_error(e, format_error_body(e))
- rescue *retryable_errors => e
- raise_openstack_error(e) unless retries < MAX_RETRIES &&
- (dns_problem?(e) || (connectivity_problem?(e) && retryable) || server_problem?(e))
-
- retries += 1
- log_retry_error(e, retries)
- sleep(DEFAULT_RETRY_TIMEOUT)
- retry
- end
- end
-
- def project_name
- if is_v3
- # Check if our connection is done through the openstack_project_name
- if params.key?(:openstack_project_name)
- params[:openstack_project_name]
- else
- # Then it means that we are using the openstack_project_id
- connection = compute
- connection.current_tenant['name']
- end
- else
- # Return the tenant name
- params[:openstack_tenant]
- end
- end
-
- def use_nova_networking?
- @use_nova_networking
- end
-
- def compute
- unless @compute
- begin
- Bosh::Common.retryable(@retry_options) do |tries, error|
- @logger.error("Failed #{tries} times, last failure due to: #{error.inspect}") unless error.nil?
- @compute = Fog::OpenStack::Compute.new(params)
- end
- rescue Excon::Error::Socket => e
- cloud_error(socket_error_msg + e.message.to_s)
- rescue Bosh::Common::RetryCountExceeded, Excon::Error::Client, Excon::Error::Server => e
- cloud_error("Unable to connect to the OpenStack Compute Service API: #{e.message}. Check task debug log for details.")
- end
- end
- @compute
- end
-
- def image
- unless @glance
- begin
- Bosh::Common.retryable(@retry_options) do |tries, error|
- @logger.error("Failed #{tries} times, last failure due to: #{error.inspect}") unless error.nil?
- @glance = Fog::OpenStack::Image.new(params)
- end
- rescue Excon::Error::Socket => e
- cloud_error(socket_error_msg + e.message.to_s)
- rescue Bosh::Common::RetryCountExceeded, Excon::Error::Client, Excon::Error::Server => e
- cloud_error("Unable to connect to the OpenStack Image Service API: #{e.message}. Check task debug log for details.")
- end
- end
- @glance
- end
-
- ##
- # Creates a client for the OpenStack volume service, or return
- # the existing connection
- #
- #
- def volume
- unless @volume
- begin
- Bosh::Common.retryable(@retry_options) do |tries, error|
- @logger.error("Failed #{tries} times, last failure due to: #{error.inspect}") unless error.nil?
- @volume = Fog::OpenStack::Volume.new(params)
- end
- rescue Excon::Error::Socket => e
- cloud_error(socket_error_msg + e.message.to_s)
- rescue Bosh::Common::RetryCountExceeded, Excon::Error::Client, Excon::Error::Server => e
- cloud_error("Unable to connect to the OpenStack Volume Service API: #{e.message}. Check task debug log for details.")
- end
- end
-
- @volume
- end
-
- def network
- unless @network
- begin
- Bosh::Common.retryable(@retry_options) do |tries, error|
- @logger.error("Failed #{tries} times, last failure due to: #{error.inspect}") unless error.nil?
- @network = Fog::OpenStack::Network.new(params)
- end
- rescue Excon::Error::Socket => e
- cloud_error(socket_error_msg + e.message.to_s)
- rescue Bosh::Common::RetryCountExceeded, Excon::Error::Client, Excon::Error::Server, Fog::Errors::NotFound => e
- cloud_error("Unable to connect to the OpenStack Network Service API: #{e.message}. Check task debug log for details.")
- end
- end
-
- @network
- end
-
- ##
- # Waits for a resource to be on a target state
- #
- # @param [Fog::Model] resource Resource to query
- # @param [Array] target_state Resource's state desired
- # @param [Symbol] state_method Resource's method to fetch state
- # @param [Boolean] ignore_not_found true if resource could be not found
- def wait_resource(resource, target_state, state_method = :status, ignore_not_found = false)
- started_at = Time.now
- desc = resource.class.name.split('::').last.to_s + ' `' + resource.id.to_s + "'"
- target_state = Array(target_state)
-
- loop do
- duration = Time.now - started_at
-
- cloud_error("Timed out waiting for #{desc} to be #{target_state.join(', ')}") if duration > @state_timeout
-
- @logger.debug("Waiting for #{desc} to be #{target_state.join(', ')} (#{duration}s)")
-
- # If resource reload is nil, perhaps it's because resource went away
- # (ie: a destroy operation). Don't raise an exception if this is
- # expected (ignore_not_found).
- if with_openstack(retryable: true) { resource.reload.nil? }
- break if ignore_not_found
- cloud_error("#{desc}: Resource not found")
- else
- state = with_openstack { resource.send(state_method).downcase.to_sym }
- end
-
- # This is not a very strong convention, but some resources
- # have 'error', 'failed' and 'killed' states, we probably don't want to keep
- # waiting if we're in these states. Alternatively we could introduce a
- # set of 'loop breaker' states but that doesn't seem very helpful
- # at the moment
- if state == :error || state == :failed || state == :killed
- cloud_error("#{desc} state is #{state}, expected #{target_state.join(', ')}#{openstack_fault_message(resource)}")
- end
-
- break if target_state.include?(state)
-
- sleep(@wait_resource_poll_interval)
- end
-
- total = Time.now - started_at
- @logger.info("#{desc} is now #{target_state.join(', ')}, took #{total}s")
- end
-
- ##
- # Parses and look ups for keys in an OpenStack response
- #
- # @param [Excon::Response] response Response from OpenStack API
- # @param [Array] keys Keys to look up in response
- # @return [Hash] Contents at the first key found, or nil if not found
- def parse_openstack_response(response, *keys)
- json_body = parse_openstack_response_body(response.body)
- key = keys.detect { |k| json_body.key?(k) } if json_body && !json_body.empty?
- json_body[key] if key
- end
-
- private
-
- def dns_problem?(e)
- e.is_a?(Excon::Error::Socket) && e.message =~ /getaddrinfo/
- end
-
- def connectivity_problem?(e)
- e.is_a?(Excon::Error::Timeout) || e.is_a?(Excon::Error::Socket)
- end
-
- def server_problem?(e)
- e.is_a?(Excon::Error::ServiceUnavailable) || e.is_a?(Excon::Error::InternalServerError)
- end
-
- def format_error_body(e)
- body = parse_openstack_response_body(e.response.body)
- msg = determine_message(body)
- format_error(e, msg)
- end
-
- def format_error(e, msg = nil)
- error_name = e.class.name.split('::').last
- [error_name, e.message, msg].uniq.reject(&:nil?).reject(&:empty?).join(' ')
- end
-
- def raise_openstack_error(e, msg = nil)
- msg ||= format_error(e)
- error_message = "OpenStack API #{msg}.\nCheck task debug log for details."
- cloud_error(error_message, e)
- end
-
- def log_retry_error(e, retry_index, msg = nil, wait_time = DEFAULT_RETRY_TIMEOUT)
- msg ||= format_error(e)
- retry_msg = "OpenStack API #{msg}, retrying (#{retry_index}/#{MAX_RETRIES}) after #{wait_time} seconds."
- @logger.info(retry_msg)
- end
-
- def openstack_params(options)
- {
- openstack_auth_url: auth_url,
- openstack_username: options['username'],
- openstack_api_key: options['api_key'],
- openstack_application_credential_id: options['application_credential_id'],
- openstack_application_credential_secret: options['application_credential_secret'],
- openstack_tenant: options['tenant'],
- openstack_project_name: options['project'],
- openstack_project_id: options['project_id'],
- openstack_domain_name: options['domain'],
- openstack_user_domain_name: options['user_domain_name'],
- openstack_project_domain_name: options['project_domain_name'],
- openstack_region: options['region'],
- openstack_endpoint_type: options['endpoint_type'],
- connection_options: options['connection_options'].merge(@extra_connection_options),
- }
- end
-
- def socket_error_msg
- "Unable to connect to the OpenStack Keystone API #{auth_url}\n"
- end
-
- def build_auth_url(url)
- remove_url_trailing_slash(remove_url_path_from_version(url))
- end
-
- def remove_url_path_from_version(url)
- if auth_url_with_version?(url)
- version_regex = is_v3 ? /\/v3(?=\/|$)/ : /\/v2.0(?=\/|$)/
- url.slice(0..(url.index(version_regex)))
- else
- url
- end
- end
-
- def auth_url_with_version?(url)
- url.match(/\/v2.0(?=\/|$)/) || url.match(/\/v3(?=\/|$)/)
- end
-
- def remove_url_trailing_slash(url)
- if url.end_with?('/')
- url[0..-2]
- else
- url
- end
- end
-
- def openstack_fault_message(resource)
- openstack_message = ''
- if resource.respond_to?(:fault) && (fault = resource.fault)
- openstack_message = "\n#{fault['message']}" if fault['message']
- openstack_message += fault['details'] if fault['details']
- end
- openstack_message
- end
-
- def determine_message(body)
- hash_with_msg_property = proc { |_k, v| (v.is_a? Hash) && v['message'] }
-
- body ||= {}
- _, value = body.find(&hash_with_msg_property)
- value ? "(#{value['message']})" : ''
- end
-
- def parse_openstack_response_body(body)
- unless body.empty?
- begin
- return JSON.parse(body)
- rescue JSON::ParserError
- # do nothing
- end
- end
- nil
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/private_network.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/private_network.rb
deleted file mode 100644
index 5c3ad0d95..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/private_network.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-
-module Bosh::OpenStackCloud
- class PrivateNetwork < Network
- attr_reader :nic
- attr_accessor :allowed_address_pairs
-
- def initialize(name, spec)
- super
- @nic = {}
- @nic['net_id'] = net_id if net_id
- end
-
- def net_id
- @spec.fetch('cloud_properties', {})
- .fetch('net_id', nil)
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/request_message.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/request_message.rb
deleted file mode 100644
index 1a24203db..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/request_message.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-module Bosh::OpenStackCloud
- class RequestMessage
- def initialize(params)
- @params = params
- end
-
- def format
- params = @params.dup
- params.delete(:ciphers)
- params.delete(:connection)
- params.delete(:__construction_args)
- params.delete(:instrumentor)
- params.delete(:middlewares)
- params.delete(:uri_parser)
- params.delete(:stack)
- hostname = params.delete(:hostname)
- method = params.delete(:method)
- protocol = params.delete(:scheme)
- port = params.delete(:port)
- path = params.delete(:path)
- headers = params.delete(:headers)
- body = params.delete(:body) || 'null'
- "#{method} #{protocol}://#{hostname}:#{port}#{path} params: #{params.to_json} headers: #{headers.to_json} body: #{body}"
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/resource_pool.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/resource_pool.rb
deleted file mode 100644
index ba60178f5..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/resource_pool.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-module Bosh::OpenStackCloud
- class ResourcePool
- def self.security_groups(resource_pool_spec)
- if resource_pool_spec&.key?('security_groups')
- raise ArgumentError, 'security groups must be an Array' unless resource_pool_spec['security_groups'].is_a?(Array)
- return resource_pool_spec['security_groups']
- end
-
- []
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/response_message.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/response_message.rb
deleted file mode 100644
index 620b01653..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/response_message.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-module Bosh::OpenStackCloud
- class ResponseMessage
- def initialize(params)
- @params = params.dup
- end
-
- def format
- params = @params.dup
- body = params.delete(:body)
- path = params.delete(:path)
- headers = params.delete(:headers)
- status_line = params.delete(:status_line)&.chomp
- params.delete(:cookies)
- params.delete(:reason_phrase)
- params.delete(:status)
- "#{status_line} #{path} params: #{params.to_json} headers: #{headers.to_json} body: #{body}"
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/security_groups.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/security_groups.rb
deleted file mode 100644
index 4aeef8f1d..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/security_groups.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-module Bosh::OpenStackCloud
- class SecurityGroups
- include Helpers
-
- def initialize(openstack)
- @openstack = openstack
- end
-
- def select_and_retrieve(default_security_groups, network_spec_security_groups, resource_pool_spec_security_groups)
- picked_security_groups = pick_security_groups(
- default_security_groups,
- network_spec_security_groups,
- resource_pool_spec_security_groups,
- )
-
- openstack_security_groups = @openstack.with_openstack {
- retrieve_security_groups
- }
- map_to_security_groups_in_openstack(picked_security_groups, openstack_security_groups)
- end
-
- private
-
- def retrieve_security_groups
- if @openstack.use_nova_networking?
- @openstack.compute.security_groups
- else
- @openstack.network.security_groups
- end
- end
-
- def pick_security_groups(default_security_groups, network_spec_security_groups, resource_pool_spec_security_groups)
- return resource_pool_spec_security_groups unless resource_pool_spec_security_groups.empty?
-
- return network_spec_security_groups unless network_spec_security_groups.empty?
-
- default_security_groups
- end
-
- def map_to_security_groups_in_openstack(picked_security_groups, openstack_security_groups)
- picked_security_groups.map do |configured_sg|
- openstack_security_group = find_openstack_sg_by_name(openstack_security_groups, configured_sg)
- openstack_security_group ||= find_openstack_sg_by_id(openstack_security_groups, configured_sg)
- cloud_error("Security group `#{configured_sg}' not found") unless openstack_security_group
- openstack_security_group
- end
- end
-
- def find_openstack_sg_by_name(openstack_security_groups, security_group_name)
- @openstack.with_openstack(retryable: true) do
- openstack_security_groups.find { |openstack_sg| openstack_sg.name == security_group_name }
- end
- end
-
- def find_openstack_sg_by_id(openstack_security_groups, security_group_id)
- @openstack.with_openstack(retryable: true) do
- openstack_security_groups.find { |openstack_sg| openstack_sg.id == security_group_id }
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/server.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/server.rb
deleted file mode 100644
index c38dd6527..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/server.rb
+++ /dev/null
@@ -1,230 +0,0 @@
-module Bosh::OpenStackCloud
- class Server
- include Helpers
-
- REGISTRY_KEY_TAG = :registry_key
-
- def initialize(agent_properties, human_readable_vm_names, logger, openstack, registry, use_dhcp)
- @agent_properties = agent_properties
- @human_readable_vm_names = human_readable_vm_names
- @logger = logger
- @openstack = openstack
- @registry = registry
- @use_dhcp = use_dhcp
- end
-
- attr_reader :use_dhcp
-
- def create(agent_settings, network_configurator, resource_pool, create_vm_params)
- create_vm_params = create_vm_params.dup
-
- begin
- nics = network_configurator.nics
- @logger.debug("Using NICs: `#{nics.join(', ')}'")
- create_vm_params[:nics] = nics
- create_vm_params[:user_data] = JSON.dump(
- user_data(create_vm_params[:name], network_configurator.network_spec, agent_settings),
- )
-
- server = create_server(create_vm_params)
- configure_server(network_configurator, server)
-
- server_tags = {}
- tag_server(server_tags, server, agent_settings.registry_key, network_configurator.network_spec, resource_pool.fetch('loadbalancer_pools', []))
- update_server_settings(server, agent_settings)
-
- server.id.to_s
- rescue StandardError => e
- begin
- destroy(server, server_tags) if server
- rescue StandardError => destroy_err
- @logger.warn("Failed to destroy server: #{destroy_err.message}")
- end
-
- raise e
- end
- end
-
- def destroy(server, server_tags)
- server_tags ||= {}
- server_port_ids = NetworkConfigurator.port_ids(@openstack, server.id)
- @logger.debug("Network ports: `#{server_port_ids.join(', ')}' found for server #{server.id}")
-
- lbaas_error = catch_error('Removing lbaas pool memberships') { LoadbalancerConfigurator.new(@openstack, @logger).cleanup_memberships(server_tags) }
- @openstack.with_openstack(retryable: true, ignore_not_found: true) { server.destroy }
- fail_on_error(
- catch_error('Wait for server deletion') { @openstack.wait_resource(server, %i[terminated deleted], :state, true) },
- catch_error('Removing ports') { NetworkConfigurator.cleanup_ports(@openstack, server_port_ids) },
- lbaas_error,
- catch_error('Deleting registry settings') {
- registry_key = server_tags.fetch(REGISTRY_KEY_TAG.to_s, server.name)
- unless @registry.instance_of? NoopRegistry
- @logger.info("Deleting settings for server `#{server.id}' with registry_key `#{registry_key}' ...")
- end
- @registry.delete_settings(registry_key)
- },
- )
- end
-
- private
-
- def create_server(create_vm_params)
- @logger.debug("Using boot params: `#{Bosh::Cpi::Redactor.clone_and_redact(create_vm_params, 'user_data').inspect}'")
- server = @openstack.with_openstack do
- begin
- @openstack.compute.servers.create(create_vm_params)
- rescue Excon::Error::Timeout => e
- @logger.debug(e.backtrace)
- cloud_error_message = "VM creation with name '#{create_vm_params[:name]}' received a timeout. " \
- "The VM might still have been created by OpenStack.\nOriginal message: "
- raise Bosh::Clouds::VMCreationFailed.new(false), cloud_error_message + e.message
- rescue Excon::Error::BadRequest, Excon::Error::NotFound, Fog::OpenStack::Compute::NotFound => e
- raise e if @openstack.use_nova_networking?
- not_existing_net_ids = not_existing_net_ids(create_vm_params[:nics])
- raise e if not_existing_net_ids.empty?
- @logger.debug(e.backtrace)
- cloud_error_message = "VM creation with name '#{create_vm_params[:name]}' failed. Following network " \
- "IDs are not existing or not accessible from this project: '#{not_existing_net_ids.join(',')}'. " \
- 'Make sure you do not use subnet IDs'
- raise Bosh::Clouds::VMCreationFailed.new(false), cloud_error_message
- end
- end
- server
- end
-
- def configure_server(network_configurator, server)
- @logger.info("Creating new server `#{server.id}'...")
- begin
- @openstack.wait_resource(server, :active, :state)
-
- @logger.info("Configuring network for server `#{server.id}'...")
- network_configurator.configure(@openstack, server)
- rescue StandardError => e
- @logger.warn("Failed to create server: #{e.message}")
- raise Bosh::Clouds::VMCreationFailed.new(true), e.message
- end
- end
-
- def tag_server(server_tags, server, registry_key, network_spec, loadbalancer_pools)
- if @human_readable_vm_names
- @logger.debug("'human_readable_vm_names' enabled")
-
- server_tags[REGISTRY_KEY_TAG] = registry_key
- else
- @logger.debug("'human_readable_vm_names' disabled")
- end
-
- server_tags.merge!(
- LoadbalancerConfigurator
- .new(@openstack, @logger)
- .create_pool_memberships(server, network_spec, loadbalancer_pools),
- )
-
- begin
- unless server_tags.empty?
- TagManager.tag_server(server, server_tags)
- @logger.debug("Tagged VM '#{server.id}' with tags '#{server_tags}")
- end
- rescue StandardError => e
- @logger.warn("Unable to tag server with tags '#{server_tags}")
- raise Bosh::Clouds::VMCreationFailed.new(true), e.message
- end
- end
-
- def update_server_settings(server, agent_settings)
- settings = initial_agent_settings(agent_settings)
- @logger.info("Updating settings for server `#{server.id}'...") unless @registry.instance_of? NoopRegistry
- @registry.update_settings(agent_settings.registry_key, settings)
- rescue StandardError => e
- @logger.warn("Failed to register server: #{e.message}")
- raise Bosh::Clouds::VMCreationFailed.new(false), e.message
- end
-
- ##
- # Prepare server user data
- #
- # @param [String] registry_key used by agent to look up settings from registry
- # @param [Hash] network_spec network specification
- # @return [Hash] server user data
- def user_data(registry_key, network_spec, agent_settings, public_key = nil)
- data = {}
-
- data['server'] = { 'name' => registry_key }
- data['openssh'] = { 'public_key' => public_key } if public_key
- data['networks'] = agent_network_spec(network_spec)
-
- with_dns(network_spec) do |servers|
- data['dns'] = { 'nameserver' => servers }
- end
-
- if @registry.endpoint
- data['registry'] = { 'endpoint' => @registry.endpoint }
- else
- data.merge!(initial_agent_settings(agent_settings))
- end
-
- data
- end
-
- def not_existing_net_ids(nics)
- result = []
- begin
- network = @openstack.network
- nics.each do |nic|
- if nic['net_id']
- result << nic['net_id'] unless @openstack.with_openstack(retryable: true) { network.networks.get(nic['net_id']) }
- end
- end
- rescue StandardError => e
- @logger.warn(e.backtrace)
- end
- result
- end
-
- ##
- # Generates initial agent settings. These settings will be used by Bosh Agent
- # server. Disk conventions in Bosh Agent for OpenStack are:
- # - system disk: /dev/sda
- # - ephemeral disk: /dev/sdb
- # - persistent disks: /dev/sdc through /dev/sdz
- # As some kernels remap device names (from sd* to vd* or xvd*), Bosh Agent will lookup for the proper device name
- def initial_agent_settings(agent_settings)
- settings = {
- 'vm' => {
- 'name' => agent_settings.registry_key,
- },
- 'agent_id' => agent_settings.agent_id,
- 'networks' => agent_network_spec(agent_settings.network_spec),
- 'disks' => {
- 'system' => '/dev/sda',
- 'persistent' => {},
- },
- }
-
- settings['disks']['ephemeral'] = agent_settings.has_ephemeral ? '/dev/sdb' : nil
- settings['env'] = agent_settings.environment if agent_settings.environment
- settings.merge(@agent_properties)
- end
-
- def agent_network_spec(network_spec)
- network_spec.map do |name, settings|
- settings['use_dhcp'] = @use_dhcp unless settings['type'] == 'vip'
- [name, settings]
- end.to_h
- end
-
- ##
- # Extract dns server list from network spec and yield the the list
- #
- # @param [Hash] network_spec network specification for instance
- # @yield [Array]
- def with_dns(network_spec)
- network_spec.each_value do |properties|
- if properties.key?('dns') && !properties['dns'].nil?
- yield properties['dns']
- end
- end
- end
-
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/stemcell.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/stemcell.rb
deleted file mode 100644
index 8198d20e1..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/stemcell.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-module Bosh::OpenStackCloud
- module Stemcell
- include Helpers
-
- attr_reader :id, :image_id
-
- def initialize(logger, openstack, id)
- @image_id = id
- @openstack = openstack
- @logger = logger
- end
-
- def self.create(logger, openstack, id)
- regex = / light$/
-
- if id.match?(regex)
- LightStemcell.new(logger, openstack, id.gsub(regex, ''))
- else
- HeavyStemcell.new(logger, openstack, id)
- end
- end
-
- def validate_existence
- image = @openstack.with_openstack(retryable: true) { @openstack.image.images.find_by_id(image_id) }
- cloud_error("Image `#{id}' not found") if image.nil?
- @logger.debug("Using image: `#{id}'")
- end
- end
-
- class HeavyStemcell
- include Stemcell
-
- def initialize(logger, openstack, id)
- super
- @id = id
- end
-
- def delete
- image = @openstack.with_openstack(retryable: true) { @openstack.image.images.find_by_id(image_id) }
- if image
- @openstack.with_openstack(retryable: true, ignore_not_found: true) { image.destroy }
- @logger.info("Stemcell `#{image_id}' is now deleted")
- else
- @logger.info("Stemcell `#{image_id}' not found. Skipping.")
- end
- end
- end
-
- class LightStemcell
- include Stemcell
-
- def initialize(logger, openstack, id)
- super
- @id = "#{id} light"
- end
-
- def delete
- @logger.info("NoOP: Deleting light stemcell '#{id}'")
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/stemcell_creator.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/stemcell_creator.rb
deleted file mode 100644
index 2c8f2dbf6..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/stemcell_creator.rb
+++ /dev/null
@@ -1,138 +0,0 @@
-module Bosh::OpenStackCloud
- class StemcellCreator
- include Helpers
- def initialize(logger, openstack, cloud_properties)
- @logger = logger
- @openstack = openstack
- @cloud_properties = cloud_properties
- end
-
- def create(*args)
- creator.create(*args)
- end
-
- private
-
- def creator
- if @cloud_properties.key?('image_id')
- LightStemcellCreator.new(@logger, @openstack, @cloud_properties)
- else
- HeavyStemcellCreator.new(@logger, @openstack, @cloud_properties)
- end
- end
- end
-
- class LightStemcellCreator
- include Helpers
- def initialize(logger, openstack, cloud_properties)
- @logger = logger
- @openstack = openstack
- @cloud_properties = cloud_properties
- end
-
- def create(_, _)
- image_id = @cloud_properties['image_id']
- @logger.info("Checking for image with id '#{image_id}' referenced by light stemcell")
- image = @openstack.with_openstack(retryable: true) { @openstack.image.images.get(image_id) }
- if !image || image.status != 'active'
- cloud_error("No active image with id '#{image_id}' referenced by light stemcell found in OpenStack.")
- end
-
- LightStemcell.new(@logger, @openstack, image.id)
- end
- end
-
- class HeavyStemcellCreator
- include Helpers
-
- def initialize(logger, openstack, cloud_properties)
- @logger = logger
- @openstack = openstack
- @cloud_properties = cloud_properties
- end
-
- def set_public_param(image_params, is_public)
- image_params[:visibility] = is_public ? 'public' : 'private'
- end
-
- def set_image_properties(image_params, image_properties)
- image_params.merge!(image_properties)
- end
-
- def upload(image_params, image_location)
- image = create_openstack_image(image_params)
- @openstack.wait_resource(image, :queued)
- @logger.info("Performing file upload for image: '#{image.id}'...")
- image.upload_data(File.open(image_location, 'rb'))
- image
- end
-
- def create(image_path, is_public)
- Dir.mktmpdir do |tmp_dir|
- @logger.info('Creating new image...')
-
- image_params = {
- name: "#{@cloud_properties['name']}/#{@cloud_properties['version']}",
- disk_format: @cloud_properties['disk_format'],
- container_format: @cloud_properties['container_format'],
- }
-
- set_public_param(image_params, is_public)
-
- image_properties = HeavyStemcellCreator.normalize_image_properties(@cloud_properties)
-
- set_image_properties(image_params, image_properties)
-
- @logger.info("Extracting stemcell file to `#{tmp_dir}'...")
- unpack_image(tmp_dir, image_path)
-
- image_location = File.join(tmp_dir, 'root.img')
- image = upload(image_params, image_location)
-
- @logger.info("Waiting for image '#{image.id}' to have status 'active'...")
- @openstack.wait_resource(image, :active)
-
- HeavyStemcell.new(@logger, @openstack, image.id.to_s)
- end
- rescue StandardError => e
- @logger.error(e)
- raise e
- end
-
- def create_openstack_image(image_params)
- @logger.debug("Using image params: `#{image_params.inspect}'")
- @openstack.with_openstack { @openstack.image.images.create(image_params) }
- end
-
- def unpack_image(tmp_dir, image_path)
- result = Bosh::Exec.sh("tar -C #{tmp_dir} -xzf #{image_path} 2>&1", on_error: :return)
- if result.failed?
- @logger.error("Extracting stemcell root image failed in dir #{tmp_dir}, " \
- "tar returned #{result.exit_status}, output: #{result.output}")
- cloud_error('Extracting stemcell root image failed. Check task debug log for details.')
- end
- root_image = File.join(tmp_dir, 'root.img')
- cloud_error('Root image is missing from stemcell archive') unless File.exist?(root_image)
- end
-
- def self.normalize_image_properties(properties)
- image_properties = {}
- image_options = %w[version os_type os_distro architecture auto_disk_config
- hw_vif_model hw_disk_bus_model hw_scsi_model hw_disk_bus
- hw_vif_multiqueue_enabled hypervisor_type vmware_adaptertype
- vmware_disktype vmware_linked_clone vmware_ostype]
- image_options.reject { |image_option| properties[property_option_for_image_option(image_option)].nil? }.each do |image_option|
- image_properties[image_option.to_sym] = properties[property_option_for_image_option(image_option)].to_s
- end
- image_properties
- end
-
- def self.property_option_for_image_option(image_option)
- if image_option == 'hypervisor_type'
- 'hypervisor'
- else
- image_option
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/tag_manager.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/tag_manager.rb
deleted file mode 100644
index 7bab6d797..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/tag_manager.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-module Bosh::OpenStackCloud
- class TagManager
- MAX_TAG_KEY_LENGTH = 255
- MAX_TAG_VALUE_LENGTH = 255
-
- def self.tag_server(server, tags)
- formatted_tags = format(tags)
-
- server.metadata.update(formatted_tags) unless formatted_tags.empty?
- end
-
- def self.tag_volume(volume, volume_id, tags)
- formatted_tags = format(tags)
-
- volume.update_metadata(volume_id, formatted_tags) unless formatted_tags.empty?
- end
-
- def self.tag_snapshot(snapshot, tags)
- formatted_tags = format(tags)
-
- snapshot.update_metadata(formatted_tags) unless formatted_tags.empty?
- end
-
- def self.format(tags)
- tags
- .reject { |key, value| key.nil? || value.nil? }
- .map do |key, value|
- [key.to_s[0..(MAX_TAG_KEY_LENGTH - 1)], value.to_s[0..(MAX_TAG_VALUE_LENGTH - 1)]]
- end
- .to_h
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/vip_network.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/vip_network.rb
deleted file mode 100644
index 9eccb289d..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/vip_network.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-module Bosh::OpenStackCloud
- ##
- # Represents OpenStack vip network: where users sets VM's IP (floating IP's
- # in OpenStack)
- class VipNetwork < Network
- ##
- # Configures OpenStack vip network
- #
- # @param [Bosh::OpenStackCloud::Openstack] openstack
- # @param [Fog::OpenStack::Compute::Server] server OpenStack server to
- # configure
- def configure(openstack, server, network_id)
- cloud_error("No IP provided for vip network `#{@name}'") if @ip.nil?
-
- openstack.with_openstack do
- FloatingIp.reassociate(openstack, @ip, server, network_id)
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/vm_creator.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/vm_creator.rb
deleted file mode 100644
index 439a2beef..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/vm_creator.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-module Bosh::OpenStackCloud
- class VmCreator
- include Helpers
-
- def initialize(openstack, network_configurator, server, az_provider, cloud_properties, agent_settings, create_vm_params)
- @openstack = openstack
- @network_configurator = network_configurator
- @server = server
- @az_provider = az_provider
-
- @cloud_properties = cloud_properties
- @create_vm_params = create_vm_params
- @agent_settings = agent_settings
-
- @logger = Bosh::Clouds::Config.logger
- end
-
- def perform
- if @az_provider.use_multiple_azs?(@cloud_properties)
- create_vm_multiple_azs
- else
- create_vm_single_az
- end
- end
-
- private
-
- def create_vm_single_az
- availability_zone = @az_provider.select(@disk_locality, @cloud_properties['availability_zone'])
- prepare_vm_network
- create_vm_in_az(availability_zone)
- rescue StandardError => e
- clean_vm_network
- raise e
- end
-
- def create_vm_multiple_azs
- availability_zones = @az_provider.select_azs(@cloud_properties)
- prepare_vm_network
- begin
- availability_zones.each_with_index do |az, i|
- begin
- return create_vm_in_az(az)
- rescue StandardError => e
- if az == availability_zones.last
- @logger.error("Failed to create VM in AZ '#{az}' with error '#{e}' after #{i + 1} retries. No AZs left to retry.")
- raise e
- else
- @logger.warn("Failed to create VM in AZ '#{az}' with error '#{e}', retrying in a different AZ")
- end
- end
- end
- rescue StandardError => e
- clean_vm_network
- raise e
- end
- end
-
- def create_vm_in_az(availability_zone)
- @create_vm_params[:availability_zone] = availability_zone if availability_zone
- @server.create(
- @agent_settings,
- @network_configurator,
- @cloud_properties,
- @create_vm_params
- )
- end
-
- def prepare_vm_network
- @network_configurator.prepare(@openstack)
- end
-
- def clean_vm_network
- @network_configurator.cleanup(@openstack)
- rescue StandardError => e
- @logger.warn("Failed to cleanup network resources: #{e.message}")
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/vm_factory.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/vm_factory.rb
deleted file mode 100644
index f71a4374f..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/vm_factory.rb
+++ /dev/null
@@ -1,119 +0,0 @@
-module Bosh::OpenStackCloud
- class VmFactory
- include Helpers
-
- def initialize(openstack, server, create_vm_params, disk_locality, az_provider, openstack_properties)
- @openstack = openstack
- @server = server
-
- @create_vm_params = create_vm_params
- @disk_locality = disk_locality
- @az_provider = az_provider
- @openstack_properties = openstack_properties
-
- @logger = Bosh::Clouds::Config.logger
- end
-
- def create_vm(network_configurator, agent_id, environment, stemcell_id, cloud_properties)
- pick_security_groups(@create_vm_params, ResourcePool.security_groups(cloud_properties), network_configurator)
- pick_stemcell(@create_vm_params, stemcell_id)
- flavor = pick_flavor(@create_vm_params, cloud_properties)
- pick_key_name(@create_vm_params, cloud_properties)
- configure_volumes(@create_vm_params, flavor, cloud_properties)
-
- agent_settings = OpenStruct.new(
- registry_key: @create_vm_params[:name],
- agent_id:,
- environment:,
- has_ephemeral: flavor_has_ephemeral_disk?(flavor),
- network_spec: network_configurator.network_spec,
- )
-
- VmCreator.new(
- @openstack,
- network_configurator,
- @server,
- @az_provider,
- cloud_properties,
- agent_settings,
- @create_vm_params,
- ).perform
- end
-
- private
-
- def pick_security_groups(server_params, resource_pool_groups, network_configurator)
- network_configurator.check_preconditions(@openstack.use_nova_networking?, @create_vm_params[:config_drive], @server.use_dhcp)
- network_configurator.pick_groups(@openstack, @openstack_properties.default_security_groups, resource_pool_groups)
- server_params[:security_groups] = network_configurator.picked_security_groups.map(&:name)
- end
-
- def pick_stemcell(server_params, stemcell_id)
- stemcell = Stemcell.create(@logger, @openstack, stemcell_id)
- stemcell.validate_existence
- server_params[:image_ref] = stemcell.image_id
- end
-
- def pick_flavor(server_params, resource_pool)
- compute = @openstack.with_openstack { @openstack.compute }
- flavor = @openstack.with_openstack(retryable: true) do
- compute.flavors.find { |f| f.name == resource_pool['instance_type'] }
- end
- cloud_error("Flavor `#{resource_pool['instance_type']}' not found") if flavor.nil?
- if flavor_has_ephemeral_disk?(flavor)
- if flavor.ram
- # Ephemeral disk size should be at least the double of the vm total memory size, as agent will need:
- # - vm total memory size for swapon,
- # - the rest for /var/vcap/data
- min_ephemeral_size = (flavor.ram / 1024) * 2
- if flavor.ephemeral < min_ephemeral_size
- cloud_error("Flavor `#{resource_pool['instance_type']}' should have at least #{min_ephemeral_size}Gb " \
- 'of ephemeral disk')
- end
- end
- end
- @logger.debug("Using flavor: `#{resource_pool['instance_type']}'")
- server_params[:flavor_ref] = flavor.id
- flavor
- end
-
- def pick_key_name(server_params, resource_pool)
- keyname = resource_pool['key_name'] || @openstack_properties.default_key_name
- validate_key_exists(keyname)
- server_params[:key_name] = keyname
- end
-
- def validate_key_exists(keyname)
- keypair = @openstack.with_openstack(retryable: true) { @openstack.compute.key_pairs.find { |k| k.name == keyname } }
- cloud_error("Key-pair `#{keyname}' not found") if keypair.nil?
- @logger.debug("Using key-pair: `#{keypair.name}' (#{keypair.fingerprint})")
- end
-
- def configure_volumes(server_params, flavor, resource_pool)
- volume_configurator = Bosh::OpenStackCloud::VolumeConfigurator.new(@logger)
- return unless volume_configurator.boot_from_volume?(@openstack_properties.boot_from_volume, resource_pool)
-
- boot_vol_size = volume_configurator.select_boot_volume_size(flavor, resource_pool)
- server_params[:block_device_mapping_v2] = [{
- uuid: server_params[:image_ref],
- source_type: 'image',
- destination_type: 'volume',
- volume_size: boot_vol_size,
- boot_index: '0',
- delete_on_termination: '1',
- device_name: '/dev/vda',
- }]
- server_params.delete(:image_ref)
- end
-
- ##
- # Checks if the OpenStack flavor has ephemeral disk
- #
- # @param [Fog::OpenStack::Compute::Flavor] OpenStack flavor
- # @return [Boolean] true if flavor has ephemeral disk, false otherwise
- def flavor_has_ephemeral_disk?(flavor)
- flavor.ephemeral && flavor.ephemeral.to_i > 0
- end
-
- end
-end
diff --git a/src/bosh_openstack_cpi/lib/cloud/openstack/volume_configurator.rb b/src/bosh_openstack_cpi/lib/cloud/openstack/volume_configurator.rb
deleted file mode 100644
index f3f584a35..000000000
--- a/src/bosh_openstack_cpi/lib/cloud/openstack/volume_configurator.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-module Bosh::OpenStackCloud
- class VolumeConfigurator
- include Helpers
-
- def initialize(logger)
- @logger = logger
- end
-
- def select_boot_volume_size(flavor, resource_pool)
- if resource_pool['root_disk'].nil?
- if flavor.disk == 0
- cloud_error("Flavor '#{flavor.name}' has a root disk size of 0. Either pick a different flavor or define root_disk.size in your VM cloud_properties")
- end
-
- flavor.disk
- else
- root_disk_size = resource_pool['root_disk']['size']
- raise ArgumentError, 'Minimum root_disk size is 1 GiB' if root_disk_size.nil? || root_disk_size < 1
- @logger.debug("Using root_disk of size '#{root_disk_size}', instead of flavor.disk")
-
- root_disk_size
- end
- end
-
- def boot_from_volume?(boot_from_volume, resource_pool)
- return boot_from_volume if resource_pool['boot_from_volume'].nil?
-
- resource_pool['boot_from_volume']
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/assets/sample_config.yml b/src/bosh_openstack_cpi/spec/assets/sample_config.yml
deleted file mode 100644
index 52425bf82..000000000
--- a/src/bosh_openstack_cpi/spec/assets/sample_config.yml
+++ /dev/null
@@ -1,15 +0,0 @@
----
-openstack:
- auth_url: http://127.0.0.1:5000/v2.0
- username: foo
- api_key: bar
- tenant: bosh
- region:
- endpoint_type: publicURL
- default_key_name: default
- default_security_groups: ["default"]
-
-registry:
- endpoint: http://127.0.0.1:25695
- user: admin
- password: admin
diff --git a/src/bosh_openstack_cpi/spec/integration/calculate_vm_cloud_properties_spec.rb b/src/bosh_openstack_cpi/spec/integration/calculate_vm_cloud_properties_spec.rb
deleted file mode 100644
index 25e31a029..000000000
--- a/src/bosh_openstack_cpi/spec/integration/calculate_vm_cloud_properties_spec.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-require_relative './spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- include Bosh::OpenStackCloud::Helpers
-
- before(:all) do
- @config = IntegrationConfig.new
- end
-
- let(:logger) { @config.logger }
-
- before do
- delegate = double('delegate', logger:, cpi_task_log: nil)
- Bosh::Clouds::Config.configure(delegate)
- allow(Bosh::Clouds::Config).to receive(:logger).and_return(logger)
- end
-
- let(:cpi_for_cloud_props) { @config.create_cpi(boot_from_volume:) }
-
- let(:boot_from_volume) { false }
-
- it 'maps cloud agnostic VM properties to OpenStack-specific cloud_properties' do
- cloud_props = cpi_for_cloud_props.calculate_vm_cloud_properties(
- 'ram' => 512,
- 'cpu' => 1,
- 'ephemeral_disk_size' => 2 * 1024,
- )
-
- expect(cloud_props).to include('instance_type')
- instance_type = cloud_props['instance_type']
- expect(instance_type).to_not be_nil
-
- flavor = cpi_for_cloud_props.compute.flavors.find { |f| f.name == instance_type }
- expect(flavor).to_not be_nil
- expect(flavor.ram).to be >= 512
- expect(flavor.vcpus).to be >= 1
- expect(flavor.disk).to be >= 2
- end
-
- context 'when boot_from_volume is true' do
- let(:boot_from_volume) { true }
-
- it 'sets custom root disk size if no flavor has enough ephemeral disk' do
- cloud_props = cpi_for_cloud_props.calculate_vm_cloud_properties(
- 'ram' => 512,
- 'cpu' => 1,
- 'ephemeral_disk_size' => 10_000 * 1024, # assumes no flavor has 10TB disks
- )
-
- expect(cloud_props).to include('instance_type')
- instance_type = cloud_props['instance_type']
- expect(instance_type).to_not be_nil
-
- flavor = cpi_for_cloud_props.compute.flavors.find { |f| f.name == instance_type }
- expect(flavor).to_not be_nil
- expect(flavor.ram).to be >= 512
- expect(flavor.vcpus).to be >= 1
-
- custom_root_disk = cloud_props['root_disk']
- expect(custom_root_disk).to_not be_nil
- expect(custom_root_disk['size']).to be >= 10_000
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/integration/cpi_logging_spec.rb b/src/bosh_openstack_cpi/spec/integration/cpi_logging_spec.rb
deleted file mode 100644
index f2ccf8772..000000000
--- a/src/bosh_openstack_cpi/spec/integration/cpi_logging_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require_relative './spec_helper'
-
-describe Bosh::OpenStackCloud::ExconLoggingInstrumentor do
- include Bosh::OpenStackCloud::Helpers
-
- before(:all) do
- @config = IntegrationConfig.new
- end
-
- let(:logger) { Bosh::Cpi::Logger.new(log) }
- let(:log) { StringIO.new('') }
- let(:request_id) { '1234' }
- let(:cpi) { @config.create_cpi(boot_from_volume:) }
- let(:boot_from_volume) { false }
-
- before do
- logger.set_request_id(request_id)
- allow(Bosh::Clouds::Config).to receive(:logger).and_return(logger)
- end
-
- it 'logs excon messages' do
- cpi.calculate_vm_cloud_properties(
- 'ram' => 512,
- 'cpu' => 1,
- 'ephemeral_disk_size' => 2 * 1024,
- )
-
- expect(log.string).to match(%r{excon\.request GET https?://.*:\d+(?:/\w+)*/v\d\.\d/})
- expect(log.string).to match(%r{excon\.response HTTP/.*(?:/\w+)*/v\d\.\d/})
- end
-
- it 'logs excon exceptions' do
- cpi.delete_disk('123')
-
- expect(log.string).to match(%r{excon\.error HTTP/1\.1 404 Not Found \S*/v3/\S*volumes/123 params: .*})
- expect(log.string).not_to include('excon.error.response')
- end
-
- it 'includes the request_id' do
- cpi.calculate_vm_cloud_properties(
- 'ram' => 512,
- 'cpu' => 1,
- 'ephemeral_disk_size' => 2 * 1024,
- )
-
- expect(log.string).to include('[req_id 1234]')
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/integration/image_spec.rb b/src/bosh_openstack_cpi/spec/integration/image_spec.rb
deleted file mode 100644
index 605f9766f..000000000
--- a/src/bosh_openstack_cpi/spec/integration/image_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative './spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- include Bosh::OpenStackCloud::Helpers
-
- before(:all) do
- @config = IntegrationConfig.new
- end
-
- let(:logger) { @config.logger }
- let(:openstack) { @config.create_openstack }
-
- before do
- delegate = double('delegate', logger:, cpi_task_log: nil)
- Bosh::Clouds::Config.configure(delegate)
- allow(Bosh::Clouds::Config).to receive(:logger).and_return(logger)
- end
-
- describe 'Glance support' do
- let(:cpi_for_stemcell) { @config.create_cpi }
-
- after do
- cpi_for_stemcell.delete_stemcell(@stemcell_id) if @stemcell_id
- openstack.wait_resource(@image, :deleted, :status, true) if @image
- end
-
- it 'uploads and deletes a stemcell' do
- @stemcell_id, stemcell_manifest = upload_stemcell(cpi_for_stemcell, @config.stemcell_path)
- expect(@stemcell_id).to_not be_nil
-
- @image = openstack.with_openstack(retryable: true) { openstack.image.images.get(@stemcell_id) }
- expect(@image).to_not be_nil
- expect(@image.name).to eq("#{stemcell_manifest['cloud_properties']['name']}/#{stemcell_manifest['cloud_properties']['version']}")
- expect(@image.visibility).to eq('private')
- expect(@image.os_distro).to eq('ubuntu')
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/integration/lifecycle_spec.rb b/src/bosh_openstack_cpi/spec/integration/lifecycle_spec.rb
deleted file mode 100644
index 20833ec32..000000000
--- a/src/bosh_openstack_cpi/spec/integration/lifecycle_spec.rb
+++ /dev/null
@@ -1,604 +0,0 @@
-require_relative './spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- before(:all) do
- @config = IntegrationConfig.new
- @cpi_for_stemcell = @config.create_cpi
- @stemcell_id, = upload_stemcell(@cpi_for_stemcell, @config.stemcell_path)
- end
-
- before { allow(Bosh::Clouds::Config).to receive(:logger).and_return(@config.logger) }
-
- after(:all) do
- @cpi_for_stemcell.delete_stemcell(@stemcell_id)
- end
-
- let(:boot_from_volume) { false }
- let(:config_drive) { nil }
- let(:use_dhcp) { true }
- let(:human_readable_vm_names) { false }
- let(:use_nova_networking) { false }
- let(:openstack) { @config.create_openstack }
-
- subject(:cpi) do
- @config.create_cpi(boot_from_volume:, config_drive:, human_readable_vm_names:, use_nova_networking:, use_dhcp:)
- end
-
- describe 'dynamic network' do
- # even for dynamic networking we need to set the net_id as we may be in an environment
- # with multiple networks
- let(:network_spec) do
- {
- 'default' => {
- 'type' => 'dynamic',
- 'cloud_properties' => {
- 'net_id' => @config.net_id,
- },
- },
- }
- end
-
- context 'without existing disks and with a floating ip' do
- let(:network_spec_with_vip_network) do
- {
- 'vip_network' => {
- 'type' => 'vip',
- 'ip' => @config.floating_ip,
- },
- }.merge(network_spec)
- end
-
- before { @vm_with_assigned_floating_ip = create_vm(@stemcell_id, network_spec_with_vip_network, []) }
- after { clean_up_vm(@vm_with_assigned_floating_ip) if @vm_with_assigned_floating_ip }
-
- it 'exercises the vm lifecycle and reassigns the floating ip' do
- vm_lifecycle(@stemcell_id, network_spec_with_vip_network)
- end
- end
-
- context 'with existing disks' do
- before do
- @temp_vm_cid = create_vm(@stemcell_id, network_spec, [])
- @existing_volume_id = cpi.create_disk(2048, {}, @temp_vm_cid)
- cpi.delete_vm(@temp_vm_cid)
- end
- after { cpi.delete_disk(@existing_volume_id) if @existing_volume_id }
-
- it 'exercises the vm lifecycle' do
- expect {
- vm_lifecycle(@stemcell_id, network_spec, @existing_volume_id)
- }.to_not raise_error
- end
- end
-
- describe 'set_vm_metadata' do
- let(:human_readable_vm_names) { true }
- before { @human_readable_vm_name_id = create_vm(@stemcell_id, network_spec, []) }
- after { clean_up_vm(@human_readable_vm_name_id) if @human_readable_vm_name_id }
-
- it 'sets the vm name according to the metadata' do
- vm = openstack.compute.servers.get(@human_readable_vm_name_id)
- expect(vm.name).to eq 'openstack_cpi_spec/instance_id'
- end
- end
- end
-
- describe 'manual network' do
- let(:network_spec) do
- {
- 'default' => {
- 'type' => 'manual',
- 'ip' => @config.manual_ip,
- 'cloud_properties' => {
- 'net_id' => @config.net_id,
- },
- },
- }
- end
-
- context 'without existing disks' do
- it 'exercises the vm lifecycle' do
- expect {
- vm_lifecycle(@stemcell_id, network_spec)
- }.to_not raise_error
- end
- end
-
- context 'with existing disks' do
- before do
- @temp_vm_cid = create_vm(@stemcell_id, network_spec, [])
- @existing_volume_id = cpi.create_disk(2048, {}, @temp_vm_cid)
- clean_up_vm(@temp_vm_cid)
- end
-
- after { cpi.delete_disk(@existing_volume_id) if @existing_volume_id }
-
- it 'exercises the vm lifecycle' do
- expect {
- vm_lifecycle(@stemcell_id, network_spec, @existing_volume_id)
- }.to_not raise_error
- end
- end
-
- context 'with multiple networks and config_drive' do
- let(:multiple_network_spec) do
- {
- 'network_1' => {
- 'type' => 'manual',
- 'ip' => @config.no_dhcp_manual_ip_1,
- 'cloud_properties' => {
- 'net_id' => @config.net_id_no_dhcp_1,
- },
- },
- 'network_2' => {
- 'type' => 'manual',
- 'ip' => @config.no_dhcp_manual_ip_2,
- 'cloud_properties' => {
- 'net_id' => @config.net_id_no_dhcp_2,
- },
- 'use_dhcp' => false,
- },
- }
- end
-
- let(:config_drive) { 'cdrom' }
- let(:use_dhcp) { false }
-
- after { clean_up_vm(@multiple_nics_vm_id) if @multiple_nics_vm_id }
-
- it 'creates writes the mac addresses of the two networks to the metadata service' do
- server_user_data_as_string = nil
- allow_any_instance_of(Bosh::OpenStackCloud::Server).to receive(:create_server).and_wrap_original do |method, *arguments|
- server_user_data_as_string = arguments[0][:user_data]
- method.call(*arguments)
- end
-
- @multiple_nics_vm_id = create_vm(@stemcell_id, multiple_network_spec, [])
-
- vm = openstack.compute.servers.get(@multiple_nics_vm_id)
- network_interfaces = vm.addresses.map { |_, interfaces| interfaces }.flatten
- network_interface_1 = network_interfaces.find(&where_ip_address_is(@config.no_dhcp_manual_ip_1))
- network_interface_2 = network_interfaces.find(&where_ip_address_is(@config.no_dhcp_manual_ip_2))
-
- server_user_data = JSON.parse(server_user_data_as_string)
- expect(network_interface_1['OS-EXT-IPS-MAC:mac_addr']).to eq(server_user_data['networks']['network_1']['mac'])
- expect(network_interface_2['OS-EXT-IPS-MAC:mac_addr']).to eq(server_user_data['networks']['network_2']['mac'])
-
- ports = openstack.with_openstack(retryable: true) { openstack.network.ports.all(device_id: @multiple_nics_vm_id) }
- clean_up_vm(@multiple_nics_vm_id) if @multiple_nics_vm_id
-
- found_ports = openstack.with_openstack(retryable: true) { ports.find { |port| openstack.network.ports.get port.id } }
- expect(found_ports).to be_nil
- end
-
- def where_ip_address_is(ip)
- ->(network_interface) { network_interface['addr'] == ip }
- end
- end
-
- context 'when a neutron port already exists for a given IP' do
- before do
- clean_up_port(@config.manual_ip, @config.net_id)
- openstack.network.create_port(
- @config.net_id,
- fixed_ips: [{ ip_address: @config.manual_ip }],
- security_groups: [@config.security_group_id],
- )
- end
-
- after do
- clean_up_vm(@vm_id) if @vm_id
- clean_up_port(@config.manual_ip, @config.net_id)
- end
-
- it 'can still create the VM' do
- expect {
- @vm_id = create_vm(@stemcell_id, network_spec, [])
- }.to_not raise_error
- end
-
- def clean_up_port(ip, net_id)
- ports = openstack.with_openstack(retryable: true) do
- openstack.network.ports.all(fixed_ips: ["ip_address=#{ip}", "network_id=#{net_id}"])
- end
-
- port_ids = ports.select { |p| p.status == 'DOWN' && p.device_id.empty? && p.device_owner.empty? }.map(&:id)
- openstack.with_openstack(retryable: true) { openstack.network.delete_port(port_ids.first) } unless port_ids.empty?
- end
- end
-
- context 'with vrrp' do
- before { @vm_with_vrrp_ip = create_vm(@stemcell_id, network_spec, [], { 'allowed_address_pairs' => @config.allowed_address_pairs }) }
- after { clean_up_vm(@vm_with_vrrp_ip) if @vm_with_vrrp_ip }
-
- it 'adds vrrp_ip as allowed_address_pairs' do
- vrrp_port = openstack.with_openstack(retryable: true) do
- openstack.network.ports.all(fixed_ips: "ip_address=#{@config.manual_ip}")[0]
- end
- port_info = openstack.with_openstack(retryable: true) do
- openstack.network.get_port(vrrp_port.id)
- end
- expect(port_info).to be
-
- allowed_address_pairs = port_info[:body]['port']['allowed_address_pairs']
- expect(allowed_address_pairs.size).not_to be_zero
-
- assigned_allowed_address_pairs = allowed_address_pairs[0]['ip_address']
-
- expect(assigned_allowed_address_pairs).to eq(@config.allowed_address_pairs)
- end
- end
- end
-
- context 'when booting from volume' do
- let(:boot_from_volume) { true }
- let(:network_spec) do
- {
- 'default' => {
- 'type' => 'manual',
- 'ip' => @config.manual_ip,
- 'cloud_properties' => {
- 'net_id' => @config.net_id,
- },
- },
- }
- end
-
- def test_boot_volume(resource_pool = {})
- @vm_id = create_vm(@stemcell_id, network_spec, [], resource_pool)
- volumes = volumes(@vm_id)
- expect(volumes.size).to eq(1)
- expect(volumes.first['device']).to eq('/dev/vda')
- end
-
- after(:each) { clean_up_vm(@vm_id) if @vm_id }
-
- it 'creates a vm with boot_volume on /dev/vda' do
- test_boot_volume
- end
-
- context 'when boot_from_volume defined in the cloud_properties' do
- let(:boot_from_volume) { false }
-
- it 'creates a vm with boot_volume on /dev/vda' do
- test_boot_volume({ 'boot_from_volume' => true })
- end
- end
-
- context 'and flavor has root disk size 0' do
- let(:resource_pool) do
- {
- 'instance_type' => @config.instance_type_with_no_root_disk,
- }
- end
-
- context 'and root disk size given in manifest' do
- before do
- resource_pool['root_disk'] = {
- 'size' => 20,
- }
- end
-
- it 'creates a vm with boot_volume on /dev/vda' do
- test_boot_volume
- end
- end
-
- context 'and root disk size not given in manifest' do
- it 'raises an error' do
- expect {
- vm_lifecycle(@stemcell_id, network_spec, nil, resource_pool)
- }.to raise_error(Bosh::Clouds::CloudError, /Flavor '#{@config.instance_type_with_no_root_disk}' has a root disk size of 0/)
- end
- end
- end
- end
-
- context 'when using cloud_properties and specifying security groups' do
- let(:network_spec) do
- {
- 'default' => {
- 'type' => 'dynamic',
- 'cloud_properties' => {
- 'net_id' => @config.net_id,
- 'security_groups' => [security_group],
- },
- },
- }
- end
-
- context 'when security group is specified by name' do
- let(:security_group) { @config.security_group_name }
-
- it 'exercises the vm lifecycle' do
- expect {
- vm_lifecycle(@stemcell_id, network_spec)
- }.to_not raise_error
- end
- end
-
- context 'when security group is specified by id' do
- let(:security_group) { @config.security_group_id }
-
- it 'exercises the vm lifecycle' do
- expect {
- vm_lifecycle(@stemcell_id, network_spec)
- }.to_not raise_error
- end
- end
- end
-
- context 'when using config drive as cdrom' do
- let(:config_drive) { @config.config_drive }
-
- let(:network_spec) do
- {
- 'default' => {
- 'type' => 'dynamic',
- 'cloud_properties' => {
- 'net_id' => @config.net_id,
- },
- },
- }
- end
-
- it 'exercises the vm lifecycle' do
- expect {
- vm_lifecycle(@stemcell_id, network_spec)
- }.to_not raise_error
- end
- end
-
- context 'when vm creation fails' do
- let(:network_spec_that_fails) do
- {
- 'default' => {
- 'type' => 'manual',
- 'ip' => @config.manual_ip,
- 'cloud_properties' => {
- 'net_id' => @config.net_id,
- },
- },
- 'vip' => {
- 'type' => 'vip',
- 'ip' => '255.255.255.255',
- },
- }
- end
-
- def no_active_vm_with_ip?(ip)
- openstack.compute.servers.none? do |s|
- s.private_ip_address == ip && [:active].include?(s.state.downcase.to_sym)
- end
- end
-
- def no_port_remaining?(net_id, ip)
- openstack.with_openstack(retryable: true) do
- openstack.network.ports
- .select { |port| port.network_id == net_id }
- .none? { |port| port.fixed_ips.detect { |ips| ips['ip_address'] == ip } }
- end
- end
-
- it 'cleans up vm' do
- expect {
- create_vm(@stemcell_id, network_spec_that_fails, [])
- }.to raise_error Bosh::Clouds::VMCreationFailed, /Floating IP '255.255.255.255' not allocated/
-
- expect(no_active_vm_with_ip?(@config.manual_ip)).to be
- expect(no_port_remaining?(@config.net_id, @config.manual_ip)).to eq(true)
- end
-
- it 'better error message for wrong net ID' do
- network_spec_with_wrong_net_id = {
- 'default' => {
- 'type' => 'dynamic',
- 'cloud_properties' => {
- 'net_id' => '00000000-0000-0000-0000-000000000000',
- },
- },
- }
- expect {
- create_vm(@stemcell_id, network_spec_with_wrong_net_id, [])
- }.to raise_error Bosh::Clouds::VMCreationFailed, /'00000000-0000-0000-0000-000000000000'/
- end
- end
-
- context 'when detaching a non-existing disk' do
- # Detaching a non-existing disk from vm should NOT raise error
- let(:network_spec) do
- {
- 'default' => {
- 'type' => 'dynamic',
- 'cloud_properties' => {
- 'net_id' => @config.net_id,
- },
- },
- }
- end
-
- it 'exercises the vm lifecycles' do
- vm_id = create_vm(@stemcell_id, network_spec, [])
-
- expect {
- @config.logger.info("Detaching disk vm_id=#{vm_id} disk_id=non-existing-disk")
- cpi.detach_disk(vm_id, 'non-existing-disk')
- }.to_not raise_error
-
- clean_up_vm(vm_id)
- end
- end
-
- describe 'use_nova_networking=true' do
- let(:network_spec) do
- {
- 'default' => {
- 'type' => 'dynamic',
- 'cloud_properties' => {
- 'net_id' => @config.net_id,
- },
- },
- }
- end
-
- let(:use_nova_networking) { true }
- after { clean_up_vm(@vm_id_for_nova_compatibility) if @vm_id_for_nova_compatibility }
-
- it 'create vm does not use neutron for security groups' do
- stub_request(:any, /.*\/v2\.0\/security-groups/)
-
- @vm_id_for_nova_compatibility = create_vm(@stemcell_id, network_spec, [])
-
- expect(WebMock).to_not have_requested(:any, /.*\/v2\.0\/security-groups/)
- end
- end
-
- describe 'light stemcell' do
- let(:light_stemcell_id) { "#{@stemcell_id} light" }
-
- describe '#create_stemcell' do
- it 'returns the stemcell id with ` light` suffix' do
- cloud_properties = {
- 'image_id' => @stemcell_id,
- }
-
- expect(cpi.create_stemcell('not_relevant_path', cloud_properties)).to eq(light_stemcell_id)
- end
-
- context 'when referenced image does not exist' do
- it 'raises an error' do
- cloud_properties = {
- 'image_id' => 'non-existing-id',
- }
-
- expect {
- cpi.create_stemcell('not_relevant_path', cloud_properties)
- }.to raise_error Bosh::Clouds::CloudError
- end
- end
- end
-
- describe '#create_vm' do
- let(:network_spec) do
- {
- 'default' => {
- 'type' => 'dynamic',
- 'cloud_properties' => {
- 'net_id' => @config.net_id,
- },
- },
- }
- end
-
- it 'creates a vm with the heavy stemcell id' do
- vm_lifecycle(light_stemcell_id, network_spec)
- end
- end
- end
-
- describe 'set_disk_metadata' do
- before { @disk_id = cpi.create_disk(2048, {}, nil) }
- after { clean_up_disk(@disk_id) if @disk_id }
-
- let(:metadata) do
- {
- 'id' => 'my-id',
- 'deployment' => 'my-deployment',
- 'job' => 'my-job',
- 'index' => 'my-index',
- 'some_key' => 'some_value',
- }
- end
-
- it 'sets the disk metadata accordingly' do
- disk = openstack.with_openstack(retryable: true) { openstack.volume.volumes.get(@disk_id) }
- expect(disk.metadata).not_to include(metadata)
-
- cpi.set_disk_metadata(@disk_id, metadata)
-
- disk = openstack.with_openstack(retryable: true) { openstack.volume.volumes.get(@disk_id) }
- expect(disk.metadata).to include(metadata)
- end
- end
-
- describe 'resize_disk' do
- before { @disk_id = cpi.create_disk(2048, {}, nil) }
- after { clean_up_disk(@disk_id) if @disk_id }
-
- it 'resizes the disk' do
- cpi.resize_disk(@disk_id, 4096)
-
- disk = openstack.with_openstack(retryable: true) { openstack.volume.volumes.get(@disk_id) }
- expect(disk.size).to eq(4)
- end
- end
-
- describe 'when using load balancer pool' do
- before(:all) do
- skip('No lbaas pool configured') unless @config.lbaas_pool_name
- end
-
- let(:network_spec) do
- {
- 'default' => {
- 'type' => 'dynamic',
- 'cloud_properties' => {
- 'net_id' => @config.net_id,
- },
- },
- }
- end
-
- let(:resource_pool_spec_with_lbaas_pools) do
- {
- 'loadbalancer_pools' => [
- { 'name' => @config.lbaas_pool_name, 'port' => 4443 },
- ],
- 'key_name' => @config.default_key_name,
- 'availability_zone' => @config.availability_zone,
- 'instance_type' => @config.instance_type,
- }
- end
-
- it 'exercises vm lifecycle' do
- vm_id = nil
-
- expect {
- vm_id = create_vm(@stemcell_id, network_spec, [], resource_pool_spec_with_lbaas_pools)
- }.to_not raise_error
-
- expect(vm_id).not_to be_nil
-
- expect {
- clean_up_vm(vm_id)
- }.to_not raise_error
- end
- end
-
- describe 'when creating a server in a non-existent availability zone' do
- let(:network_spec) do
- {
- 'default' => {
- 'type' => 'dynamic',
- 'cloud_properties' => {
- 'net_id' => @config.net_id,
- },
- },
- }
- end
-
- let(:resource_pool_spec) do
- {
- 'key_name' => @config.default_key_name,
- 'availability_zone' => 'fake-availability-zone',
- 'instance_type' => @config.instance_type,
- }
- end
-
- it 'raises an error' do
- expect{
- create_vm(@stemcell_id, network_spec, [], resource_pool_spec)
- }.to raise_error;
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/integration/lifecycle_v2_spec.rb b/src/bosh_openstack_cpi/spec/integration/lifecycle_v2_spec.rb
deleted file mode 100644
index 9804c5c88..000000000
--- a/src/bosh_openstack_cpi/spec/integration/lifecycle_v2_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative './spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- subject(:cpi) { @config.create_cpi }
-
- before(:all) do
- @config = IntegrationConfig.new(:v2)
- end
-
- let(:boot_from_volume) { false }
- let(:config_drive) { nil }
- let(:logger) { @config.logger }
-
- before do
- delegate = double('delegate', logger:, cpi_task_log: nil)
- Bosh::Clouds::Config.configure(delegate)
- allow(Bosh::Clouds::Config).to receive(:logger).and_return(logger)
- end
-
- describe 'Basic Keystone V2 support' do
- context 'with missing VM id' do
- it 'should return false' do
- logger.info('Checking VM existence')
- expect(cpi).to_not have_vm('non-existing-vm-id')
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/integration/spec_helper.rb b/src/bosh_openstack_cpi/spec/integration/spec_helper.rb
deleted file mode 100644
index 253c4700a..000000000
--- a/src/bosh_openstack_cpi/spec/integration/spec_helper.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require 'spec_helper'
-require 'webmock/rspec'
-require_relative './support/integration_config'
-require_relative './support/lifecycle_helpers'
-require 'cloud'
-require 'tempfile'
-require 'logger'
-require 'ostruct'
-require 'bosh/cpi'
-
-RSpec.configure do |config|
- config.before(:all) { WebMock.allow_net_connect! }
-end
-
-def upload_stemcell(cpi, stemcell_path)
- stemcell_manifest = Psych.load_file(File.join(stemcell_path, 'stemcell.MF'))
- stemcell_id = cpi.create_stemcell(File.join(stemcell_path, 'image'), stemcell_manifest['cloud_properties'])
- [stemcell_id, stemcell_manifest]
-end
diff --git a/src/bosh_openstack_cpi/spec/integration/support/integration_config.rb b/src/bosh_openstack_cpi/spec/integration/support/integration_config.rb
deleted file mode 100644
index e17fcb5ae..000000000
--- a/src/bosh_openstack_cpi/spec/integration/support/integration_config.rb
+++ /dev/null
@@ -1,143 +0,0 @@
-class IntegrationConfig
- attr_reader :logger,
- :auth_url,
- :username,
- :api_key,
- :tenant,
- :project,
- :domain,
- :stemcell_path,
- :net_id,
- :net_id_no_dhcp_1,
- :net_id_no_dhcp_2,
- :volume_type,
- :manual_ip,
- :no_dhcp_manual_ip_1,
- :no_dhcp_manual_ip_2,
- :disable_snapshots,
- :default_key_name,
- :config_drive,
- :ignore_server_az,
- :instance_type,
- :instance_type_with_no_root_disk,
- :availability_zone,
- :region,
- :floating_ip,
- :security_group_id,
- :security_group_name,
- :ca_cert_path,
- :insecure,
- :lbaas_pool_name,
- :allowed_address_pairs
-
- def initialize(identity_version = :v3)
- if identity_version == :v3
- @auth_url = LifecycleHelper.get_config(:auth_url_v3)
- @domain = LifecycleHelper.get_config(:domain)
- @username = LifecycleHelper.get_config(:username_v3)
- @api_key = LifecycleHelper.get_config(:api_key_v3)
- @project = LifecycleHelper.get_config(:project)
- else
- @auth_url = LifecycleHelper.get_config(:auth_url_v2)
- @username = LifecycleHelper.get_config(:username_v2, LifecycleHelper.get_config(:username_v3))
- @api_key = LifecycleHelper.get_config(:api_key_v2, LifecycleHelper.get_config(:api_key_v3))
- @tenant = LifecycleHelper.get_config(:tenant, LifecycleHelper.get_config(:project))
- end
-
- @logger = Bosh::Cpi::Logger.new(STDERR)
- @logger.level = ::Logger::INFO
- @logger.set_request_id("fake-#{Random.rand(100000..999999)}")
-
- @ca_cert_content = LifecycleHelper.get_config(:ca_cert, nil)
- if @ca_cert_content && !@ca_cert_content.empty? && @ca_cert_content != 'null'
- @ca_cert_file = write_ca_cert(logger)
- @ca_cert_path = @ca_cert_file.path
- end
- @insecure = LifecycleHelper.get_config(:insecure, false)
- @connection_options = {
- 'connect_timeout' => LifecycleHelper.get_config(:connect_timeout, '120').to_i,
- 'read_timeout' => LifecycleHelper.get_config(:read_timeout, '120').to_i,
- 'write_timeout' => LifecycleHelper.get_config(:write_timeout, '120').to_i,
- 'ssl_verify_peer' => !@insecure,
- }
- @connection_options['ssl_ca_file'] = @ca_cert_path if @ca_cert_path
-
- @stemcell_path = LifecycleHelper.get_config(:stemcell_path)
- @net_id = LifecycleHelper.get_config(:net_id)
- @net_id_no_dhcp_1 = LifecycleHelper.get_config(:net_id_no_dhcp_1)
- @net_id_no_dhcp_2 = LifecycleHelper.get_config(:net_id_no_dhcp_2)
- @volume_type = LifecycleHelper.get_config(:volume_type)
- @manual_ip = LifecycleHelper.get_config(:manual_ip)
- @no_dhcp_manual_ip_1 = LifecycleHelper.get_config(:no_dhcp_manual_ip_1)
- @no_dhcp_manual_ip_2 = LifecycleHelper.get_config(:no_dhcp_manual_ip_2)
- @disable_snapshots = LifecycleHelper.get_config(:disable_snapshots, false)
- @default_key_name = LifecycleHelper.get_config(:default_key_name)
- @config_drive = LifecycleHelper.get_config(:config_drive, 'cdrom')
- @ignore_server_az = LifecycleHelper.get_config(:ignore_server_az, 'false')
- @instance_type = LifecycleHelper.get_config(:instance_type, 'm1.small')
- @instance_type_with_no_root_disk = LifecycleHelper.get_config(:flavor_with_no_root_disk)
- @availability_zone = LifecycleHelper.get_config(:availability_zone, nil)
- @floating_ip = LifecycleHelper.get_config(:floating_ip)
- @security_group_id = LifecycleHelper.get_config(:security_group_id)
- @security_group_name = LifecycleHelper.get_config(:security_group_name)
- @lbaas_pool_name = LifecycleHelper.get_config(:lbaas_pool_name, nil)
- @allowed_address_pairs = LifecycleHelper.get_config(:allowed_address_pairs, nil)
- # some environments may not have this set, and it isn't strictly necessary so don't raise if it isn't set
- @region = LifecycleHelper.get_config(:region, nil)
- Bosh::Clouds::Config.configure(OpenStruct.new(logger: @logger, cpi_task_log: nil))
- end
-
- def create_cpi(boot_from_volume: false, config_drive: nil, human_readable_vm_names: false, use_nova_networking: false, use_dhcp: true, default_volume_type: nil)
- properties = {
- 'openstack' => openstack_properties(boot_from_volume, config_drive, human_readable_vm_names, use_nova_networking, use_dhcp, default_volume_type),
- }
- Bosh::OpenStackCloud::Cloud.new(properties, 2)
- end
-
- def create_openstack
- Bosh::OpenStackCloud::Openstack.new(openstack_properties, {}, {})
- end
-
- def openstack_properties(boot_from_volume = false, config_drive = nil, human_readable_vm_names = false, use_nova_networking = false, use_dhcp = true, default_volume_type = nil)
- properties = {
- 'auth_url' => @auth_url,
- 'username' => @username,
- 'api_key' => @api_key,
- 'region' => @region,
- 'endpoint_type' => 'publicURL',
- 'default_key_name' => @default_key_name,
- 'default_security_groups' => %w[default],
- 'default_volume_type' => default_volume_type,
- 'wait_resource_poll_interval' => 5,
- 'boot_from_volume' => boot_from_volume,
- 'config_drive' => config_drive,
- 'use_dhcp' => use_dhcp,
- 'ignore_server_availability_zone' => str_to_bool(@ignore_server_az),
- 'human_readable_vm_names' => human_readable_vm_names,
- 'use_nova_networking' => use_nova_networking,
- 'connection_options' => @connection_options,
- 'vm' => {
- 'stemcell' => {
- 'api_version' => 2,
- },
- },
- }
-
- if @domain
- properties['domain'] = @domain
- properties['project'] = @project
- else
- properties['tenant'] = @tenant
- end
- properties
- end
-
- private
-
- def write_ca_cert(logger)
- @ca_cert_file = Tempfile.new(['cacert', '.pem'])
- logger.info("cacert.pem file: #{@ca_cert_file.path}")
- File.write(@ca_cert_file.path, @ca_cert_content)
- @ca_cert_file
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/integration/support/lifecycle_helpers.rb b/src/bosh_openstack_cpi/spec/integration/support/lifecycle_helpers.rb
deleted file mode 100644
index bcd715996..000000000
--- a/src/bosh_openstack_cpi/spec/integration/support/lifecycle_helpers.rb
+++ /dev/null
@@ -1,130 +0,0 @@
-module Support
- module LifecycleHelpers
- def volumes(vm_id)
- openstack.with_openstack(retryable: true) { openstack.compute.servers.get(vm_id).volume_attachments }
- end
-
- def vm_lifecycle(stemcell_id, network_spec, disk_id = nil, resource_pool = {})
- vm_id = create_vm(stemcell_id, network_spec, Array(disk_id), resource_pool)
-
- if disk_id
- @config.logger.info("Reusing disk #{disk_id} for VM vm_id #{vm_id}")
- else
- @config.logger.info("Creating disk for VM vm_id #{vm_id}")
- disk_id = cpi.create_disk(2048, {}, vm_id)
- expect(disk_id).to be
- end
-
- @config.logger.info("Checking existence of disk vm_id=#{vm_id} disk_id=#{disk_id}")
- expect(cpi.has_disk?(disk_id)).to be(true)
-
- @config.logger.info("Attaching disk vm_id=#{vm_id} disk_id=#{disk_id}")
- cpi.attach_disk(vm_id, disk_id)
-
- @config.logger.info("Detaching disk vm_id=#{vm_id} disk_id=#{disk_id}")
- cpi.detach_disk(vm_id, disk_id)
-
- disk_snapshot_id = create_disk_snapshot(disk_id) unless @config.disable_snapshots
- rescue StandardError => create_error
- # intentionally blank
- ensure
- funcs = [
- -> { clean_up_disk(disk_id) },
- -> { clean_up_vm(vm_id) },
- ]
- funcs.unshift(-> { clean_up_disk_snapshot(disk_snapshot_id) }) unless @config.disable_snapshots
- run_all_and_raise_any_errors(create_error, funcs)
- end
-
- def create_vm(stemcell_id, network_spec, disk_locality, resource_pool = {}, environment = { 'bosh' => { 'group' => 'instance-group-1' } })
- @config.logger.info("Creating VM with stemcell_id=#{stemcell_id}")
- vm_id, = cpi.create_vm(
- 'agent-007',
- stemcell_id,
- { 'instance_type' => @config.instance_type,
- 'availability_zone' => @config.availability_zone}.merge(resource_pool),
- network_spec,
- disk_locality,
- environment,
- )
- expect(vm_id).to be
-
- @config.logger.info("Checking VM existence vm_id=#{vm_id}")
- expect(cpi).to have_vm(vm_id)
-
- @config.logger.info("Setting VM metadata vm_id=#{vm_id}")
- cpi.set_vm_metadata(vm_id, {
- 'deployment' => 'deployment',
- 'name' => 'openstack_cpi_spec/instance_id',
- })
-
- vm_id
- end
-
- def clean_up_vm(vm_id)
- if vm_id
- @config.logger.info("Deleting VM vm_id=#{vm_id}")
- cpi.delete_vm(vm_id)
-
- @config.logger.info("Checking VM existence vm_id=#{vm_id}")
- expect(cpi).to_not have_vm(vm_id)
- else
- @config.logger.info('No VM to delete')
- end
- end
-
- def clean_up_disk(disk_id)
- if disk_id
- @config.logger.info("Deleting disk disk_id=#{disk_id}")
- cpi.delete_disk(disk_id)
- else
- @config.logger.info('No disk to delete')
- end
- end
-
- def create_disk_snapshot(disk_id)
- @config.logger.info("Creating disk snapshot disk_id=#{disk_id}")
- disk_snapshot_id = cpi.snapshot_disk(disk_id, {
- deployment: 'deployment',
- job: 'openstack_cpi_spec',
- index: '0',
- instance_id: 'instance',
- agent_id: 'agent',
- director_name: 'Director',
- director_uuid: '6d06b0cc-2c08-43c5-95be-f1b2dd247e18',
- })
- expect(disk_snapshot_id).to be
-
- @config.logger.info("Created disk snapshot disk_snapshot_id=#{disk_snapshot_id}")
- disk_snapshot_id
- end
-
- def clean_up_disk_snapshot(disk_snapshot_id)
- if disk_snapshot_id
- @config.logger.info("Deleting disk snapshot disk_snapshot_id=#{disk_snapshot_id}")
- cpi.delete_snapshot(disk_snapshot_id)
- else
- @config.logger.info('No disk snapshot to delete')
- end
- end
-
- def run_all_and_raise_any_errors(existing_errors, funcs)
- exceptions = Array(existing_errors)
- funcs.each do |f|
- begin
- f.call
- rescue StandardError => e
- exceptions << e
- end
- end
- # Prints all exceptions but raises original exception
- exceptions.each { |e| @config.logger.info("Failed with: #{e.inspect}\n#{e.backtrace.join("\n")}\n") }
- raise exceptions.first if exceptions.any?
- end
- end
-end
-
-RSpec.configure do |config|
- config.include(Support::LifecycleHelpers)
-end
-
diff --git a/src/bosh_openstack_cpi/spec/integration/volume_spec.rb b/src/bosh_openstack_cpi/spec/integration/volume_spec.rb
deleted file mode 100644
index 23c7ae684..000000000
--- a/src/bosh_openstack_cpi/spec/integration/volume_spec.rb
+++ /dev/null
@@ -1,157 +0,0 @@
-require_relative './spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- include Bosh::OpenStackCloud::Helpers
-
- before(:all) do
- @config = IntegrationConfig.new
- @cpi_for_stemcell = @config.create_cpi
- @stemcell_id, = upload_stemcell(@cpi_for_stemcell, @config.stemcell_path)
- end
-
- after(:all) do
- @cpi_for_stemcell.delete_stemcell(@stemcell_id)
- end
-
- let(:disk_metadata) do
- {
- 'director' => 'Director',
- 'deployment' => 'deployment',
- 'instance_id' => 'instance',
- 'job' => 'openstack_cpi_spec',
- 'instance_index' => '0',
- 'instance_name' => 'openstack_cpi_spec/instance',
- 'attached_at' => '2017-08-23T16:13:00Z',
- }
- end
-
- let(:disk_snapshot_metadata) do
- {
- deployment: 'deployment',
- job: 'openstack_cpi_spec',
- index: 0,
- instance_id: 'instance',
- agent_id: 'agent',
- director_name: 'Director',
- director_uuid: '6d06b0cc-2c08-43c5-95be-f1b2dd247e18',
- }
- end
-
- let(:expected_snapshot_metadata) do
- {
- 'director' => 'Director',
- 'director_uuid' => '6d06b0cc-2c08-43c5-95be-f1b2dd247e18',
- 'deployment' => 'deployment',
- 'instance_id' => 'instance',
- 'instance_index' => '0',
- 'instance_name' => 'openstack_cpi_spec/instance',
- 'agent_id' => 'agent',
- }
- end
-
- let(:cpi_for_vm) { @config.create_cpi }
- let(:openstack) { @config.create_openstack }
-
- let(:network_spec) do
- {
- 'default' => {
- 'type' => 'dynamic',
- 'cloud_properties' => {
- 'net_id' => @config.net_id,
- },
- },
- }
- end
-
- let(:vm_id) do
- created_vm_id, = cpi_for_vm.create_vm(
- 'agent-007',
- @stemcell_id,
- {
- 'instance_type' => @config.instance_type,
- 'availability_zone' => @config.availability_zone,
- },
- network_spec,
- [],
- 'key' => 'value',
- )
- created_vm_id
- end
-
- let(:cloud_properties) { {} }
-
- let(:supported_volume_type) { @config.volume_type }
-
- after(:each) do
- cpi_for_vm.delete_vm(vm_id)
- end
-
- describe 'Cinder support' do
- context 'with NO global default_volume_type' do
- let(:cpi_for_volume) { @config.create_cpi }
-
- context 'and NO `type` set in cloud_properties' do
- it 'uses default Cinder volume type' do
- volume_lifecycle
- end
- end
-
- context 'and `type` set in cloud_properties' do
- let(:cloud_properties) { { 'type' => supported_volume_type } }
-
- it 'uses the `type` configured in cloud_properties' do
- volume_lifecycle(supported_volume_type)
- end
- end
- end
-
- context 'with global default_volume_type' do
- context 'and `type` set in cloud_properties' do
- let(:cpi_for_volume) { @config.create_cpi(default_volume_type: 'type-to-override') }
- let(:cloud_properties) { { 'type' => supported_volume_type } }
-
- it 'uses the `type` configured in cloud_properties' do
- volume_lifecycle(supported_volume_type)
- end
- end
-
- context 'and no `type` set in cloud_properties' do
- let(:cpi_for_volume) { @config.create_cpi(default_volume_type: supported_volume_type) }
-
- it 'uses the default_volume_type' do
- volume_lifecycle(supported_volume_type)
- end
- end
- end
- end
-
- def volume_lifecycle(volume_type = nil)
- expect(vm_id).to_not be_nil
-
- disk_id = cpi_for_volume.create_disk(2048, cloud_properties, vm_id)
- expect(disk_id).to be
-
- expect(cpi_for_volume.has_disk?(disk_id)).to be(true)
-
- found_volume_type = openstack.with_openstack(retryable: true) { openstack.volume.volumes.get(disk_id).volume_type }
- expect(found_volume_type).to eq(volume_type) unless volume_type.nil?
-
- cpi_for_volume.attach_disk(vm_id, disk_id)
-
- cpi_for_volume.set_disk_metadata(disk_id, disk_metadata)
- found_metadata = openstack.with_openstack(retryable: true) { cpi_for_volume.volume.volumes.get(disk_id).metadata }
- expect(found_metadata).to include(disk_metadata)
-
- disk_snapshot_id = cpi_for_volume.snapshot_disk(disk_id, disk_snapshot_metadata)
- expect(disk_snapshot_id).to be
-
- found_snapshot_metadata = openstack.with_openstack(retryable: true) do
- cpi_for_volume.volume.snapshots.get(disk_snapshot_id).metadata
- end
- expect(found_snapshot_metadata).to eq(expected_snapshot_metadata)
-
- cpi_for_volume.delete_snapshot(disk_snapshot_id)
- cpi_for_volume.detach_disk(vm_id, disk_id)
- cpi_for_volume.delete_disk(disk_id)
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/spec_helper.rb b/src/bosh_openstack_cpi/spec/spec_helper.rb
deleted file mode 100644
index 5de0f380e..000000000
--- a/src/bosh_openstack_cpi/spec/spec_helper.rb
+++ /dev/null
@@ -1,233 +0,0 @@
-$LOAD_PATH.unshift File.expand_path('../lib', __dir__)
-
-require 'tmpdir'
-require 'zlib'
-require 'webmock'
-require 'tempfile'
-require 'timecop'
-
-require 'cloud/openstack'
-
-def mock_cloud_options(api_version = 2, devstack = false)
- cloud_properties = {
- 'plugin' => 'openstack',
- 'properties' => {
- 'openstack' => {
- 'auth_url' => 'http://127.0.0.1:5000/v2.0',
- 'username' => 'admin',
- 'api_key' => 'nova',
- 'tenant' => 'dummy_tenant',
- 'region' => 'RegionOne',
- 'state_timeout' => 1,
- 'wait_resource_poll_interval' => 3,
- 'use_dhcp' => true,
- 'stemcell_public_visibility' => false,
- },
- 'registry' => {
- 'endpoint' => 'localhost:42288',
- 'user' => 'admin',
- 'password' => 'admin',
- },
- 'agent' => {
- 'foo' => 'bar',
- 'baz' => 'zaz',
- },
- },
- }
- if api_version == 3
- keystone_path = devstack ? '/identity/v3' : '/v3'
- cloud_properties['properties']['openstack']['auth_url'] = "http://127.0.0.1:5000#{keystone_path}"
- cloud_properties['properties']['openstack']['project'] = 'dummy_project'
- cloud_properties['properties']['openstack']['domain'] = 'some_domain'
- else
- keystone_path = devstack ? '/identity/v2.0' : '/v2.0'
- cloud_properties['properties']['openstack']['auth_url'] = "http://127.0.0.1:5000#{keystone_path}"
- end
- cloud_properties
-end
-
-def mock_registry(endpoint = 'http://registry:3333')
- registry = double('registry', endpoint:)
- allow(Bosh::Cpi::RegistryClient).to receive(:new).and_return(registry)
- registry
-end
-
-def mock_cloud(options = nil, cpi_api_version = 1)
- servers = double('servers')
- images = double('images')
- flavors = double('flavors')
- volumes = double('volumes')
- snapshots = double('snapshots')
- key_pairs = double('key_pairs')
- security_groups = [double('default_sec_group', id: 'default_sec_group_id', name: 'default')]
-
- image = double(Fog::OpenStack::Image)
- allow(Fog::OpenStack::Image).to receive(:new).and_return(image)
- allow(image).to receive(:images).and_return(images)
-
- volume = double(Fog::OpenStack::Volume)
- allow(volume).to receive(:volumes).and_return(volumes)
- allow(volume).to receive(:snapshots).and_return(snapshots)
- allow(Fog::OpenStack::Volume).to receive(:new).and_return(volume)
-
- network = double(Fog::OpenStack::Network)
- allow(network).to receive(:security_groups).and_return(security_groups)
- allow(Fog::OpenStack::Network).to receive(:new).and_return(network)
-
- compute = double(Fog::OpenStack::Compute)
-
- allow(compute).to receive(:servers).and_return(servers)
- allow(compute).to receive(:flavors).and_return(flavors)
- allow(compute).to receive(:key_pairs).and_return(key_pairs)
-
- allow(Fog::OpenStack::Compute).to receive(:new).and_return(compute)
-
- fog = Struct
- .new(:compute, :network, :image, :volume)
- .new(compute, network, image, volume)
-
- yield(fog) if block_given?
-
- Bosh::OpenStackCloud::Cloud.new(options || mock_cloud_options['properties'], cpi_api_version)
-end
-
-def mock_glance(options = nil)
- cloud = mock_cloud(options)
-
- image = double(Fog::OpenStack::Image, images: double('images'))
- allow(cloud.instance_variable_get('@openstack')).to receive(:image).and_return(image)
- allow(image).to receive(:class).and_return(Fog::OpenStack::Image)
-
- yield image if block_given?
-
- cloud
-end
-
-def mock_sec_groups(receiver, sec_groups = [])
- allow(receiver).to receive(:security_groups).and_return(sec_groups)
- allow(sec_groups).to receive(:all).and_return(sec_groups)
-end
-
-def dynamic_network_spec
- {
- 'type' => 'dynamic',
- 'cloud_properties' => {
- 'security_groups' => %w[default],
- },
- 'use_dhcp' => true,
- }
-end
-
-def manual_network_spec(net_id: 'net', ip: '0.0.0.0', default: nil, overwrites: {})
- {
- 'ip' => ip,
- 'default' => default,
- 'cloud_properties' => {
- 'security_groups' => %w[default],
- 'net_id' => net_id,
- },
- 'use_dhcp' => true,
- }.merge(overwrites)
-end
-
-def manual_network_without_netid_spec
- {
- 'cloud_properties' => {
- 'security_groups' => %w[default],
- },
- }
-end
-
-def dynamic_network_with_netid_spec
- {
- 'type' => 'dynamic',
- 'cloud_properties' => {
- 'security_groups' => %w[default],
- 'net_id' => 'net',
- },
- }
-end
-
-def vip_network_spec
- {
- 'type' => 'vip',
- 'ip' => '10.0.0.1',
- }
-end
-
-def combined_network_spec
- {
- 'network_a' => dynamic_network_spec,
- 'network_b' => vip_network_spec,
- }
-end
-
-def resource_pool_spec
- {
- 'key_name' => 'test_key',
- 'availability_zone' => 'foobar-1a',
- 'instance_type' => 'm1.tiny',
- }
-end
-
-def resource_pool_spec_with_root_disk
- {
- 'key_name' => 'test_key',
- 'availability_zone' => 'foobar-1a',
- 'instance_type' => 'm1.tiny',
- 'root_disk' => { 'size' => 10_240 },
- }
-end
-
-def resource_pool_spec_with_0_root_disk
- {
- 'key_name' => 'test_key',
- 'availability_zone' => 'foobar-1a',
- 'instance_type' => 'm1.tiny',
- 'root_disk' => { 'size' => 0 },
- }
-end
-
-RSpec.configure do |config|
- config.before(:each) { allow(Bosh::Clouds::Config).to receive(:logger).and_return(double.as_null_object) }
-end
-
-class LifecycleHelper
- extend WebMock::API
-
- def self.get_config(key, default = :none)
- env_file = ENV['LIFECYCLE_ENV_FILE']
- env_name = ENV['LIFECYCLE_ENV_NAME']
- env_key = "BOSH_OPENSTACK_#{key.to_s.upcase}"
-
- value = if env_file
- config = load_config_from_file(env_file, env_name)
- config[key.to_s]
- else
- ENV[env_key]
- end
-
- value_empty = value.to_s.empty?
- if value_empty && default == :none
- raise("Missing #{key}/#{env_key}; use LIFECYCLE_ENV_FILE=file.yml and LIFECYCLE_ENV_NAME=xxx or set in ENV")
- end
-
- value_empty ? default : value
- end
-
- def self.load_config_from_file(env_file, env_name)
- @configs ||= YAML.load_file(env_file)
- config =
- if env_name
- raise "no such env #{env_name} in #{env_file} (available: #{@configs.keys.sort.join(', ')})" unless @configs[env_name]
- @configs[env_name]
- else
- @configs
- end
- config
- end
-end
-
-def str_to_bool(string)
- string == 'true'
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/attach_disk_spec.rb b/src/bosh_openstack_cpi/spec/unit/attach_disk_spec.rb
deleted file mode 100644
index 3884377d5..000000000
--- a/src/bosh_openstack_cpi/spec/unit/attach_disk_spec.rb
+++ /dev/null
@@ -1,223 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- let(:server_metadata) { [] }
- let(:server) { double('server', id: 'i-test', name: 'i-test', flavor: { 'id' => 'f-test' }, metadata: server_metadata) }
- let(:volume) { double('volume', id: 'v-foobar') }
- let(:flavor) { double('flavor', id: 'f-test', ephemeral: 10, swap: '') }
- let(:cpi_api_version) { 1 }
- let(:cloud) do
- mock_cloud(cloud_options['properties'], cpi_api_version) do |fog|
- expect(fog.compute.servers).to receive(:get).with('i-test').and_return(server)
- expect(fog.volume.volumes).to receive(:get).with('v-foobar').and_return(volume)
- expect(fog.compute.flavors).to receive(:find).and_return(flavor)
- end
- end
- let(:cloud_options) { mock_cloud_options }
-
- before(:each) do
- allow(server.metadata).to receive(:get).with(:registry_key).and_return(double('metadatum', 'value' => 'i-test'))
- @registry = mock_registry
- end
-
- it 'attaches an OpenStack volume to a server' do
- volume_attachments = []
- attachment = double('attachment', device: '/dev/sdc')
-
- expect(server).to receive(:volume_attachments).and_return(volume_attachments)
- expect(server).to receive(:attach_volume).with(volume.id, '/dev/sdc').and_return(attachment)
- expect(cloud.openstack).to receive(:wait_resource).with(volume, :'in-use')
-
- old_settings = { 'foo' => 'bar' }
- new_settings = {
- 'foo' => 'bar',
- 'disks' => {
- 'persistent' => {
- 'v-foobar' => '/dev/sdc',
- },
- },
- }
-
- expect(@registry).to receive(:read_settings).with('i-test').and_return(old_settings)
- expect(@registry).to receive(:update_settings).with('i-test', new_settings)
-
- cloud.attach_disk('i-test', 'v-foobar')
- end
-
- it 'picks available device name' do
- volume_attachments = [{ 'volumeId' => 'v-c', 'device' => '/dev/vdc' },
- { 'volumeId' => 'v-d', 'device' => '/dev/xvdd' }]
- attachment = double('attachment', device: '/dev/sdd')
-
- expect(server).to receive(:volume_attachments).and_return(volume_attachments)
- expect(server).to receive(:attach_volume).with(volume.id, '/dev/sde').and_return(attachment)
- expect(cloud.openstack).to receive(:wait_resource).with(volume, :'in-use')
-
- old_settings = { 'foo' => 'bar' }
- new_settings = {
- 'foo' => 'bar',
- 'disks' => {
- 'persistent' => {
- 'v-foobar' => '/dev/sde',
- },
- },
- }
-
- expect(@registry).to receive(:read_settings).with('i-test').and_return(old_settings)
- expect(@registry).to receive(:update_settings).with('i-test', new_settings)
-
- cloud.attach_disk('i-test', 'v-foobar')
- end
-
- it 'raises an error when sdc..sdz are all reserved' do
- volume_attachments = ('c'..'z').each_with_object([]) do |char, array|
- array << { 'volumeId' => "v-#{char}", 'device' => "/dev/sd#{char}" }
- end
-
- expect(server).to receive(:volume_attachments).and_return(volume_attachments)
-
- expect {
- cloud.attach_disk('i-test', 'v-foobar')
- }.to raise_error(Bosh::Clouds::CloudError, /too many disks attached/)
- end
-
- it 'bypasses the attaching process when volume is already attached to a server' do
- volume_attachments = [{ 'volumeId' => 'v-foobar', 'device' => '/dev/sdc' }]
-
- cloud = mock_cloud do |fog|
- expect(fog.compute.servers).to receive(:get).with('i-test').and_return(server)
- expect(fog.volume.volumes).to receive(:get).with('v-foobar').and_return(volume)
- end
-
- expect(server).to receive(:volume_attachments).and_return(volume_attachments)
- expect(volume).not_to receive(:attach)
-
- old_settings = { 'foo' => 'bar' }
- new_settings = {
- 'foo' => 'bar',
- 'disks' => {
- 'persistent' => {
- 'v-foobar' => '/dev/sdc',
- },
- },
- }
-
- expect(@registry).to receive(:read_settings).with('i-test').and_return(old_settings)
- expect(@registry).to receive(:update_settings).with('i-test', new_settings)
-
- cloud.attach_disk('i-test', 'v-foobar')
- end
-
- context 'first device name letter' do
- before do
- allow(server).to receive(:volume_attachments).and_return([])
- allow(cloud.openstack).to receive(:wait_resource)
- allow(cloud).to receive(:update_agent_settings)
- end
- subject(:attach_disk) { cloud.attach_disk('i-test', 'v-foobar') }
-
- let(:flavor) { double('flavor', id: 'f-test', ephemeral: 0, swap: '') }
-
- context 'when there is no ephemeral, swap disk and config drive' do
- it 'return letter b' do
- expect(server).to receive(:attach_volume).with(volume.id, '/dev/sdb')
- attach_disk
- end
- end
-
- context 'when there is ephemeral disk' do
- let(:flavor) { double('flavor', id: 'f-test', ephemeral: 1024, swap: '') }
-
- it 'return letter c' do
- expect(server).to receive(:attach_volume).with(volume.id, '/dev/sdc')
- attach_disk
- end
- end
-
- context 'when there is swap disk' do
- let(:flavor) { double('flavor', id: 'f-test', ephemeral: 0, swap: 200) }
-
- it 'return letter c' do
- expect(server).to receive(:attach_volume).with(volume.id, '/dev/sdc')
- attach_disk
- end
- end
-
- context 'when config_drive is set as disk' do
- let(:cloud_options) do
- cloud_options = mock_cloud_options
- cloud_options['properties']['openstack']['config_drive'] = 'disk'
- cloud_options
- end
-
- it 'returns letter c' do
- expect(server).to receive(:attach_volume).with(volume.id, '/dev/sdc')
- attach_disk
- end
- end
-
- context 'when there is ephemeral and swap disk' do
- let(:flavor) { double('flavor', id: 'f-test', ephemeral: 1024, swap: 200) }
-
- it 'returns letter d' do
- expect(server).to receive(:attach_volume).with(volume.id, '/dev/sdd')
- attach_disk
- end
- end
-
- context 'when there is ephemeral, swap disk and config drive is disk' do
- let(:flavor) { double('flavor', id: 'f-test', ephemeral: 1024, swap: 200) }
- let(:cloud_options) do
- cloud_options = mock_cloud_options
- cloud_options['properties']['openstack']['config_drive'] = 'disk'
- cloud_options
- end
-
- it 'returns letter e' do
- expect(server).to receive(:attach_volume).with(volume.id, '/dev/sde')
- attach_disk
- end
- end
-
- context 'when server flavor is not found' do
- let(:flavor) { nil }
-
- it 'returns letter b' do
- expect(server).to receive(:attach_volume).with(volume.id, '/dev/sdb')
- attach_disk
- end
- end
- end
-
- context 'when cpi api verion is 1' do
- let(:cpi_api_version) { 1 }
-
- before do
- allow(server).to receive(:volume_attachments).and_return([])
- allow(cloud.openstack).to receive(:wait_resource)
- allow(cloud).to receive(:update_agent_settings)
- allow(server).to receive(:attach_volume)
- end
-
- it 'does not return a disk hint' do
- disk_hint = cloud.attach_disk('i-test', 'v-foobar')
- expect(disk_hint).to eq(nil)
- end
- end
-
- context 'when cpi api version is 2' do
- let(:cpi_api_version) { 2 }
-
- before do
- allow(server).to receive(:volume_attachments).and_return([])
- allow(cloud.openstack).to receive(:wait_resource)
- allow(cloud).to receive(:update_agent_settings)
- allow(server).to receive(:attach_volume)
- end
-
- it 'returns a disk hint' do
- disk_hint = cloud.attach_disk('i-test', 'v-foobar')
- expect(disk_hint).to eq('/dev/sdc')
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/availability_zone_provider_spec.rb b/src/bosh_openstack_cpi/spec/unit/availability_zone_provider_spec.rb
deleted file mode 100644
index d346dcfda..000000000
--- a/src/bosh_openstack_cpi/spec/unit/availability_zone_provider_spec.rb
+++ /dev/null
@@ -1,182 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::AvailabilityZoneProvider do
- let(:foo_volume) { double('foo_volume') }
- let(:bar_volume) { double('bar_volume') }
- let(:volumes) { double('volumes') }
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack) }
- let(:compute) { double(Fog::OpenStack::Compute) }
- let(:volume) { double(Fog::Volume) }
- let(:az_provider) { Bosh::OpenStackCloud::AvailabilityZoneProvider.new(openstack, ignore_server_az) }
-
- before do
- allow(openstack).to receive(:compute).and_return(compute)
- allow(openstack).to receive(:volume).and_return(volume)
- allow(openstack).to receive(:with_openstack) { |&block| block.call }
- allow(bar_volume).to receive(:id).and_return('bar_id')
- allow(foo_volume).to receive(:id).and_return('foo_id')
- allow(foo_volume).to receive(:availability_zone).and_return('west_az')
- allow(volumes).to receive(:get).with('foo_id').and_return(foo_volume)
- allow(volumes).to receive(:get).with('bar_id').and_return(bar_volume)
- allow(volume).to receive(:volumes).and_return(volumes)
- end
-
- describe '.use_multiple_azs?' do
- let(:ignore_server_az) { true }
- let(:multiple_azs_cloud_properties) { { 'availability_zones' => %w[]} }
- let(:single_az_cloud_properties) { { 'availability_zone' => '' } }
- let(:invalid_cloud_properties) { { 'availability_zone' => '', 'availability_zones' => [] } }
- let(:empty_cloud_properties) { {} }
-
- it 'returns true if list is set' do
- expect(az_provider.use_multiple_azs?(multiple_azs_cloud_properties)).to be_truthy
- end
-
- it 'returns false if single_az is set' do
- expect(az_provider.use_multiple_azs?(single_az_cloud_properties)).to be_falsey
- end
-
- it 'should return false if neither is given' do
- expect(az_provider.use_multiple_azs?(empty_cloud_properties)).to be_falsey
- end
-
- it 'raises an exception if both are configured' do
- expect {
- az_provider.use_multiple_azs?(invalid_cloud_properties)
- }.to raise_error(Bosh::Clouds::CloudError, 'Invalid cloud_properties: only one property of "availability_zone" and "availability_zones" allowed.')
- end
-
- context 'when ignore_server is false' do
- let(:ignore_server_az) { false }
- let(:cloud_properties) { { } }
-
- it 'raises an error if az list is given and ignore_server_availability_zone is false' do
- expect {
- az_provider.use_multiple_azs?(multiple_azs_cloud_properties)
- }.to raise_error(Bosh::Clouds::CloudError, 'Cannot use multiple azs without openstack.ignore_server_availability_zone')
- end
- end
-
- # end
- end
-
- context 'when the server availability zone of the server must be the same as the disk' do
- let(:ignore_server_az) { false }
-
- context 'when the volume IDs are present' do
- context 'when az of volume is empty string' do
- before do
- allow(bar_volume).to receive(:availability_zone).and_return('')
- end
-
- it 'returns nil' do
- expect(az_provider.select(['bar_id'], nil)).to be_nil
- end
- end
-
- context 'when az of volume is nil' do
- before do
- allow(bar_volume).to receive(:availability_zone).and_return(nil)
- end
-
- it 'returns nil' do
- expect(az_provider.select(['bar_id'], nil)).to be_nil
- end
- end
-
- context 'when the volumes and resource pool are all from the same availability zone' do
- before do
- expect(bar_volume).to receive(:availability_zone).and_return('west_az')
- end
-
- it "should return the disk's availability zone" do
- selected_availability_zone = az_provider.select(%w[foo_id bar_id], 'west_az')
- expect(selected_availability_zone).to eq('west_az')
- end
- end
-
- context 'when the disks are from different AZs and no resource pool AZ is provided' do
- before do
- allow(bar_volume).to receive(:availability_zone).and_return('east_az')
- end
-
- it 'should raise an error' do
- expect {
- az_provider.select(%w[foo_id bar_id], nil)
- }.to raise_error Bosh::Clouds::CloudError, "can't use multiple availability zones: VM is created in default AZ, disk 'foo_id' is in AZ 'west_az', disk 'bar_id' is in AZ 'east_az'. Enable 'openstack.ignore_server_availability_zone' to allow VMs and disks to be in different AZs, or use the same AZ for both."
- end
- end
-
- context 'when the disks are from the same AZ and no resource pool AZ is provided' do
- before do
- expect(bar_volume).to receive(:availability_zone).and_return('west_az')
- end
-
- it 'should select the common disk AZ' do
- selected_availability_zone = az_provider.select(%w[foo_id bar_id], nil)
- expect(selected_availability_zone).to eq('west_az')
- end
- end
-
- context 'when there is a volume in a different AZ from other volumes or the resource pool AZ' do
- before do
- allow(bar_volume).to receive(:availability_zone).and_return('east_az')
- end
-
- it 'should raise an error' do
- expect {
- az_provider.select(%w[foo_id bar_id], 'west_az')
- }.to raise_error Bosh::Clouds::CloudError, "can't use multiple availability zones: VM is created in AZ 'west_az', disk 'foo_id' is in AZ 'west_az', disk 'bar_id' is in AZ 'east_az'. Enable 'openstack.ignore_server_availability_zone' to allow VMs and disks to be in different AZs, or use the same AZ for both."
- end
- end
-
- context 'when the disk AZs do not match the resource pool AZ' do
- before do
- allow(bar_volume).to receive(:availability_zone).and_return('west_az')
- end
-
- it 'should raise an error' do
- expect {
- az_provider.select(%w[foo_id bar_id], 'south_az')
- }.to raise_error Bosh::Clouds::CloudError, "can't use multiple availability zones: VM is created in AZ 'south_az', disk 'foo_id' is in AZ 'west_az', disk 'bar_id' is in AZ 'west_az'. Enable 'openstack.ignore_server_availability_zone' to allow VMs and disks to be in different AZs, or use the same AZ for both."
- end
- end
-
- context 'when all AZs provided are mismatched' do
- before do
- allow(bar_volume).to receive(:availability_zone).and_return('east_az')
- end
-
- it 'should raise an error' do
- expect {
- az_provider.select(%w[foo_id bar_id], 'south_az')
- }.to raise_error Bosh::Clouds::CloudError, "can't use multiple availability zones: VM is created in AZ 'south_az', disk 'foo_id' is in AZ 'west_az', disk 'bar_id' is in AZ 'east_az'. Enable 'openstack.ignore_server_availability_zone' to allow VMs and disks to be in different AZs, or use the same AZ for both."
- end
- end
-
- context 'when there are no disks IDs' do
- it 'should return the resource pool AZ value' do
- expect(az_provider.select([], nil)).to eq nil
- expect(az_provider.select([], 'north_az')).to eq('north_az')
-
- expect(az_provider.select(nil, 'north_az')).to eq('north_az')
- end
- end
- end
-
- context '.select_azs' do
- context 'when the server availability zone of the server can be different from the disk' do
- let(:availability_zones) { double }
- let(:cloud_properties) { { 'availability_zones' => availability_zones } }
-
- it 'should return the multiple availability zones' do
- allow(availability_zones).to receive(:shuffle).and_return(%w[multiple_id multiple_id2])
- selected_availability_zones = az_provider.select_azs(cloud_properties)
-
- expect(availability_zones).to have_received(:shuffle)
- expect(selected_availability_zones).to include('multiple_id', 'multiple_id2')
- end
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/bin/openstack_cpi_spec.rb b/src/bosh_openstack_cpi/spec/unit/bin/openstack_cpi_spec.rb
deleted file mode 100644
index 5cee00311..000000000
--- a/src/bosh_openstack_cpi/spec/unit/bin/openstack_cpi_spec.rb
+++ /dev/null
@@ -1,144 +0,0 @@
-require 'spec_helper'
-require 'tempfile'
-require 'English'
-
-describe 'the openstack_cpi executable' do
- describe '#set_vm_metadata' do
- it 'will not evaluate anything that causes an exception and will return the proper message to stdout' do
- config_file = create_config_file('0.0.0.0:5000/v2.0')
- command_file = create_cpi_command_file('set_vm_metadata', [1, {}])
-
- stdoutput = execute_cpi_command(command_file, config_file)
- status = $CHILD_STATUS.exitstatus
-
- expect(status).to eq(0)
- result = JSON.parse(stdoutput)
-
- expect(result.keys).to eq(%w[result error log])
-
- expect(result['result']).to be_nil
-
- expect(result['error']).to eq(
- 'type' => 'Unknown',
- 'message' => 'bad URI (is not URI?): "0.0.0.0:5000"',
- 'ok_to_retry' => false,
- )
-
- expect(result['log']).to include('backtrace')
- end
-
- it 'will fail if registry.endpoint is not provided' do
- config_file = create_config_file('http://0.0.0.0:5000/v2.0', nil)
- command_file = create_cpi_command_file('set_vm_metadata', [1, {}])
-
- stdoutput = execute_cpi_command(command_file, config_file)
-
- result = JSON.parse(stdoutput)
-
- expect(result['result']).to be_nil
- expect(result['error']['type']).to eq('InvalidCall')
- expect(result['error']['message']).to match(/# { endpoint => Missing key } }/)
- expect(result['error']['ok_to_retry']).to eq(false)
- end
-
- it 'will return an appropriate error message when passed an invalid config file' do
- config_file = Tempfile.new('cloud_properties.yml')
- File.open(config_file, 'w') do |file|
- file.write({}.to_yaml)
- end
-
- command_file = create_cpi_command_file('set_vm_metadata', [1, {}])
-
- stdoutput = execute_cpi_command(command_file, config_file)
- status = $CHILD_STATUS.exitstatus
-
- expect(status).to eq(0)
- result = JSON.parse(stdoutput)
-
- expect(result.keys).to eq(%w[result error log])
-
- expect(result['result']).to be_nil
-
- expect(result['error']).to eq(
- 'type' => 'Unknown',
- 'message' => 'Could not find cloud properties in the configuration',
- 'ok_to_retry' => false,
- )
-
- expect(result['log']).to include('backtrace')
- end
- end
-
- describe '#calculate_vm_cloud_properties' do
- it 'raises an error if calculate_vm_cloud_properties fields are missing' do
- config_file = create_config_file('0.0.0.0:5000/v2.0')
- command_file = create_cpi_command_file('calculate_vm_cloud_properties', [{}])
-
- stdoutput = execute_cpi_command(command_file, config_file)
- status = $CHILD_STATUS.exitstatus
-
- expect(status).to eq(0)
- result = JSON.parse(stdoutput)
-
- expect(result.keys).to eq(%w[result error log])
-
- expect(result['result']).to be_nil
-
- expect(result['error']).to eq(
- 'type' => 'Unknown',
- 'message' => "Missing VM cloud properties: 'cpu', 'ram', 'ephemeral_disk_size'",
- 'ok_to_retry' => false,
- )
-
- expect(result['log']).to include('backtrace')
- end
- end
-end
-
-def create_config_file(auth_url = 'http://0.0.0.0:5000/v2.0', registry_endpoint = '0.0.0.0:5000')
- config_file = Tempfile.new('cloud_properties.yml')
- File.open(config_file, 'w') do |file|
- file.write(
- {
- 'cloud' => {
- 'properties' => {
- 'openstack' => {
- 'auth_url' => auth_url,
- 'username' => 'openstack-user',
- 'api_key' => 'openstack-password',
- 'tenant' => 'dev',
- 'region' => 'west-coast',
- 'endpoint_type' => 'publicURL',
- 'state_timeout' => 300,
- 'boot_from_volume' => false,
- 'stemcell_public_visibility' => false,
- 'connection_options' => {},
- 'default_key_name' => nil,
- 'default_security_groups' => nil,
- 'wait_resource_poll_interval' => 5,
- 'config_drive' => 'disk',
- },
- 'registry' => {
- 'endpoint' => registry_endpoint,
- 'user' => 'registry-user',
- 'password' => 'registry-password',
- },
- },
- },
- }.to_yaml,
- )
- end
- config_file
-end
-
-def create_cpi_command_file(method_name, method_args)
- command_file = Tempfile.new('command.json')
- File.open(command_file, 'w') do |file|
- file.write({ 'method' => method_name, 'arguments' => method_args, 'context' => { 'director_uuid' => 'abc123' } }.to_json)
- end
- command_file
-end
-
-def execute_cpi_command(command_file, config_file)
- `bin/openstack_cpi #{config_file.path} < #{command_file.path} 2> /dev/null`
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/bosh_release/jobs/cpi/templates/cpi.json.erb_spec.rb b/src/bosh_openstack_cpi/spec/unit/bosh_release/jobs/cpi/templates/cpi.json.erb_spec.rb
deleted file mode 100644
index 1e1347557..000000000
--- a/src/bosh_openstack_cpi/spec/unit/bosh_release/jobs/cpi/templates/cpi.json.erb_spec.rb
+++ /dev/null
@@ -1,175 +0,0 @@
-require 'spec_helper'
-require 'json'
-require 'yaml'
-require 'bosh/template/test'
-
-describe 'cpi.json.erb' do
- let(:cpi_v1_json) { JSON.parse(template.render(manifest_cpi_v1)) }
- let(:cpi_v2_json) { JSON.parse(template.render(manifest_cpi_v2)) }
-
- let(:release) { Bosh::Template::Test::ReleaseDir.new(File.join(File.dirname(__FILE__), '../../../../../../../../')) }
- let(:job) { release.job('openstack_cpi') }
- let(:template) { job.template('config/cpi.json') }
-
- let(:manifest_cpi_v1) do
- {
- 'openstack' => {
- 'auth_url' => 'openstack.auth_url',
- 'username' => 'openstack.username',
- 'api_key' => 'openstack.api_key',
- 'tenant' => 'openstack.tenant',
- 'default_key_name' => 'openstack.default_key_name',
- 'default_security_groups' => 'openstack.default_security_groups',
- 'wait_resource_poll_interval' => 'openstack.wait_resource_poll_interval',
- 'human_readable_vm_names' => false,
- 'ignore_server_availability_zone' => 'openstack.ignore_server_availability_zone',
- },
- 'ntp' => [],
- 'registry' => {
- 'username' => 'registry.username',
- 'password' => 'registry.password',
- 'host' => 'registry.host',
- 'endpoint' => 'http://registry.host:25777',
- },
- 'nats' => {
- 'address' => 'nats_address.example.com',
- 'password' => 'nats-password',
- 'user' => 'nats-user',
- },
- }
- end
-
- let(:manifest_cpi_v2) do
- {
- 'openstack' => {
- 'auth_url' => 'openstack.auth_url',
- 'username' => 'openstack.username',
- 'api_key' => 'openstack.api_key',
- 'tenant' => 'openstack.tenant',
- 'default_key_name' => 'openstack.default_key_name',
- 'default_security_groups' => 'openstack.default_security_groups',
- 'wait_resource_poll_interval' => 'openstack.wait_resource_poll_interval',
- 'human_readable_vm_names' => false,
- 'ignore_server_availability_zone' => 'openstack.ignore_server_availability_zone',
- },
- }
- end
-
- it 'is able to render the erb given most basic manifest properties' do
- expect(cpi_v2_json).to eq(
- 'cloud' => {
- 'plugin' => 'openstack',
- 'properties' => {
- 'openstack' => {
- 'api_key' => 'openstack.api_key',
- 'auth_url' => 'openstack.auth_url',
- 'boot_from_volume' => false,
- 'default_key_name' => 'openstack.default_key_name',
- 'default_security_groups' => 'openstack.default_security_groups',
- 'endpoint_type' => 'publicURL',
- 'ignore_server_availability_zone' => 'openstack.ignore_server_availability_zone',
- 'state_timeout' => 300,
- 'stemcell_public_visibility' => false,
- 'tenant' => 'openstack.tenant',
- 'use_dhcp' => true,
- 'username' => 'openstack.username',
- 'wait_resource_poll_interval' => 'openstack.wait_resource_poll_interval',
- 'human_readable_vm_names' => false,
- 'use_nova_networking' => false,
- 'default_volume_type' => nil,
- },
- },
- },
- )
- end
-
- context 'when using human readable VM names' do
- it 'template rendering succeeds' do
- manifest_cpi_v2['openstack']['human_readable_vm_names'] = true
-
- expect(cpi_v2_json['cloud']['properties']['openstack']['human_readable_vm_names']).to be true
- end
- end
-
- context 'when registry is configured for bosh-init' do
- it 'concatinates host and port as registry endpoint and template rendering succeeds' do
- manifest_cpi_v2['registry'] = {}
- manifest_cpi_v2['registry']['username'] = 'registry.username'
- manifest_cpi_v2['registry']['password'] = 'registry.password'
- manifest_cpi_v2['registry']['host'] = '127.0.0.1'
- manifest_cpi_v2['registry']['port'] = 6901
-
- expect(cpi_v2_json['cloud']['properties']['registry']['endpoint']).to eq('http://127.0.0.1:6901')
- end
-
- it 'it raises an error if some registry properties are missing' do
- manifest_cpi_v2['registry'] = {}
- manifest_cpi_v2['registry']['username'] = ''
- manifest_cpi_v2['registry']['password'] = ''
- manifest_cpi_v2['registry']['endpoint'] = 'http://registry.host:25777'
- manifest_cpi_v2['registry']['port'] = 6901
-
- expect { cpi_v2_json }.to raise_error Bosh::Template::UnknownProperty
- end
-
- it 'it does not raise an error if no registry properties are set' do
- manifest_cpi_v2['registry'] = {}
-
- expect { cpi_v2_json }.to_not raise_error
- expect(cpi_v2_json['cloud']['properties']['registry']).to eq(nil)
- end
- end
-
- describe 'when anti-affinity is configured' do
- [false, true].each do |prop|
- context "when anti-affinity is set to #{prop}" do
- it 'errors to inform the user this is no longer supported' do
- manifest_cpi_v1['openstack']['enable_auto_anti_affinity'] = prop
-
- expect { cpi_v1_json }.to raise_error RuntimeError,
- "Property 'enable_auto_anti_affinity' is no longer supported. Please remove it from your configuration."
- end
- end
- end
- end
-
- context 'when cpi api v1' do
- it 'is able to render the erb given most basic manifest properties' do
- expect(cpi_v1_json).to eq(
- 'cloud' => {
- 'plugin' => 'openstack',
- 'properties' => {
- 'agent' => {
- 'mbus' => 'nats://nats-user:nats-password@nats_address.example.com:4222',
- 'ntp' => [],
- },
- 'openstack' => {
- 'api_key' => 'openstack.api_key',
- 'auth_url' => 'openstack.auth_url',
- 'boot_from_volume' => false,
- 'default_key_name' => 'openstack.default_key_name',
- 'default_security_groups' => 'openstack.default_security_groups',
- 'endpoint_type' => 'publicURL',
- 'ignore_server_availability_zone' => 'openstack.ignore_server_availability_zone',
- 'state_timeout' => 300,
- 'stemcell_public_visibility' => false,
- 'tenant' => 'openstack.tenant',
- 'use_dhcp' => true,
- 'username' => 'openstack.username',
- 'wait_resource_poll_interval' => 'openstack.wait_resource_poll_interval',
- 'human_readable_vm_names' => false,
- 'use_nova_networking' => false,
- 'default_volume_type' => nil,
- },
- 'registry' => {
- 'address' => 'registry.host',
- 'endpoint' => 'http://registry.host:25777',
- 'password' => 'registry.password',
- 'user' => 'registry.username',
- },
- }
- }
- )
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/cloud_spec.rb b/src/bosh_openstack_cpi/spec/unit/cloud_spec.rb
deleted file mode 100644
index aae6d6dcf..000000000
--- a/src/bosh_openstack_cpi/spec/unit/cloud_spec.rb
+++ /dev/null
@@ -1,370 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- let(:default_connection_options) {
- { 'instrumentor' => Bosh::OpenStackCloud::ExconLoggingInstrumentor }
- }
- let(:cpi_api_version) { 1 }
-
- describe :new do
- let(:cloud_options) { mock_cloud_options }
- let(:cloud_options_stemcell_v2) do
- cloud_options['properties']['openstack']['vm'] = {
- 'stemcell' => {
- 'api_version' => 2,
- },
- }
- cloud_options
- end
-
- before {
- expect(Fog::OpenStack::Compute).to_not receive(:new)
- expect(Fog::OpenStack::Image).to_not receive(:new)
- expect(Fog::OpenStack::Volume).to_not receive(:new)
- expect(Fog::Network).to_not receive(:new)
- }
-
- context 'when CPI API v2 is called' do
- let(:cpi_api_version) { 2 }
-
- context 'when stemcell API v1 is used' do
- it 'creates a RegistryClient' do
- registry = Bosh::OpenStackCloud::Cloud.new(cloud_options['properties'], cpi_api_version).registry
- expect(registry).to be_instance_of(Bosh::Cpi::RegistryClient)
- end
- end
-
- context 'when stemcell API v2 is used' do
- it 'creates a NoopRegistry' do
- registry = Bosh::OpenStackCloud::Cloud.new(cloud_options_stemcell_v2['properties'], cpi_api_version).registry
- expect(registry).to be_instance_of(Bosh::OpenStackCloud::NoopRegistry)
- end
- end
- end
-
- context 'when CPI API v1 is called' do
- context 'when stemcell API v1 is used' do
- it 'creates a RegistryClient' do
- registry = Bosh::OpenStackCloud::Cloud.new(cloud_options['properties'], cpi_api_version).registry
- expect(registry).to be_instance_of(Bosh::Cpi::RegistryClient)
- end
- end
-
- context 'when stemcell API v2 is used' do
- it 'creates a RegistryClient' do
- registry = Bosh::OpenStackCloud::Cloud.new(cloud_options_stemcell_v2['properties'], cpi_api_version).registry
- expect(registry).to be_instance_of(Bosh::Cpi::RegistryClient)
- end
- end
-
- describe 'validation' do
- let(:options) do
- {
- 'openstack' => {
- 'username' => 'fake-username',
- 'api_key' => 'fake-api-key',
- },
- 'registry' => {
- 'endpoint' => 'fake-registry',
- 'user' => 'fake-user',
- 'password' => 'fake-password',
- },
- }
- end
- subject { Bosh::OpenStackCloud::Cloud.new(options, cpi_api_version) }
-
- context 'when keystone V2 API is used' do
- before do
- options['openstack']['auth_url'] = 'http://fake-auth-url/v2.0'
- options['openstack']['tenant'] = 'fake-tenant'
- end
-
- it 'does not raise an error' do
- expect { subject }.to_not raise_error
- end
-
- context 'when connection_options are specified' do
- it 'expects connection_options to be a hash' do
- options['openstack']['connection_options'] = { 'any-key' => 'any-value' }
-
- expect { subject }.to_not raise_error
- end
-
- it 'raises an error if connection_options is not a Hash' do
- options['openstack']['connection_options'] = 'connection_options'
-
- expect { subject }.to raise_error(ArgumentError, /Invalid OpenStack cloud properties/)
- end
- end
-
- context 'when boot_from_volume is specified' do
- it 'expects boot_from_volume to be a boolean' do
- options['openstack']['boot_from_volume'] = true
-
- expect { subject }.to_not raise_error
- end
-
- it 'raises an error if boot_from_volume is not a boolean' do
- options['openstack']['boot_from_volume'] = 'boot_from_volume'
-
- expect { subject }.to raise_error(ArgumentError, /Invalid OpenStack cloud properties/)
- end
- end
-
- context 'config_drive' do
- it 'accepts cdrom as a value' do
- options['openstack']['config_drive'] = 'cdrom'
- expect { subject }.to_not raise_error
- end
-
- it 'accepts disk as a value' do
- options['openstack']['config_drive'] = 'disk'
- expect { subject }.to_not raise_error
- end
-
- it 'accepts nil as a value' do
- options['openstack']['config_drive'] = nil
- expect { subject }.to_not raise_error
- end
-
- it 'raises an error if config_drive is not cdrom or disk or nil' do
- options['openstack']['config_drive'] = 'incorrect-value'
- expect { subject }.to raise_error(ArgumentError, /Invalid OpenStack cloud properties/)
- end
- end
- end
-
- context 'when keystone V3 API is used' do
- before do
- options['openstack']['auth_url'] = 'http://127.0.0.1:5000/v3'
- end
-
- it 'raises an error when no project or project_id is specified' do
- options['openstack']['domain'] = 'fake_domain'
- expect { subject }
- .to raise_error(ArgumentError,
- Regexp.new('Invalid OpenStack cloud properties: ' \
- '# { project => Missing key } }'))
- end
-
- it 'raises an error when no domain is specified' do
- options['openstack']['project'] = 'fake_project'
- expect { subject }
- .to raise_error(ArgumentError,
- Regexp.new('Invalid OpenStack cloud properties: ' \
- '# { domain => Missing key } }'))
- end
-
- context 'when project and domain are specified' do
- before do
- options['openstack']['project'] = 'fake_project'
- options['openstack']['domain'] = 'fake_domain'
- end
-
- it 'does not raise an error' do
- expect { subject }.to_not raise_error
- end
- end
-
- context 'when project_id and domain are specified' do
- before do
- options['openstack']['project_id'] = 'fake_project_id'
- options['openstack']['domain'] = 'fake_domain'
- end
-
- it 'does not raise an error' do
- expect { subject }.to_not raise_error
- end
- end
-
- context 'when project and user_domain_name and project_domain_name are specified' do
- before do
- options['openstack']['project'] = 'fake_project'
- options['openstack']['user_domain_name'] = 'fake_user_domain'
- options['openstack']['project_domain_name'] = 'fake_project_domain'
- end
-
- it 'does not raise an error' do
- expect { subject }.to_not raise_error
- end
- end
-
- context 'when checking authentication' do
- before do
- options['openstack']['auth_url'] = 'http://fake-auth-url/v2.0'
- options['openstack']['tenant'] = 'fake-tenant'
- end
-
- it 'raises ArgumentError if there are no authentication credentials provided' do
- options['openstack']['username'] = nil
- options['openstack']['api_key'] = nil
-
- expect { subject }.to raise_error(ArgumentError, /Invalid OpenStack cloud properties/)
- end
-
- it 'raises ArgumentError if only api_key is provided' do
- options['openstack']['api_key'] = nil
-
- expect { subject }.to raise_error(ArgumentError, /Invalid OpenStack cloud properties/)
- end
-
- it 'raises ArgumentError if only username is provided' do
- options['openstack']['username'] = nil
-
- expect { subject }.to raise_error(ArgumentError, /Invalid OpenStack cloud properties/)
- end
-
- it 'raises ArgumentError if both username and application credential id are provided' do
- options['openstack']['application_credential_id'] = 'fake-application-credential-id'
-
- expect { subject }.to raise_error(ArgumentError, /Invalid OpenStack cloud properties/)
- end
-
- it 'does not raise an error if application credential id and secret are provided' do
- options['openstack']['api_key'] = nil
- options['openstack']['username'] = nil
- options['openstack']['application_credential_id'] = 'fake-application-credential-id'
- options['openstack']['application_credential_secret'] = 'fake-application-credential-secret'
-
- expect { subject }.to_not raise_error
- end
-
- it 'raises ArgumentError if only application credential id is provided' do
- options['openstack']['api_key'] = nil
- options['openstack']['username'] = nil
- options['openstack']['application_credential_id'] = 'fake-application-credential-id'
-
- expect { subject }.to raise_error(ArgumentError, /Invalid OpenStack cloud properties/)
- end
-
- it 'raises ArgumentError if only application credential secret is provided' do
- options['openstack']['api_key'] = nil
- options['openstack']['username'] = nil
- options['openstack']['application_credential_secret'] = 'fake-application-credential-secret'
-
- expect { subject }.to raise_error(ArgumentError, /Invalid OpenStack cloud properties/)
- end
-
- it 'raises ArgumentError if too many credentials are provided' do
- options['openstack']['api_key'] = 'fake_api_key'
- options['openstack']['username'] = 'fake_username'
- options['openstack']['application_credential_id'] = 'fake-application-credential-id'
- options['openstack']['application_credential_secret'] = 'fake-application-credential-secret'
-
- expect { subject }.to raise_error(ArgumentError, /Invalid OpenStack cloud properties/)
- end
- end
-
- end
-
- context 'when options are empty' do
- let(:options) { Hash.new('options') }
-
- it 'raises ArgumentError' do
- expect { subject }.to raise_error(ArgumentError, /Invalid OpenStack cloud properties/)
- end
- end
-
- context 'when options are not a Hash' do
- let(:options) { 'this is a string' }
-
- it 'raises ArgumentError' do
- expect { subject }.to raise_error(ArgumentError, /Invalid OpenStack cloud properties/)
- end
- end
- end
- end
- end
-
- describe :update_agent_settings do
- let(:cloud_options) { mock_cloud_options }
- let(:connection_options) { nil }
- let(:merged_connection_options) { default_connection_options }
-
- let(:compute) { instance_double('Fog::OpenStack::Compute') }
- before { allow(Fog::OpenStack::Compute).to receive(:new).and_return(compute) }
-
- let(:image) { instance_double('Fog::Image') }
- before { allow(Fog::OpenStack::Image).to receive(:new).and_return(image) }
-
- context 'when server has no registry_key tag' do
- it 'uses the server name as key' do
- cpi = Bosh::OpenStackCloud::Cloud.new(cloud_options['properties'], cpi_api_version)
- server = double('server', id: 'id', name: 'name', metadata: double('metadata'))
-
- allow(server.metadata).to receive(:get).with(:registry_key).and_return(nil)
-
- expect(cpi.registry).to receive(:read_settings).with('name')
- expect(cpi.registry).to receive(:update_settings).with('name', anything)
-
- cpi.update_agent_settings(server) {
- # intentionally empty
- }
- end
- end
-
- context 'when server has a registry_key tag' do
- it 'uses the registry_key tag value as key' do
- cpi = Bosh::OpenStackCloud::Cloud.new(cloud_options['properties'], cpi_api_version)
- server = double('server', id: 'id', name: 'name', metadata: double('metadata'))
-
- allow(server.metadata).to receive(:get).with(:registry_key).and_return(double('metadatum', 'value' => 'registry-tag-value'))
-
- expect(cpi.registry).to receive(:read_settings).with('registry-tag-value')
- expect(cpi.registry).to receive(:update_settings).with('registry-tag-value', anything)
-
- cpi.update_agent_settings(server) {
- # intentionally empty
- }
- end
- end
-
- context 'when registry is used' do
- it 'logs that settings get updated' do
- cpi = Bosh::OpenStackCloud::Cloud.new(cloud_options['properties'], cpi_api_version)
- server = double('server', id: 'id', name: 'name', metadata: double('metadata'))
- allow(server.metadata).to receive(:get).with(:registry_key).and_return(nil)
- allow(cpi.registry).to receive(:read_settings)
- allow(cpi.registry).to receive(:update_settings)
-
- expect(cpi.logger).to receive(:info).with("Updating settings for server 'id' with registry key 'name'...")
-
- cpi.update_agent_settings(server) {
- # intentionally empty
- }
- end
- end
-
- context 'when registry is not used' do
- let(:cpi_api_version) { 2 }
- let(:cloud_options_stemcell_v2) do
- cloud_options['properties']['openstack']['vm'] = {
- 'stemcell' => {
- 'api_version' => 2,
- },
- }
- cloud_options
- end
- it 'does not log anything' do
- cpi = Bosh::OpenStackCloud::Cloud.new(cloud_options_stemcell_v2['properties'], cpi_api_version)
- server = double('server', id: 'id', name: 'name', metadata: double('metadata'))
- allow(server.metadata).to receive(:get).with(:registry_key).and_return(nil)
- expect(cpi.logger).to_not receive(:info)
-
- cpi.update_agent_settings(server) {
- # intentionally empty
- }
- end
- end
- end
-
- describe :info do
- let(:cloud_options) { mock_cloud_options }
-
- it 'returns correct info' do
- cpi = Bosh::OpenStackCloud::Cloud.new(cloud_options['properties'], cpi_api_version)
- expect(cpi.info).to eq('api_version' => 2, 'stemcell_formats' => ['openstack-raw', 'openstack-qcow2', 'openstack-light'])
- end
- end
-
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/configure_networks_spec.rb b/src/bosh_openstack_cpi/spec/unit/configure_networks_spec.rb
deleted file mode 100644
index d87acefa6..000000000
--- a/src/bosh_openstack_cpi/spec/unit/configure_networks_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- it 'forces recreation always' do
- expect {
- mock_cloud.configure_networks('i-test', 'net_a' => { 'type' => 'foo' })
- }.to raise_error(Bosh::Clouds::NotSupported, /network configuration change requires VM recreation/)
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/cpi_lambda_spec.rb b/src/bosh_openstack_cpi/spec/unit/cpi_lambda_spec.rb
deleted file mode 100644
index 929e6bfb1..000000000
--- a/src/bosh_openstack_cpi/spec/unit/cpi_lambda_spec.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::CpiLambda do
- subject { described_class.create(cpi_config, cpi_log, ssl_ca_file, ca_cert_from_context) }
- let(:cpi_config) {
- {
- 'cloud' => {
- 'properties' => {
- 'openstack' => {
- 'key1' => 'value1',
- 'key2' => 'value2',
- },
- },
- },
- }
- }
- let(:ssl_ca_file) { 'feel-free-to-change' }
- let(:cpi_log) { StringIO.new }
- let(:ca_cert_from_context) { Tempfile.new('ca_cert').path }
-
- describe 'when creating a cloud' do
- it 'passes parts of the cpi config to openstack' do
- expect(Bosh::Clouds::Openstack).to receive(:new).with({ 'openstack' => cpi_config['cloud']['properties']['openstack'],
- 'cpi_log' => cpi_log }, 1)
- subject.call({}, 1)
- end
-
- context 'if invalid cpi config is given' do
- let(:cpi_config) { { 'empty' => 'config' } }
-
- it 'raises an error' do
- expect {
- subject.call({}, 1)
- }.to raise_error(/Could not find cloud properties in the configuration/)
- end
- end
-
- context 'if using ca_certs in config' do
- let(:cpi_config) do
- { 'cloud' => { 'properties' => { 'openstack' => { 'connection_options' => { 'ca_cert' => 'xyz' } } } } }
- end
-
- it 'sets ssl_ca_file that is passed and removes ca_certs' do
- expect(Bosh::Clouds::Openstack).to receive(:new)
- .with({ 'openstack' => { 'connection_options' => { 'ssl_ca_file' => ssl_ca_file } }, 'cpi_log' => cpi_log }, 1)
- subject.call({}, 1)
- end
- end
-
- context 'if openstack properties are provided in the context' do
- it 'merges the openstack properties' do
- context = {
- 'newkey' => 'newvalue',
- 'newkey2' => 'newvalue2',
- }
-
- expect(Bosh::Clouds::Openstack).to receive(:new).with({ 'openstack' => { 'key1' => 'value1',
- 'key2' => 'value2',
- 'newkey' => 'newvalue',
- 'newkey2' => 'newvalue2' },
- 'cpi_log' => cpi_log }, 1)
- subject.call(context, 1)
- end
-
- it 'writes the given ca_cert to the disk and sets ssl_ca_file to its path' do
- context = {
- 'newkey' => 'newvalue',
- 'connection_options' => { 'ca_cert' => 'xyz' },
- }
-
- expect(Bosh::Clouds::Openstack).to receive(:new)
- .with({ 'openstack' => { 'newkey' => 'newvalue',
- 'key1' => 'value1',
- 'key2' => 'value2',
- 'connection_options' => { 'ssl_ca_file' => ca_cert_from_context } },
- 'cpi_log' => cpi_log }, 1)
-
- subject.call(context, 1)
- expect(File.read(ca_cert_from_context)).to eq('xyz')
- end
-
- context 'when the context does not include a ca_cert' do
- it 'does not write into the file' do
- allow(Bosh::Clouds::Openstack).to receive(:new)
-
- subject.call({}, 1)
-
- expect(File.read(ca_cert_from_context)).to eq('')
- end
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/create_disk_spec.rb b/src/bosh_openstack_cpi/spec/unit/create_disk_spec.rb
deleted file mode 100644
index e8870d803..000000000
--- a/src/bosh_openstack_cpi/spec/unit/create_disk_spec.rb
+++ /dev/null
@@ -1,180 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- describe 'connecting to the OpenStack Volume Service' do
- it 'connects when creating a volume' do
- unique_name = SecureRandom.uuid
- disk_params = {
- display_name: "volume-#{unique_name}",
- display_description: '',
- name: "volume-#{unique_name}",
- description: '',
- size: 2,
- }
- volume = double('volume', id: 'v-foobar')
-
- cloud = mock_cloud do |fog|
- allow(fog.volume.volumes).to receive(:create)
- .with(disk_params).and_return(volume)
- end
-
- allow(cloud).to receive(:generate_unique_name).and_return(unique_name)
- allow(cloud.openstack).to receive(:wait_resource).with(volume, :available)
-
- expect(Fog::OpenStack::Volume).to receive(:new)
- expect(cloud.create_disk(2048, {})).to eq('v-foobar')
- end
- end
-
- it 'creates an OpenStack volume' do
- unique_name = SecureRandom.uuid
- disk_params = {
- display_name: "volume-#{unique_name}",
- display_description: '',
- name: "volume-#{unique_name}",
- description: '',
- size: 2,
- }
- volume = double('volume', id: 'v-foobar')
-
- cloud = mock_cloud do |fog|
- allow(fog.volume.volumes).to receive(:create)
- .with(disk_params).and_return(volume)
- end
-
- allow(cloud).to receive(:generate_unique_name).and_return(unique_name)
- allow(cloud.openstack).to receive(:wait_resource).with(volume, :available)
-
- expect(cloud.create_disk(2048, {})).to eq('v-foobar')
- end
-
- it 'creates an OpenStack volume with the specified volume_type' do
- unique_name = SecureRandom.uuid
- disk_params = {
- display_name: "volume-#{unique_name}",
- display_description: '',
- name: "volume-#{unique_name}",
- description: '',
- size: 2,
- volume_type: 'foo',
- }
- volume = double('volume', id: 'v-foobar')
-
- cloud = mock_cloud do |fog|
- expect(fog.volume.volumes).to receive(:create)
- .with(disk_params).and_return(volume)
- end
-
- expect(cloud).to receive(:generate_unique_name).and_return(unique_name)
- expect(cloud.openstack).to receive(:wait_resource).with(volume, :available)
-
- expect(cloud.create_disk(2048, 'type' => 'foo')).to eq('v-foobar')
- end
-
- it 'creates an OpenStack volume with the default volume_type' do
- unique_name = SecureRandom.uuid
- disk_params = {
- display_name: "volume-#{unique_name}",
- display_description: '',
- name: "volume-#{unique_name}",
- description: '',
- size: 2,
- volume_type: 'default-type',
- }
- volume = double('volume', id: 'v-foobar')
-
- global_properties = mock_cloud_options['properties']
- global_properties['openstack']['default_volume_type'] = 'default-type'
- cloud = mock_cloud(global_properties) do |fog|
- expect(fog.volume.volumes).to receive(:create)
- .with(disk_params).and_return(volume)
- end
-
- expect(cloud).to receive(:generate_unique_name).and_return(unique_name)
- expect(cloud.openstack).to receive(:wait_resource).with(volume, :available)
-
- expect(cloud.create_disk(2048, {})).to eq('v-foobar')
- end
-
- it 'rounds up disk size' do
- unique_name = SecureRandom.uuid
- disk_params = {
- display_name: "volume-#{unique_name}",
- display_description: '',
- name: "volume-#{unique_name}",
- description: '',
- size: 3,
- }
- volume = double('volume', id: 'v-foobar')
-
- cloud = mock_cloud do |fog|
- expect(fog.volume.volumes).to receive(:create)
- .with(disk_params).and_return(volume)
- end
-
- expect(cloud).to receive(:generate_unique_name).and_return(unique_name)
- expect(cloud.openstack).to receive(:wait_resource).with(volume, :available)
-
- cloud.create_disk(2049, {})
- end
-
- it 'check min disk size' do
- expect {
- mock_cloud.create_disk(100, {})
- }.to raise_error(Bosh::Clouds::CloudError, /Minimum disk size is 1 GiB/)
- end
-
- it 'puts disk in the same AZ as a server' do
- unique_name = SecureRandom.uuid
- disk_params = {
- display_name: "volume-#{unique_name}",
- display_description: '',
- name: "volume-#{unique_name}",
- description: '',
- size: 1,
- availability_zone: 'foobar-land',
- }
- server = double('server', id: 'i-test',
- availability_zone: 'foobar-land')
- volume = double('volume', id: 'v-foobar')
-
- cloud = mock_cloud do |fog|
- expect(fog.compute.servers).to receive(:get)
- .with('i-test').and_return(server)
- expect(fog.volume.volumes).to receive(:create)
- .with(disk_params).and_return(volume)
- end
-
- expect(cloud).to receive(:generate_unique_name).and_return(unique_name)
- expect(cloud.openstack).to receive(:wait_resource).with(volume, :available)
-
- cloud.create_disk(1024, {}, 'i-test')
- end
-
- it 'does not put disk in the same AZ as a server if asked not to' do
- unique_name = SecureRandom.uuid
- disk_params = {
- display_name: "volume-#{unique_name}",
- display_description: '',
- name: "volume-#{unique_name}",
- description: '',
- size: 1,
- }
- double('server', id: 'i-test',
- availability_zone: 'foobar-land')
- volume = double('volume', id: 'v-foobar')
-
- cloud_options = mock_cloud_options
- cloud_options['properties']['openstack']['ignore_server_availability_zone'] = true
-
- cloud = mock_cloud(cloud_options['properties']) do |fog|
- expect(fog.volume.volumes).to receive(:create)
- .with(disk_params).and_return(volume)
- end
-
- expect(cloud).to receive(:generate_unique_name).and_return(unique_name)
- expect(cloud.openstack).to receive(:wait_resource).with(volume, :available)
-
- cloud.create_disk(1024, {}, 'i-test')
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/create_stemcell_spec.rb b/src/bosh_openstack_cpi/spec/unit/create_stemcell_spec.rb
deleted file mode 100644
index 0ead5c70d..000000000
--- a/src/bosh_openstack_cpi/spec/unit/create_stemcell_spec.rb
+++ /dev/null
@@ -1,266 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- let(:image) { double('image', id: 'i-bar') }
- let(:unique_name) { SecureRandom.uuid }
-
- before { @tmp_dir = Dir.mktmpdir }
-
- describe 'Image upload based flow' do
- let(:cloud_options) { nil }
-
- context 'given a heavy stemcell' do
- before do
- @cloud = mock_glance(cloud_options) do |glance|
- @glance = glance
- end
- end
-
- it 'creates an image and uploads data using a stemcell file' do
- image_params = {
- name: 'stemcell-name/x.y.z',
- disk_format: 'qcow2',
- container_format: 'bare',
- visibility: 'private',
- version: 'x.y.z',
- }
-
- expect(@glance.images).to receive(:create).with(image_params).and_return(image)
- allow(image).to receive(:reload).and_return({})
- allow(image).to receive(:status).and_return(:not_queued, :queued, :not_active, :active)
- expect(@cloud.openstack).to receive(:sleep).with(3).twice
-
- expect(Dir).to receive(:mktmpdir).and_yield(@tmp_dir)
- expect_any_instance_of(Bosh::OpenStackCloud::HeavyStemcellCreator).to receive(:unpack_image).with(@tmp_dir, '/tmp/foo')
-
- fake_file = double(File)
-
- expect(File).to receive(:open).with("#{@tmp_dir}/root.img", 'rb').and_return(fake_file)
-
- expect(image).to receive(:upload_data).with(fake_file)
-
- sc_id = @cloud.create_stemcell('/tmp/foo',
- 'name' => 'stemcell-name',
- 'version' => 'x.y.z',
- 'container_format' => 'bare',
- 'disk_format' => 'qcow2')
-
- expect(sc_id).to eq 'i-bar'
- end
-
- it 'sets custom image properties from cloud_properties' do
- image_params = {
- name: 'stemcell-name/x.y.z',
- disk_format: 'qcow2',
- container_format: 'bare',
- visibility: 'private',
- version: 'x.y.z',
- os_type: 'linux',
- os_distro: 'ubuntu',
- architecture: 'x86_64',
- auto_disk_config: 'true',
- }
-
- expect(@glance.images).to receive(:create).with(image_params).and_return(image)
-
- expect(Dir).to receive(:mktmpdir).and_yield(@tmp_dir)
- expect_any_instance_of(Bosh::OpenStackCloud::HeavyStemcellCreator).to receive(:unpack_image).with(@tmp_dir, '/tmp/foo')
- expect(@cloud.openstack).to receive(:wait_resource).with(image, :queued)
-
- fake_file = double(File)
-
- expect(File).to receive(:open).with("#{@tmp_dir}/root.img", 'rb').and_return(fake_file)
-
- expect(image).to receive(:upload_data).with(fake_file)
-
- expect(@cloud.openstack).to receive(:wait_resource).with(image, :active)
-
- sc_id = @cloud.create_stemcell('/tmp/foo',
- 'name' => 'stemcell-name',
- 'version' => 'x.y.z',
- 'os_type' => 'linux',
- 'os_distro' => 'ubuntu',
- 'architecture' => 'x86_64',
- 'auto_disk_config' => 'true',
- 'foo' => 'bar',
- 'container_format' => 'bare',
- 'disk_format' => 'qcow2')
-
- expect(sc_id).to eq 'i-bar'
- end
-
- it 'passes through whitelisted glance properties from cloud_properties to glance when making a stemcell' do
- extra_properties = {
- 'name' => 'stemcell-name',
- 'version' => 'x.y.z',
- 'os_type' => 'linux',
- 'os_distro' => 'ubuntu',
- 'architecture' => 'x86_64',
- 'auto_disk_config' => 'true',
- 'foo' => 'bar',
- 'container_format' => 'bare',
- 'disk_format' => 'qcow2',
- 'hw_vif_model' => 'fake-hw_vif_model',
- 'hypervisor' => 'fake-hypervisor_type', # hypervisor turns into hypervisor_type
- }
-
- image_params = {
- name: 'stemcell-name/x.y.z',
- disk_format: 'qcow2',
- container_format: 'bare',
- visibility: 'private',
- version: 'x.y.z',
- os_type: 'linux',
- os_distro: 'ubuntu',
- architecture: 'x86_64',
- auto_disk_config: 'true',
- hw_vif_model: 'fake-hw_vif_model',
- hypervisor_type: 'fake-hypervisor_type',
- }
-
- expect(@glance.images).to receive(:create).with(image_params).and_return(image)
-
- allow(Dir).to receive(:mktmpdir).and_yield(@tmp_dir)
- allow_any_instance_of(Bosh::OpenStackCloud::HeavyStemcellCreator).to receive(:unpack_image)
- allow(@cloud.openstack).to receive(:wait_resource).with(image, :queued)
-
- fake_file = double(File)
- expect(File).to receive(:open).with("#{@tmp_dir}/root.img", 'rb').and_return(fake_file)
- expect(image).to receive(:upload_data).with(fake_file)
-
- allow(@cloud.openstack).to receive(:wait_resource).with(image, :active)
-
- @cloud.create_stemcell('/tmp/foo', extra_properties)
- end
-
- it 'should throw an error for non existent root image in stemcell archive' do
- result = Bosh::Exec::Result.new('cmd', 'output', 0)
- expect(Bosh::Exec).to receive(:sh).and_return(result)
-
- allow(File).to receive(:exists?).and_return(false)
-
- expect {
- @cloud.create_stemcell('/tmp/foo',
- 'name' => 'stemcell-name',
- 'version' => 'x.y.z',
- 'container_format' => 'bare',
- 'disk_format' => 'qcow2')
- }.to raise_exception(Bosh::Clouds::CloudError, 'Root image is missing from stemcell archive')
- end
-
- it 'should fail if cannot extract root image' do
- result = Bosh::Exec::Result.new('cmd', 'output', 1)
- expect(Bosh::Exec).to receive(:sh).and_return(result)
-
- expect(Dir).to receive(:mktmpdir).and_yield(@tmp_dir)
-
- expect {
- @cloud.create_stemcell('/tmp/foo',
- 'name' => 'stemcell-name',
- 'version' => 'x.y.z',
- 'container_format' => 'ami',
- 'disk_format' => 'ami')
- }.to raise_exception(Bosh::Clouds::CloudError,
- 'Extracting stemcell root image failed. Check task debug log for details.')
- end
-
- context 'stemcell_public_visibility is true' do
- let(:cloud_options) do
- cloud_options = mock_cloud_options['properties']
- cloud_options['openstack']['stemcell_public_visibility'] = true
- cloud_options
- end
-
- it 'sets stemcell visibility to public when required' do
- image_params = {
- name: 'stemcell-name/x.y.z',
- disk_format: 'qcow2',
- container_format: 'bare',
- visibility: 'public',
- version: 'x.y.z',
- }
-
- expect(@glance.images).to receive(:create).with(image_params).and_return(image)
-
- expect(Dir).to receive(:mktmpdir).and_yield(@tmp_dir)
- expect_any_instance_of(Bosh::OpenStackCloud::HeavyStemcellCreator).to receive(:unpack_image).with(@tmp_dir, '/tmp/foo')
- expect(@cloud.openstack).to receive(:wait_resource).with(image, :queued)
-
- fake_file = double(File)
- expect(File).to receive(:open).with("#{@tmp_dir}/root.img", 'rb').and_return(fake_file)
- expect(image).to receive(:upload_data).with(fake_file)
-
- expect(@cloud.openstack).to receive(:wait_resource).with(image, :active)
-
- sc_id = @cloud.create_stemcell('/tmp/foo',
- 'name' => 'stemcell-name',
- 'version' => 'x.y.z',
- 'container_format' => 'bare',
- 'disk_format' => 'qcow2')
-
- expect(sc_id).to eq 'i-bar'
- end
- end
- end
-
- context 'given a light stemcell' do
- let(:images) { double('images', get: image) }
- let(:image) { double('image', id: 'image_id', status: 'active') }
-
- before(:each) do
- @cloud = mock_glance(cloud_options) do |glance|
- @glance = glance
- allow(glance).to receive(:images).and_return(images)
- end
- end
-
- it 'returns the image id with ` light` suffix' do
- cloud_properties = {
- 'image_id' => 'image_id',
- }
-
- stemcell_id = @cloud.create_stemcell('/tmp/foo', cloud_properties)
-
- expect(stemcell_id).to eq('image_id light')
- end
-
- it 'checks if image with id exists in OpenStack' do
- cloud_properties = {
- 'image_id' => 'image_id',
- }
-
- @cloud.create_stemcell('/tmp/foo', cloud_properties)
-
- expect(images).to have_received(:get).with('image_id')
- end
-
- context 'when image with given id does not exist in OpenStack' do
- let(:images) { double('images', get: nil) }
-
- it 'raises a cloud error' do
- cloud_properties = {
- 'image_id' => 'non_existing_image_id',
- }
-
- expect {
- @cloud.create_stemcell('/tmp/foo', cloud_properties)
- }.to raise_error(Bosh::Clouds::CloudError, 'No active image with id \'non_existing_image_id\' referenced by light stemcell found in OpenStack.')
- end
- end
-
- context 'when image with given id is not in state `active`' do
- let(:image) { double('image', id: 'image_id', status: 'not-active') }
-
- it 'raises a cloud error' do
- cloud_properties = {
- 'image_id' => 'image_id',
- }
-
- expect {
- @cloud.create_stemcell('/tmp/foo', cloud_properties)
- }.to raise_error(Bosh::Clouds::CloudError, 'No active image with id \'image_id\' referenced by light stemcell found in OpenStack.')
- end
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/create_vm_spec.rb b/src/bosh_openstack_cpi/spec/unit/create_vm_spec.rb
deleted file mode 100644
index 7da9f4778..000000000
--- a/src/bosh_openstack_cpi/spec/unit/create_vm_spec.rb
+++ /dev/null
@@ -1,1055 +0,0 @@
-require 'spec_helper'
-require 'excon'
-
-describe Bosh::OpenStackCloud::Cloud, 'create_vm' do
- def agent_settings(unique_name, network_spec = dynamic_network_spec, ephemeral = '/dev/sdb')
- {
- 'vm' => {
- 'name' => "vm-#{unique_name}",
- },
- 'agent_id' => 'agent-id',
- 'networks' => { 'network_a' => network_spec },
- 'disks' => {
- 'system' => '/dev/sda',
- 'ephemeral' => ephemeral,
- 'persistent' => {},
- },
- 'env' => {
- 'test_env' => 'value',
- },
- 'foo' => 'bar', # Agent env
- 'baz' => 'zaz',
- }
- end
-
- def openstack_params(network_spec = { 'network_a' => dynamic_network_spec }, boot_from_volume = false)
- params = {
- name: "vm-#{unique_name}",
- image_ref: 'sc-id',
- flavor_ref: 'f-test',
- key_name: 'test_key',
- security_groups: configured_security_groups,
- os_scheduler_hints: scheduler_hints,
- nics:,
- config_drive: false,
- user_data: JSON.dump(user_data(unique_name, network_spec, nameserver, false)),
- availability_zone: 'foobar-1a',
- }
-
- if boot_from_volume
- params.delete(:image_ref)
- params[:block_device_mapping_v2] = [{
- uuid: 'sc-id',
- source_type: 'image',
- destination_type: 'volume',
- volume_size: 2,
- boot_index: '0',
- delete_on_termination: '1',
- device_name: '/dev/vda',
- }]
- end
-
- params
- end
-
- def user_data(unique_name, network_spec, nameserver = nil, openssh = false)
- user_data = {
- 'server' => {
- 'name' => "vm-#{unique_name}",
- },
- }
- user_data['openssh'] = { 'public_key' => 'public openssh key' } if openssh
- user_data['networks'] = network_spec
- user_data['dns'] = { 'nameserver' => [nameserver] } if nameserver
- user_data['registry'] = { 'endpoint' => 'http://registry:3333' }
- user_data
- end
-
- let(:unique_name) { SecureRandom.uuid }
- let(:server) { double('server', id: 'i-test', name: 'i-test') }
- let(:image) { double('image', id: 'sc-id', name: 'sc-id') }
- let(:flavor) { double('flavor', id: 'f-test', name: 'm1.tiny', ram: 1024, disk: 2, ephemeral: 2) }
- let(:key_pair) {
- double('key_pair', id: 'k-test', name: 'test_key',
- fingerprint: '00:01:02:03:04', public_key: 'public openssh key')
- }
- let(:configured_security_groups) { %w[default] }
- let(:nameserver) { nil }
- let(:nics) { [] }
- let(:scheduler_hints) { nil }
- let(:options) { mock_cloud_options['properties'] }
- let(:environment) { { 'test_env' => 'value' } }
- let(:cpi_api_version) { 1 }
- let(:cloud) do
- mock_cloud(options, cpi_api_version) do |fog|
- allow(fog.image.images).to receive(:find_by_id).and_return(image)
- allow(fog.compute.servers).to receive(:create).and_return(server)
- allow(fog.compute.flavors).to receive(:find).and_return(flavor)
- allow(fog.compute.key_pairs).to receive(:find).and_return(key_pair)
- end
- end
- let(:network_configuration) { { 'network_a' => dynamic_network_spec } }
-
-
- before(:each) do
- @registry = mock_registry
- Bosh::Clouds::Config.configure(double('config', uuid: 'director-uuid'))
- allow(@registry).to receive(:delete_settings)
- allow(@registry).to receive(:update_settings)
- allow(cloud).to receive(:generate_unique_name).and_return(unique_name)
- allow(cloud.openstack).to receive(:wait_resource)
- allow(Bosh::OpenStackCloud::TagManager).to receive(:tag_server)
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:port_ids).and_return([])
- end
-
- it 'redacts user_data' do
- allow(Bosh::Clouds::Config.logger).to receive(:debug)
-
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
-
- expect(Bosh::Clouds::Config.logger).to have_received(:debug).with(/Using boot params:.*"user_data" => ""/)
- end
-
- it "creates an OpenStack server and polls until it's ready" do
- vm_id = cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- expect(cloud.openstack).to have_received(:wait_resource).with(server, :active, :state)
- expect(vm_id).to eq('i-test')
- end
-
- describe 'multi-homed VMs' do
- let(:cloud) do
- cloud_options = mock_cloud_options['properties']
- cloud_options['openstack'].merge!(
- 'config_drive' => 'cdrom',
- 'use_dhcp' => false,
- 'use_nova_networking' => false,
- )
-
- mock_cloud(cloud_options) do |openstack|
- allow(openstack.compute.servers).to receive(:create).and_return(server)
- allow(openstack.image.images).to receive(:find_by_id).and_return(image)
- allow(openstack.compute.flavors).to receive(:find).and_return(flavor)
- allow(openstack.compute.key_pairs).to receive(:find).and_return(key_pair)
- port_result_net = double('ports1', id: '117717c1-81cb-4ac4-96ab-99aaf1be9ca8', network_id: 'net', mac_address: 'AA:AA:AA:AA:AA:AA')
- ports = double('Fog::OpenStack::Network::Ports')
- allow(ports).to receive(:create).with({network_id: 'net', fixed_ips: [{ ip_address: '10.0.0.1' }], security_groups: ['default_sec_group_id']}).and_return(port_result_net)
- allow(openstack.network).to receive(:ports).and_return(ports)
- end
- end
- let(:network_spec) { { 'network_a' => manual_network_spec(ip: '10.0.0.1') } }
- let(:expected_network_spec) { { 'network_a' => manual_network_spec(ip: '10.0.0.1', overwrites: { 'mac' => 'AA:AA:AA:AA:AA:AA', 'use_dhcp' => false }) } }
- let(:nics) { [{ 'net_id' => 'net', 'port_id' => '117717c1-81cb-4ac4-96ab-99aaf1be9ca8' }] }
-
- it 'creates an OpenStack server with config drive and mac addresses' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_spec, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(openstack_params(expected_network_spec).merge(config_drive: true))
- end
- end
-
- context 'with nameserver' do
- let(:nameserver) { '1.2.3.4' }
- let(:network_spec) do
- network_spec = dynamic_network_spec
- network_spec['dns'] = [nameserver]
- network_spec
- end
-
- it 'passes dns servers in server user data when present' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => network_spec }, nil, environment)
-
- expect(cloud.openstack.compute.servers).to have_received(:create).with(openstack_params('network_a' => network_spec))
- expect(@registry).to have_received(:update_settings).with("vm-#{unique_name}", agent_settings(unique_name, network_spec))
- end
- end
-
- context 'with security groups' do
- let(:network_with_security_group) {
- ns = dynamic_network_spec
- ns['cloud_properties'] ||= {}
- ns['cloud_properties']['security_groups'] = %w[net-group-1 net-group-2]
- { 'network_a' => ns }
- }
-
- let(:resource_pool_with_security_group_spec) {
- rps = resource_pool_spec
- rps['security_groups'] = %w[pool-group-1 pool-group-2]
- rps
- }
-
- before(:each) do
- mock_sec_groups(cloud.network, openstack_security_groups)
- end
-
- context 'defined in both network and resource_pools spec' do
- let(:openstack_security_groups) {
- [
- double('net-group-1', id: 'net-group-1_id', name: 'net-group-1'),
- double('net-group-2', id: 'net-group-2_id', name: 'net-group-2'),
- double('pool-group-1', id: 'pool-group-1_id', name: 'pool-group-1'),
- double('pool-group-2', id: 'pool-group-2_id', name: 'pool-group-2'),
- ]
- }
-
- it 'uses the resource pool security groups to create vm' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_with_security_group_spec, network_with_security_group, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(hash_including(security_groups: %w[pool-group-1 pool-group-2]))
- end
- end
-
- context 'defined in network spec' do
- let(:openstack_security_groups) {
- [
- double('net-group-1', id: 'net-group-1_id', name: 'net-group-1'),
- double('net-group-2', id: 'net-group-2_id', name: 'net-group-2'),
- ]
- }
-
- let(:configured_security_groups) { %w[net-group-1 net-group-2] }
-
- it 'creates an OpenStack server' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_with_security_group, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(openstack_params(network_with_security_group))
- expect(@registry).to have_received(:update_settings).with("vm-#{unique_name}", agent_settings(unique_name, network_with_security_group['network_a']))
- end
- end
-
- context 'defined in resource_pools spec' do
- let(:openstack_security_groups) {
- [
- double('pool-group-1', id: 'pool-group-1_id', name: 'pool-group-1'),
- double('pool-group-2', id: 'pool-group-2_id', name: 'pool-group-2'),
- ]
- }
-
- let(:configured_security_groups) { %w[pool-group-1 pool-group-2] }
-
- let(:dynamic_network_without_security_group) do
- ns = dynamic_network_spec
- ns['cloud_properties'] = {}
- { 'network_a' => ns }
- end
-
- it 'creates an OpenStack server' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_with_security_group_spec, dynamic_network_without_security_group, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(openstack_params(dynamic_network_without_security_group))
- expect(@registry).to have_received(:update_settings).with("vm-#{unique_name}", agent_settings(unique_name, dynamic_network_without_security_group['network_a']))
- end
- end
- end
-
- context 'with dynamic network' do
- context 'with nic' do
- let(:nics) do
- [
- { 'net_id' => 'foo' },
- ]
- end
-
- it 'creates an OpenStack server with nic for dynamic network' do
- network_spec = dynamic_network_spec
- network_spec['cloud_properties'] ||= {}
- network_spec['cloud_properties']['net_id'] = nics[0]['net_id']
-
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => network_spec }, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(openstack_params('network_a' => network_spec))
- expect(@registry).to have_received(:update_settings).with("vm-#{unique_name}", agent_settings(unique_name, network_spec))
- end
- end
-
- context 'when vrrp ip is configured' do
- let(:resource_pool_with_vrrp) {
- rps = resource_pool_spec
- rps['allowed_address_pairs'] = '10.0.0.10'
- rps
- }
-
- it 'raises an cloud error' do
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_with_vrrp, { 'network' => dynamic_network_with_netid_spec }, nil, environment)
- }.to raise_error Bosh::Clouds::CloudError, "Network with id 'net' is a dynamic network. VRRP is not supported for dynamic networks"
- end
- end
- end
-
- context 'with manual network' do
- let(:several_manual_networks) do
- {
- 'network_a' => manual_network_spec(ip: '10.0.0.1'),
- 'network_b' => manual_network_spec(net_id: 'bar', ip: '10.0.0.2'),
- }
- end
- let(:manual_network) { { 'network_a' => manual_network_spec(ip: '10.0.0.1') } }
-
- let(:nics) { [{ 'net_id' => 'net', 'v4_fixed_ip' => '10.0.0.1' }, { 'net_id' => 'bar', 'v4_fixed_ip' => '10.0.0.2' }] }
- let(:configured_security_groups) { %w[default default] }
- let(:options) do
- cloud_options = mock_cloud_options
- cloud_options['properties']['openstack']['config_drive'] = 'cdrom'
- cloud_options['properties']['openstack']['use_dhcp'] = false
- cloud_options['properties']
- end
-
- it 'calls NetworkConfigurator#prepare and NetworkConfigurator#nics' do
- expect(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:new).with(anything, nil).and_call_original
- expect_any_instance_of(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:prepare).with(anything)
- expect_any_instance_of(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:nics).and_return(nics)
-
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, several_manual_networks, nil, environment)
- end
-
- context 'when vrrp ip is configured' do
- let(:resource_pool_with_vrrp) {
- rps = resource_pool_spec
- rps['allowed_address_pairs'] = '10.0.0.10'
- rps
- }
-
- it 'calls NetworkConfigurator#prepare and NetworkConfigurator#nics' do
- expect(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:new).with(anything, '10.0.0.10').and_call_original
- expect_any_instance_of(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:prepare).with(anything)
- expect_any_instance_of(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:nics).and_return(nics)
-
- cloud.create_vm('agent-id', 'sc-id', resource_pool_with_vrrp, several_manual_networks, nil, environment)
- end
- end
-
- context 'when vm_destroy fails' do
- before(:each) do
- allow(server).to receive(:destroy).and_raise 'BOOM!!!'
- allow_any_instance_of(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:prepare)
- allow_any_instance_of(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:cleanup)
- end
-
- it 'calls NetworkConfigurator#cleanup and fails with VMCreationFailed error' do
- allow_any_instance_of(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:configure).and_raise 'BOOM configure!!!'
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, manual_network, nil, environment)
- }.to raise_error Bosh::Clouds::VMCreationFailed, 'BOOM configure!!!'
- end
- end
- end
-
- context 'with scheduler hints' do
- let(:scheduler_hints) do
- { group: 'abcd-foo-bar' }
- end
-
- it 'creates an OpenStack server with scheduler hints' do
- allow_any_instance_of(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:configure)
-
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec.merge('scheduler_hints' => scheduler_hints), combined_network_spec)
-
- expect(cloud.compute.servers).to have_received(:create).with(openstack_params(combined_network_spec))
- end
- end
-
- context 'when boot_from_volume is set' do
- let(:dynamic_network) { { 'network_a' => dynamic_network_spec } }
-
- context 'globally' do
- let(:options) do
- cloud_options = mock_cloud_options
- cloud_options['properties']['openstack']['boot_from_volume'] = true
- cloud_options['properties']
- end
-
- it 'creates an OpenStack server with a boot volume' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, dynamic_network, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(openstack_params(dynamic_network, true))
- end
- end
-
- context 'for vm type' do
- let(:resource_pool_spec_with_boot_from_volume) { resource_pool_spec.merge('boot_from_volume' => true) }
- let(:options) do
- cloud_options = mock_cloud_options
- cloud_options['properties']['openstack']['boot_from_volume'] = false
- cloud_options['properties']
- end
-
- it 'creates an OpenStack server with a boot volume' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec_with_boot_from_volume, dynamic_network, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(openstack_params(dynamic_network, true))
- end
- end
-
- context 'and a volume_type as well' do
- let(:options) do
- cloud_options = mock_cloud_options
- cloud_options['properties']['openstack']['boot_from_volume'] = true
- cloud_options['properties']['openstack']['boot_volume_cloud_properties'] = { 'type' => 'foo' }
- cloud_options['properties']
- end
-
- it 'creates an OpenStack server with a boot volume' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, dynamic_network, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(openstack_params(dynamic_network, true))
- end
- end
- end
-
- context 'when config_drive option is set' do
- let(:options) do
- cloud_options = mock_cloud_options
- cloud_options['properties']['openstack']['config_drive'] = 'cdrom'
- cloud_options['properties']
- end
-
- it 'creates an OpenStack server with config drive' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(openstack_params.merge(config_drive: true))
- end
- end
-
- context 'when OpenStack cannot create the server' do
- before do
- allow(server).to receive(:destroy)
- end
-
- context 'when OpenStack raises a Timeout error' do
- let(:socket_error) { Excon::Error::Timeout.new('read timeout reached') }
-
- it 'raises a Cloud error with vm information' do
- allow(cloud.compute.servers).to receive(:create).and_raise(socket_error)
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- }.to raise_error(Bosh::Clouds::VMCreationFailed, /'vm-#{unique_name}'.*?\nOriginal message: read timeout reached/)
- end
- end
-
- context 'when OpenStack raises a Not Found error' do
- let(:networks) { double('networks') }
- let(:not_found_error) { Excon::Error::NotFound.new('not found: 814bc266-c6de-4fd0-a713-502da09edbe9') }
-
- before(:each) do
- allow(cloud.compute.servers).to receive(:create).and_raise(not_found_error)
- allow(cloud.network).to receive(:networks).and_return(networks)
- end
-
- it 'raises a VMCreationFailed error with subnet ID' do
- allow(networks).to receive(:get).and_return(nil)
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_with_netid_spec }, nil, environment)
- }.to raise_error(Bosh::Clouds::VMCreationFailed, /'vm-#{unique_name}'.*?'net'/)
- end
-
- it 'raises a Not Found error with existing Net IDs' do
- allow_any_instance_of(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:prepare)
- allow_any_instance_of(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:cleanup)
- allow(networks).to receive(:get).and_return('some_network')
- network_with_different_net_id = { 'network_b' => manual_network_spec(net_id: 'some_other_id') }
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_with_different_net_id, nil, environment)
- }.to raise_error(Excon::Error::NotFound, 'not found: 814bc266-c6de-4fd0-a713-502da09edbe9')
- end
-
- context 'when `openstack.network.networks.get` raises' do
- before(:each) do
- allow(networks).to receive(:get).and_raise('BOOM!!!')
- end
-
- it 'raises the original error' do
- allow_any_instance_of(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:prepare)
- allow_any_instance_of(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:cleanup)
- network_with_different_net_id = { 'network_b' => manual_network_spec(net_id: 'some_other_id') }
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_with_different_net_id, nil, environment)
- }.to raise_error(Excon::Error::NotFound, 'not found: 814bc266-c6de-4fd0-a713-502da09edbe9')
- end
- end
-
- context 'when `use_nova_networking=true`' do
- let(:options) {
- mocked_options = mock_cloud_options(3)
- mocked_options['properties']['openstack']['use_nova_networking'] = true
- mocked_options['properties']
- }
-
- before(:each) do
- allow(cloud.compute.servers).to receive(:create).and_raise(not_found_error)
- security_groups = [double('default_sec_group', id: 'default_sec_group_id', name: 'default')]
- mock_sec_groups(cloud.compute, security_groups)
- end
-
- it 'raises a Not Found error with Network service not available' do
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_with_netid_spec }, nil, environment)
- }.to raise_error(Excon::Error::NotFound)
-
- expect(cloud.network).to_not have_received(:networks)
- end
- end
- end
-
- context 'when OpenStack raises a BadRequest error' do
- let(:networks) { double('networks') }
- let(:bad_request_error) { Excon::Error::BadRequest.new('Message does not matter here') }
-
- before(:each) do
- allow(cloud.compute.servers).to receive(:create).and_raise(bad_request_error)
- allow(cloud.network).to receive(:networks).and_return(networks)
- end
-
- it 'raises a VMCreationFailed error with subnet ID' do
- allow(networks).to receive(:get).and_return(nil)
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_with_netid_spec }, nil, environment)
- }.to raise_error(Bosh::Clouds::VMCreationFailed, /'vm-#{unique_name}'.*?'net'/)
- end
- end
-
- context 'with a CloudError' do
- it 'destroys the server successfully' do
- allow(cloud.openstack).to receive(:wait_resource).with(server, :active, :state).and_raise(Bosh::Clouds::CloudError)
- expect(cloud.openstack).to receive(:wait_resource).with(server, %i[terminated deleted], :state, true)
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- }.to raise_error(Bosh::Clouds::VMCreationFailed)
- end
- end
-
- context 'with a StandardError' do
- it 'destroys the server successfully' do
- allow(cloud.openstack).to receive(:wait_resource).with(server, :active, :state).and_raise(StandardError)
- expect(cloud.openstack).to receive(:wait_resource).with(server, %i[terminated deleted], :state, true)
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- }.to raise_error(Bosh::Clouds::VMCreationFailed)
- end
- end
-
- it 'raises a VMCreationFailed error and logs correct failure message when failed to destroy the server' do
- allow(server).to receive(:destroy)
- allow(cloud.openstack).to receive(:wait_resource).with(server, :active, :state).and_raise(Bosh::Clouds::CloudError)
- allow(cloud.openstack).to receive(:wait_resource).with(server, %i[terminated deleted], :state, true).and_raise(Bosh::Clouds::CloudError)
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- }.to raise_error(Bosh::Clouds::VMCreationFailed)
-
- expect(Bosh::Clouds::Config.logger).to have_received(:warn).with('Failed to create server: Bosh::Clouds::CloudError')
- expect(Bosh::Clouds::Config.logger).to have_received(:warn).with(/Failed to destroy server:.*/)
- end
- end
-
- context 'when fail to register an OpenStack server after the server is created' do
- before(:each) { allow(server).to receive(:destroy) }
-
- it 'destroys the server successfully and raises a non-retryable Error when CloudError happens' do
- allow(@registry).to receive(:update_settings).and_raise(Bosh::Clouds::CloudError)
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- }.to(raise_error { |error|
- expect(error).to be_a(Bosh::Clouds::VMCreationFailed)
- expect(error.ok_to_retry).to eq(false)
- })
- expect(cloud.openstack).to have_received(:wait_resource).with(server, %i[terminated deleted], :state, true)
- end
-
- it 'destroys the server successfully and raises a non-retryable Error when StandardError happens' do
- allow(@registry).to receive(:update_settings).and_raise(StandardError)
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- }.to(raise_error { |error|
- expect(error).to be_a(Bosh::Clouds::VMCreationFailed)
- expect(error.ok_to_retry).to eq(false)
- })
- expect(cloud.openstack).to have_received(:wait_resource).with(server, %i[terminated deleted], :state, true)
- end
-
- it 'logs correct failure message when failed to destroy the server' do
- allow(@registry).to receive(:update_settings).and_raise(Bosh::Clouds::CloudError)
- allow(cloud.openstack).to receive(:wait_resource).with(server, %i[terminated deleted], :state, true).and_raise(Bosh::Clouds::CloudError)
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- }.to raise_error(Bosh::Clouds::VMCreationFailed)
- expect(Bosh::Clouds::Config.logger).to have_received(:warn).with('Failed to register server: Bosh::Clouds::CloudError')
- expect(Bosh::Clouds::Config.logger).to have_received(:warn).with(/Failed to destroy server:.*/)
- end
- end
-
- context "when security group doesn't exist" do
- let(:openstack_security_groups) { [double('foo-sec-group', id: 'foo-sec-group-id', name: 'foo')] }
-
- it 'raises an error' do
- mock_sec_groups(cloud.network, openstack_security_groups)
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- }.to raise_error(Bosh::Clouds::CloudError, "Security group `default' not found")
- end
- end
-
- it "raises an error when flavor doesn't have enough ephemeral disk capacity" do
- flavor = double('flavor', id: 'f-test', name: 'm1.tiny', ram: 1024, ephemeral: 1)
- allow(cloud.compute.flavors).to receive(:find).and_return(flavor)
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- }.to raise_error(Bosh::Clouds::CloudError, "Flavor `m1.tiny' should have at least 2Gb of ephemeral disk")
- end
-
- context 'when use_dhcp is set to false' do
- let(:options) do
- cloud_options = mock_cloud_options
- cloud_options['properties']['openstack']['use_dhcp'] = false
- cloud_options['properties']
- end
-
- it 'updates network settings to include use_dhcp as false' do
- expected_network_spec = dynamic_network_spec
- expected_network_spec['use_dhcp'] = false
- expected_openstack_params = openstack_params('network_a' => expected_network_spec)
-
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- expect(cloud.compute.servers).to have_received(:create).with(expected_openstack_params)
- end
- end
-
- describe 'key_name configuration' do
- let(:resource_pool_spec_no_key) do
- {
- 'availability_zone' => 'foobar-1a',
- 'instance_type' => 'm1.tiny',
- }
- end
-
- context 'when key_name is only defined in resource pool' do
- it 'takes the key_name from resource pool' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(openstack_params)
- end
- end
-
- context 'when default_key_name is only defined in CPI cloud properties' do
- let(:options) do
- cloud_options_with_default_key_name = mock_cloud_options['properties']
- cloud_options_with_default_key_name['openstack']['default_key_name'] = 'default_key_name'
- cloud_options_with_default_key_name
- end
-
- before(:each) do
- allow(cloud).to receive(:validate_key_exists)
- end
-
- it 'takes the key_name from CPI cloud properties' do
- expected_openstack_params = openstack_params
- expected_openstack_params[:key_name] = 'default_key_name'
-
- expect_any_instance_of(Bosh::OpenStackCloud::VmFactory).to receive(:validate_key_exists).with(options['openstack']['default_key_name'])
-
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec_no_key, { 'network_a' => dynamic_network_spec }, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(expected_openstack_params)
- end
- end
-
- context 'when default_key_name is defined in CPI cloud properties and key_name in resource pool' do
- let(:options) do
- cloud_options_with_default_key_name = mock_cloud_options['properties']
- cloud_options_with_default_key_name['openstack']['default_key_name'] = 'default_key_name'
- cloud_options_with_default_key_name
- end
-
- before(:each) do
- allow(cloud).to receive(:validate_key_exists)
- end
-
- it 'takes the key_name from resource pool' do
- expect_any_instance_of(Bosh::OpenStackCloud::VmFactory).to receive(:validate_key_exists).with('test_key')
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- end
- end
-
- context 'when no key_name is defined' do
- it 'raises cloud error' do
- allow(cloud.compute).to receive(:key_pairs).and_return([key_pair])
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec_no_key, { 'network_a' => dynamic_network_spec }, nil, environment)
- }.to raise_error(Bosh::Clouds::CloudError, "Key-pair `' not found")
- end
- end
- end
-
- describe 'use "vm-" as registry key' do
- context 'when "human_readable_vm_names" is enabled' do
- let(:options) do
- options = mock_cloud_options['properties']
- options['openstack']['human_readable_vm_names'] = true
- options
- end
-
- it 'logs human_readable_vm_names enabled' do
- # Bosh.retryable requires us to return a non-nil value from debug
- allow(Bosh::Clouds::Config.logger).to receive(:debug).and_return('logged')
-
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
-
- expect(Bosh::Clouds::Config.logger).to have_received(:debug).with("'human_readable_vm_names' enabled")
- expect(Bosh::Clouds::Config.logger).to have_received(:debug).with("Tagged VM 'i-test' with tags '{registry_key: \"vm-#{unique_name}\"}")
- end
- end
-
- context 'when "human_readable_vm_names" is disabled' do
- let(:options) do
- mock_cloud_options['properties']
- end
-
- it 'does not tag server with registry tag' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
-
- expect(Bosh::OpenStackCloud::TagManager).to_not have_received(:tag_server).with(server, registry_key: "vm-#{unique_name}")
- end
-
- it 'logs human_readable_vm_names disabled' do
- # Bosh.retryable requires us to return a non-nil value from debug
- allow(Bosh::Clouds::Config.logger).to receive(:debug).and_return('logged')
-
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
-
- expect(Bosh::Clouds::Config.logger).to have_received(:debug).with("'human_readable_vm_names' disabled")
- end
- end
- end
-
- describe 'with light stemcell' do
- it 'creates the vm with the image id of the heavy stemcell' do
- cloud.create_vm('agent-id', 'sc-id light', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(openstack_params)
- expect(@registry).to have_received(:update_settings).with("vm-#{unique_name}", agent_settings(unique_name))
- end
- end
-
- describe 'with loadbalancer pool' do
- let(:resource_pool_spec_with_lbaas_pools) do
- resource_pool_spec.merge(
- 'loadbalancer_pools' => [
- { 'name' => 'my-pool-1', 'port' => 443 },
- { 'name' => 'my-pool-2', 'port' => 8080 },
- ],
- )
- end
-
- it 'creates as many loadbalancers as are listed in the manifest' do
- network_spec = { 'network_a' => dynamic_network_spec }
- pool_membership = Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadbalancerPoolMembership.new('name', 'port', 'pool_id', 'membership_id')
-
- expect_any_instance_of(Bosh::OpenStackCloud::LoadbalancerConfigurator)
- .to receive(:add_vm_to_pool)
- .with(server, network_spec, 'name' => 'my-pool-1', 'port' => 443)
- .and_return(pool_membership)
- expect_any_instance_of(Bosh::OpenStackCloud::LoadbalancerConfigurator)
- .to receive(:add_vm_to_pool)
- .with(server, network_spec, 'name' => 'my-pool-2', 'port' => 8080)
- .and_return(pool_membership)
-
- cloud.create_vm('agent-id', 'sc-id light', resource_pool_spec_with_lbaas_pools, network_spec, nil, environment)
- end
- end
-
- describe 'setting VM metadata' do
- context 'when human_readable_vm_names are enabled' do
- let(:options) do
- options = mock_cloud_options['properties']
- options['openstack']['human_readable_vm_names'] = true
- options
- end
-
- it 'tags registry_key with "vm-"' do
- allow(Bosh::OpenStackCloud::TagManager).to receive(:tag_server)
-
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
-
- expect(Bosh::OpenStackCloud::TagManager).to have_received(:tag_server).with(server, registry_key: "vm-#{unique_name}")
- end
-
- it 'raises an exception, if tagging fails' do
- allow(Bosh::OpenStackCloud::TagManager).to receive(:tag_server).and_raise(StandardError)
-
- expect(server).to receive(:destroy)
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- }.to raise_error(Bosh::Clouds::CloudError)
- end
- end
-
- context 'when loadbalancer_pools are present' do
- let(:resource_pool_spec_with_lbaas_pools) do
- resource_pool_spec.merge(
- 'loadbalancer_pools' => [
- { 'name' => 'my-pool-1', 'port' => 443 },
- { 'name' => 'my-pool-2', 'port' => 8080 },
- ],
- )
- end
-
- let(:loadbalancer_configurator) { instance_double(Bosh::OpenStackCloud::LoadbalancerConfigurator) }
-
- before(:each) do
- allow(Bosh::OpenStackCloud::LoadbalancerConfigurator).to receive(:new).and_return(loadbalancer_configurator)
- allow(loadbalancer_configurator).to receive(:create_pool_memberships).and_return(
- 'lbaas_pool_1' => 'pool_id/membership_id',
- 'lbaas_pool_2' => 'pool_id/membership_id',
- )
- allow(Bosh::OpenStackCloud::TagManager).to receive(:tag_server)
- end
-
- it 'tags the vm with the lbaas pool and membership' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec_with_lbaas_pools, { 'network_a' => dynamic_network_spec }, nil, environment)
-
- expect(Bosh::OpenStackCloud::TagManager).to have_received(:tag_server).with(server,
- 'lbaas_pool_1' => 'pool_id/membership_id',
- 'lbaas_pool_2' => 'pool_id/membership_id')
- end
-
- context 'when tagging fails' do
- it 'cleans up the membership and raises an exception' do
- allow(Bosh::OpenStackCloud::TagManager).to receive(:tag_server).and_raise(StandardError)
- allow(loadbalancer_configurator).to receive(:cleanup_memberships)
- allow(server).to receive(:destroy)
-
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec_with_lbaas_pools, { 'network_a' => dynamic_network_spec }, nil, environment)
- }.to raise_error(Bosh::Clouds::CloudError)
- expect(server).to have_received(:destroy)
- expect(loadbalancer_configurator).to have_received(:cleanup_memberships).with(
- 'lbaas_pool_1' => 'pool_id/membership_id',
- 'lbaas_pool_2' => 'pool_id/membership_id',
- )
- end
- end
- end
- end
-
- describe 'when multiple azs are configured' do
- let(:options) do
- options = mock_cloud_options['properties']
- options['openstack']['ignore_server_availability_zone'] = true
- options
- end
-
- let(:azs) { ['az-1', 'az-2'] }
- let(:resource_pool_spec) do
- {
- 'key_name' => 'test_key',
- 'availability_zones' => azs,
- 'instance_type' => 'm1.tiny',
- }
- end
-
- context 'dynamic network' do
- it 'creates the vm in one of the configured azs' do
- expect(cloud.compute.servers).to receive(:create).with(
- include(availability_zone: 'az-1').or(include(availability_zone: 'az-2')),
- )
-
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- end
-
- it 'iterates over the azs till it can create a vm in one of the configured azs' do
- allow_any_instance_of(Bosh::OpenStackCloud::AvailabilityZoneProvider).to receive(:select_azs).and_return(azs)
- allow(cloud.compute.servers)
- .to receive(:create)
- .with(include(availability_zone: 'az-1'))
- .and_raise Bosh::Clouds::CloudError.new('Example exception from infrastructure')
-
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(include(availability_zone: 'az-1'))
- expect(cloud.compute.servers).to have_received(:create).with(include(availability_zone: 'az-2'))
- end
-
- context 'last try fails' do
- let(:err) { Bosh::Clouds::CloudError.new('Example exception from infrastructure') }
- before { allow(cloud.compute.servers).to receive(:create).and_raise err }
-
- it 'raises an error if last try fails' do
- expect {
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, { 'network_a' => dynamic_network_spec }, nil, environment)
- }.to raise_error(Bosh::Clouds::CloudError)
- expect(cloud.compute.servers).to have_received(:create).with(include(availability_zone: 'az-1'))
- expect(cloud.compute.servers).to have_received(:create).with(include(availability_zone: 'az-2'))
- end
- end
- end
- end
-
- describe 'requests cpi api' do
- let(:expected_user_data) do
- Regexp.new('\"networks\":{\"network_a\":{\"type\":\"dynamic\",\"cloud_properties\":' \
- '{\"security_groups\":\[\"default\"\]},\"use_dhcp\":true}}')
- end
-
- context 'with cpi api version 1' do
- it 'sets networks in user data' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(hash_including(user_data: expected_user_data))
- end
-
- it 'logs that settings get updated' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.logger).to have_received(:info).with(/Updating settings/)
- end
-
- context 'when stemcell API v1' do
- it 'does not set agent_id in user data' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create)
- expect(cloud.compute.servers).not_to have_received(:create).with(hash_including(user_data: /\"agent_id\":/))
- end
-
- it 'does not set env in user data' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create)
- expect(cloud.compute.servers).not_to have_received(:create).with(hash_including(user_data: /\"env\":/))
- end
- end
-
- context 'when stemcell API v2' do
- let(:options) do
- options = mock_cloud_options['properties']
- options['openstack']['vm'] = {
- 'stemcell' => {
- 'api_version' => 2,
- },
- }
- options
- end
-
- it 'does not set agent_id in user data' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).not_to have_received(:create).with(hash_including(user_data: /\"agent_id\":/))
- end
-
- it 'does not set env in user data' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).not_to have_received(:create).with(hash_including(user_data: /\"env\":/))
- end
-
- it 'sets networks in user data' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(hash_including(user_data: expected_user_data))
- end
- end
- end
-
- context 'with cpi api version 2' do
- let(:cpi_api_version) { 2 }
-
- it 'sets networks in user data' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(hash_including(user_data: expected_user_data))
- end
-
- it 'returns instance_id and network configuration' do
- res = cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
- expect(res).to be_a(Array)
- expect(res[0]).to eq('i-test')
- expect(res[1]).to eq(network_configuration)
- end
-
- context 'when stemcell API v1' do
- it 'does not set agent settings in user data' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).not_to have_received(:create).with(hash_including(user_data: /\"foo\":/))
- end
-
- it 'does not set agent_id in user data' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create)
- expect(cloud.compute.servers).not_to have_received(:create).with(hash_including(user_data: /\"agent_id\":/))
- end
-
- it 'does not set env in user data' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create)
- expect(cloud.compute.servers).not_to have_received(:create).with(hash_including(user_data: /\"env\":/))
- end
-
- it 'does set registry' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(hash_including(user_data: /\"registry\":/))
- end
- end
-
- context 'when stemcell API v2' do
- let(:options) do
- options = mock_cloud_options['properties']
- options['openstack']['vm'] = {
- 'stemcell' => {
- 'api_version' => 2,
- },
- }
- options
- end
-
- it 'sets agent settings in user data' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(hash_including(user_data: /\"foo\":\"bar\"/))
- end
-
- it 'sets agent_id in user data' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(hash_including(user_data: /\"agent_id\":\"agent-id\"/))
- end
-
- it 'sets env in user data' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).to have_received(:create).with(
- hash_including(user_data: /\"env\":{\"test_env\":\"value\"}/),
- )
- end
-
- it 'does not set registry' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.compute.servers).not_to have_received(:create).with(hash_including(user_data: /\"registry\":/))
- end
-
- it 'does not log that settings get updated' do
- cloud.create_vm('agent-id', 'sc-id', resource_pool_spec, network_configuration, nil, environment)
-
- expect(cloud.logger).not_to have_received(:info).with(/Updating settings/)
- end
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/delete_disk_spec.rb b/src/bosh_openstack_cpi/spec/unit/delete_disk_spec.rb
deleted file mode 100644
index 62248d675..000000000
--- a/src/bosh_openstack_cpi/spec/unit/delete_disk_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- it 'deletes an OpenStack volume' do
- volume = double('volume', id: 'v-foobar')
-
- cloud = mock_cloud do |fog|
- expect(fog.volume.volumes).to receive(:get)
- .with('v-foobar').and_return(volume)
- end
-
- expect(volume).to receive(:status).and_return(:available)
- expect(volume).to receive(:destroy).and_return(true)
- expect(cloud.openstack).to receive(:wait_resource).with(volume, :deleted, :status, true)
-
- cloud.delete_disk('v-foobar')
- end
-
- it "doesn't delete an OpenStack volume unless it's state is `available'" do
- volume = double('volume', id: 'v-foobar')
-
- cloud = mock_cloud do |fog|
- expect(fog.volume.volumes).to receive(:get).with('v-foobar').and_return(volume)
- end
-
- expect(volume).to receive(:status).and_return(:busy)
-
- expect {
- cloud.delete_disk('v-foobar')
- }.to raise_error(Bosh::Clouds::CloudError,
- "Cannot delete volume `v-foobar', state is busy")
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/delete_snapshot_spec.rb b/src/bosh_openstack_cpi/spec/unit/delete_snapshot_spec.rb
deleted file mode 100644
index 3a6bad49d..000000000
--- a/src/bosh_openstack_cpi/spec/unit/delete_snapshot_spec.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- it 'deletes an OpenStack snapshot' do
- snapshot = double('snapshot', id: 'snap-foobar')
-
- cloud = mock_cloud do |fog|
- expect(fog.volume.snapshots).to receive(:get).with('snap-foobar').and_return(snapshot)
- end
-
- expect(snapshot).to receive(:status).and_return(:available)
- expect(snapshot).to receive(:destroy).and_return(true)
- expect(cloud.openstack).to receive(:wait_resource).with(snapshot, :deleted, :status, true)
-
- cloud.delete_snapshot('snap-foobar')
- end
-
- it "doesn't delete an OpenStack snapshot unless its state is `available'" do
- snapshot = double('snapshot', id: 'snap-foobar')
-
- cloud = mock_cloud do |fog|
- expect(fog.volume.snapshots).to receive(:get).with('snap-foobar').and_return(snapshot)
- end
-
- expect(snapshot).to receive(:status).and_return(:busy)
-
- expect {
- cloud.delete_snapshot('snap-foobar')
- }.to raise_error(Bosh::Clouds::CloudError, "Cannot delete snapshot `snap-foobar', state is busy")
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/delete_stemcell_spec.rb b/src/bosh_openstack_cpi/spec/unit/delete_stemcell_spec.rb
deleted file mode 100644
index f901219b6..000000000
--- a/src/bosh_openstack_cpi/spec/unit/delete_stemcell_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- it 'deletes stemcell' do
- image = double('image', id: 'i-foo', name: 'i-foo', properties: {})
-
- cloud = mock_glance do |glance|
- allow(glance.images).to receive(:find_by_id).with('i-foo').and_return(image)
- end
-
- expect(image).to receive(:destroy)
-
- cloud.delete_stemcell('i-foo')
- end
-
- describe 'with light stemcell' do
- it 'does no operation' do
- image = double('image', id: 'i-foo', name: 'i-foo', properties: {})
-
- cloud = mock_glance do |glance|
- allow(glance.images).to receive(:find_by_id).with('i-foo').and_return(image)
- end
-
- expect(image).not_to receive(:destroy)
-
- cloud.delete_stemcell('i-foo light')
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/delete_vm_spec.rb b/src/bosh_openstack_cpi/spec/unit/delete_vm_spec.rb
deleted file mode 100644
index bf2ef650c..000000000
--- a/src/bosh_openstack_cpi/spec/unit/delete_vm_spec.rb
+++ /dev/null
@@ -1,211 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- let(:registry_key) { 'vm-registry-key' }
-
- let(:server_metadata) do
- [
- double('metadatum', key: 'lbaas_pool_0', value: 'pool-id-0/membership-id-0'),
- double('metadatum', key: 'job', value: 'bosh'),
- double('metadatum', key: 'registry_key', value: registry_key),
- ]
- end
-
- let(:server) { double('server', id: 'i-foobar', name: 'i-foobar', metadata: server_metadata) }
- let(:cloud) do
- mock_cloud do |fog|
- allow(fog.compute.servers).to receive(:get).with('i-foobar').and_return(server)
- end
- end
-
- let(:loadbalancer_configurator) { instance_double(Bosh::OpenStackCloud::LoadbalancerConfigurator) }
-
- before(:each) do
- @registry = mock_registry
- Bosh::Clouds::Config.configure(double('config', uuid: 'director-uuid'))
-
- allow(Bosh::Clouds::Config).to receive(:uuid).and_return('fake-uuid')
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:port_ids).and_return(['port_id'])
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:cleanup_ports)
- allow(server).to receive(:destroy)
- allow(cloud.openstack).to receive(:wait_resource)
- allow(@registry).to receive(:delete_settings)
- allow(Bosh::OpenStackCloud::LoadbalancerConfigurator).to receive(:new).and_return(loadbalancer_configurator)
- allow(loadbalancer_configurator).to receive(:cleanup_memberships)
- end
-
- context 'when server retrieval fails' do
- let(:cloud) do
- mock_cloud do |fog|
- allow(fog.compute.servers).to receive(:get).with('i-foobar').and_raise('BOOM!')
- end
- end
-
- it 'stops and raises' do
- expect {
- cloud.delete_vm('i-foobar')
- }.to raise_error('BOOM!')
- end
- end
-
- context 'when server cannot be found' do
- let(:cloud) do
- mock_cloud do |fog|
- allow(fog.compute.servers).to receive(:get).with('i-foobar').and_return(nil)
- end
- end
-
- before(:each) do
- allow(Bosh::Clouds::Config.logger).to receive(:info)
- end
-
- it 'stops and logs' do
- cloud.delete_vm('i-foobar')
-
- expect(Bosh::Clouds::Config.logger).to have_received(:info).with('Server `i-foobar\' not found. Skipping.')
- end
- end
-
- it 'deletes an OpenStack server after removing the lbaas pool membership' do
- cloud.delete_vm('i-foobar')
-
- expect(loadbalancer_configurator).to have_received(:cleanup_memberships).with(
- 'lbaas_pool_0' => 'pool-id-0/membership-id-0',
- 'job' => 'bosh',
- 'registry_key' => 'vm-registry-key',
- ).ordered
- expect(server).to have_received(:destroy).ordered
- expect(cloud.openstack).to have_received(:wait_resource).with(server, %i[terminated deleted], :state, true).ordered
- expect(Bosh::OpenStackCloud::NetworkConfigurator).to have_received(:cleanup_ports).with(any_args, ['port_id']).ordered
- expect(cloud.logger).to have_received(:info).with(/Deleting settings/)
- expect(@registry).to have_received(:delete_settings).with(registry_key)
- end
-
- context 'when registry-less' do
- let(:cpi_api_version) { 2 }
- let(:cloud_options) { mock_cloud_options }
- let(:cloud_options_stemcell_v2) do
- cloud_options['properties']['openstack']['vm'] = {
- 'stemcell' => {
- 'api_version' => 2,
- },
- }
- cloud_options
- end
- let(:cloud) do
- mock_cloud(cloud_options_stemcell_v2['properties'], cpi_api_version) do |fog|
- allow(fog.compute.servers).to receive(:get).with('i-foobar').and_return(server)
- end
- end
-
- it 'does not log deleting settings' do
- expect(cloud.logger).to_not receive(:info).with(/Deleting settings/)
- expect(cloud.registry).to receive(:delete_settings).with(registry_key)
-
- cloud.delete_vm('i-foobar')
- end
- end
-
- context 'when server destroy fails' do
- it 'stops and raises' do
- allow(server).to receive(:destroy).and_raise('BOOM!')
-
- expect {
- cloud.delete_vm('i-foobar')
- }.to raise_error('BOOM!')
- end
- end
-
- context 'when getting ports fails' do
- it 'stops and raises' do
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:port_ids).and_raise('BOOM!')
-
- expect {
- cloud.delete_vm('i-foobar')
- }.to raise_error('BOOM!')
- end
- end
-
- context 'when port cleanup fails' do
- it 'does everything else but fails in the end' do
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:cleanup_ports).and_raise('BOOM!')
-
- expect {
- cloud.delete_vm('i-foobar')
- }.to raise_error(/BOOM!/)
-
- expect(@registry).to have_received(:delete_settings).with(registry_key)
- expect(loadbalancer_configurator).to have_received(:cleanup_memberships).with(
- 'lbaas_pool_0' => 'pool-id-0/membership-id-0',
- 'job' => 'bosh',
- 'registry_key' => 'vm-registry-key',
- )
- end
- end
-
- context 'when destruction of LBaaS membership fails' do
- it 'does everything else and fails' do
- allow(loadbalancer_configurator).to receive(:cleanup_memberships).and_raise('BOOM!')
-
- expect {
- cloud.delete_vm('i-foobar')
- }.to raise_error(/BOOM!/)
-
- expect(Bosh::OpenStackCloud::NetworkConfigurator).to have_received(:cleanup_ports).with(any_args, ['port_id'])
- expect(@registry).to have_received(:delete_settings).with(registry_key)
- end
- end
-
- context 'when port cleanup and LBaaS membership cleanup fails' do
- it 'fails with both errors, but deletes the registry settings' do
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:cleanup_ports).and_raise('BOOM!')
- allow(loadbalancer_configurator).to receive(:cleanup_memberships).and_raise('BOOM!')
-
- expect {
- cloud.delete_vm('i-foobar')
- }.to raise_error(Bosh::Clouds::CloudError)
-
- expect(Bosh::OpenStackCloud::NetworkConfigurator).to have_received(:cleanup_ports).with(any_args, ['port_id'])
- expect(loadbalancer_configurator).to have_received(:cleanup_memberships).with(
- 'lbaas_pool_0' => 'pool-id-0/membership-id-0',
- 'job' => 'bosh',
- 'registry_key' => 'vm-registry-key',
- )
- expect(@registry).to have_received(:delete_settings).with(registry_key)
- end
- end
-
- context 'when port cleanup, LBaaS membership cleanup and deleting settings from registry fails' do
- it 'fails with all errors and an aggregated error message containing the right prefixes' do
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:cleanup_ports).and_raise('BOOM1!')
- allow(loadbalancer_configurator).to receive(:cleanup_memberships).and_raise('BOOM2!')
- allow(@registry).to receive(:delete_settings).and_raise('BOOM3!')
-
- expected_error_msg = <<~EOF
- Multiple cloud errors occurred:
- Removing ports: BOOM1!
- Removing lbaas pool memberships: BOOM2!
- Deleting registry settings: BOOM3!
- EOF
-
- expect {
- cloud.delete_vm('i-foobar')
- }.to raise_error(Bosh::Clouds::CloudError, expected_error_msg.chomp)
- end
- end
-
- context 'when server is not tagged with `registry_key`' do
- let(:server_metadata) do
- [
- double('metadatum', key: 'lbaas_pool_0', value: 'pool-id-0/membership-id-0'),
- double('metadatum', key: 'job', value: 'bosh'),
- ]
- end
-
- it 'uses the server name to delete registry settings' do
- cloud.delete_vm('i-foobar')
-
- expect(@registry).to have_received(:delete_settings).with(server.name)
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/detach_disk_spec.rb b/src/bosh_openstack_cpi/spec/unit/detach_disk_spec.rb
deleted file mode 100644
index 81d32cdb0..000000000
--- a/src/bosh_openstack_cpi/spec/unit/detach_disk_spec.rb
+++ /dev/null
@@ -1,118 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- let(:server) { double('server', id: 'i-test', name: 'i-test', metadata: double('metadata')) }
-
- before(:each) do
- allow(server.metadata).to receive(:get).with(:registry_key).and_return(double('metadatum', 'value' => 'i-test'))
- @registry = mock_registry
- end
-
- it 'detaches an OpenStack volume from a server' do
- volume = double('volume', id: 'v-foobar')
- volume_attachments = [{ 'id' => 'a1', 'volumeId' => 'v-foobar' }, { 'id' => 'a2', 'volumeId' => 'v-barfoo' }]
-
- cloud = mock_cloud do |fog|
- expect(fog.compute.servers).to receive(:get).with('i-test').and_return(server)
- expect(fog.volume.volumes).to receive(:get).with('v-foobar').and_return(volume)
- end
-
- expect(server).to receive(:volume_attachments).and_return(volume_attachments)
- expect(server).to receive(:detach_volume).with(volume.id).and_return(true)
- expect(cloud.openstack).to receive(:wait_resource).with(volume, :available)
-
- old_settings = {
- 'foo' => 'bar',
- 'disks' => {
- 'persistent' => {
- 'v-foobar' => '/dev/vdc',
- 'v-barfoo' => '/dev/vdd',
- },
- },
- }
-
- new_settings = {
- 'foo' => 'bar',
- 'disks' => {
- 'persistent' => {
- 'v-barfoo' => '/dev/vdd',
- },
- },
- }
-
- expect(@registry).to receive(:read_settings).with('i-test').and_return(old_settings)
- expect(@registry).to receive(:update_settings).with('i-test', new_settings)
-
- cloud.detach_disk('i-test', 'v-foobar')
- end
-
- it 'bypasses the detaching process when volume is not attached to a server' do
- volume = double('volume', id: 'v-barfoo')
- volume_attachments = [{ 'volumeId' => 'v-foobar' }]
-
- cloud = mock_cloud do |fog|
- expect(fog.compute.servers).to receive(:get).with('i-test').and_return(server)
- expect(fog.volume.volumes).to receive(:get).with('v-barfoo').and_return(volume)
- end
-
- expect(server).to receive(:volume_attachments).and_return(volume_attachments)
- expect(volume).not_to receive(:detach)
-
- old_settings = {
- 'foo' => 'bar',
- 'disks' => {
- 'persistent' => {
- 'v-foobar' => '/dev/vdc',
- 'v-barfoo' => '/dev/vdd',
- },
- },
- }
-
- new_settings = {
- 'foo' => 'bar',
- 'disks' => {
- 'persistent' => {
- 'v-foobar' => '/dev/vdc',
- },
- },
- }
-
- expect(@registry).to receive(:read_settings).with('i-test').and_return(old_settings)
- expect(@registry).to receive(:update_settings).with('i-test', new_settings)
-
- cloud.detach_disk('i-test', 'v-barfoo')
- end
-
- it 'bypasses the detaching process when volume is missing' do
- cloud = mock_cloud do |fog|
- allow(fog.compute.servers).to receive(:get).with('i-test').and_return(server)
- allow(fog.volume.volumes).to receive(:get).with('non-exist-volume-id').and_return(nil)
- end
-
- old_settings = {
- 'foo' => 'bar',
- 'disks' => {
- 'persistent' => {
- 'non-exist-volume-id' => '/dev/vdc',
- 'exist-volume-id' => '/dev/vdd',
- },
- },
- }
-
- new_settings = {
- 'foo' => 'bar',
- 'disks' => {
- 'persistent' => {
- 'exist-volume-id' => '/dev/vdd',
- },
- },
- }
-
- expect(@registry).to receive(:read_settings).with('i-test').and_return(old_settings)
- expect(@registry).to receive(:update_settings).with('i-test', new_settings)
-
- expect {
- cloud.detach_disk('i-test', 'non-exist-volume-id')
- }.to_not raise_error
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/dynamic_network_spec.rb b/src/bosh_openstack_cpi/spec/unit/dynamic_network_spec.rb
deleted file mode 100644
index 8d454409c..000000000
--- a/src/bosh_openstack_cpi/spec/unit/dynamic_network_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::DynamicNetwork do
- subject { Bosh::OpenStackCloud::DynamicNetwork.new('default', dynamic_network_with_netid_spec) }
-
- context 'allowed_address_pair is configured' do
- it 'raises an error' do
- allowed_address_pairs = '10.0.0.10'
- subject.allowed_address_pairs = allowed_address_pairs
-
- expect {
- subject.prepare(nil, [])
- }.to raise_error Bosh::Clouds::CloudError, "Network with id '#{subject.net_id}' is a dynamic network. VRRP is not supported for dynamic networks"
- end
- end
-
- context 'allowed_address_pair is not configured' do
- it 'does not raise an error' do
- expect {
- subject.prepare(nil, [])
- }.to_not raise_error
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/excon_logging_instrumentor_spec.rb b/src/bosh_openstack_cpi/spec/unit/excon_logging_instrumentor_spec.rb
deleted file mode 100644
index b90e50c68..000000000
--- a/src/bosh_openstack_cpi/spec/unit/excon_logging_instrumentor_spec.rb
+++ /dev/null
@@ -1,273 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::ExconLoggingInstrumentor do
- describe '.instrument' do
- let(:name) { 'foo' }
- let(:params) { { foo: 'bar' } }
- let(:logger) { instance_double('Logger') }
-
- subject { Bosh::OpenStackCloud::ExconLoggingInstrumentor }
-
- before do
- allow(Bosh::Clouds::Config).to receive(:logger).and_return(logger)
- allow(logger).to receive(:debug)
- end
-
- it 'logs requests' do
- subject.instrument(name, params)
-
- expect(logger).to have_received(:debug).with("#{name} #{params}")
- end
-
- it 'yields' do
- expect { |b| Bosh::OpenStackCloud::ExconLoggingInstrumentor.instrument(name, params, &b) }.to yield_control
- end
-
- it 'does not manipulate the original hash' do
- params_with_body = { body: '{}' }
- old_body = params_with_body.fetch(:body)
-
- subject.instrument(name, params_with_body)
-
- expect(params_with_body.fetch(:body)).to be(old_body)
- end
-
- context 'excon log messages are pretty' do
- before(:each) do
- subject.instrument(name, params)
- end
-
- context 'response' do
- let(:name) { 'excon.response' }
- let(:params) {
- {
- port: '1234',
- host: 'hostname.fqdn',
- path: '/api',
- headers: { 'fake' => 'fake-fake' },
- status_line: '200 1/1',
- body: { text: 'fake-text' }.to_json,
- cookies: [],
- status: '200',
- reason_phrase: 'OK',
- other_important_key: '10.1',
- }
- }
-
- it 'returns a formatted response message' do
- expect(logger).to have_received(:debug).with('excon.response 200 1/1 /api params: {"port":"1234","host":"hostname.fqdn","other_important_key":"10.1"} headers: {"fake":"fake-fake"} body: {"text":"fake-text"}')
- end
- end
-
- context 'request' do
- let(:name) { 'excon.request' }
- let(:params) {
- {
- ciphers: 'fake-ciphers',
- connection: 'connection-class',
- stack: 'stack-class',
- hostname: 'fake-host.fqdn',
- method: 'PUT',
- scheme: 'https',
- port: '8774',
- path: '/v1',
- headers: { 'fake-headers' => 'fake-value' },
- body: '{"fake-body":"fake-value"}',
- other_important_key: '10.1',
- }
- }
-
- it 'returns a formatted message' do
- expect(logger).to have_received(:debug).with('excon.request PUT https://fake-host.fqdn:8774/v1 params: {"other_important_key":"10.1"} headers: {"fake-headers":"fake-value"} body: {"fake-body":"fake-value"}')
- end
- end
-
- context 'error' do
- let(:name) { 'excon.error' }
- let(:error_double) {
- double('excon_error', response: double('response', data: {
- body: '{"itemNotFound": {"message": "Volume 123 could not be found.", "code": 404}}',
- cookies: [],
- headers: { 'fake-headers' => 'fake-value' },
- host: 'fake-host.fqdn',
- local_address: '1.2.2',
- local_port: 123,
- path: '/v2',
- port: 8776,
- reason_phrase: 'Not Found',
- remote_ip: '1.1.2',
- status: 404,
- status_line: "HTTP/1.1 404 Not Found\r\n",
- }))
- }
- let(:params) { { error: error_double } }
-
- it 'returns a formatted response message' do
- expect(logger).to have_received(:debug).with('excon.error HTTP/1.1 404 Not Found /v2 params: {"host":"fake-host.fqdn","local_address":"1.2.2","local_port":123,"port":8776,"remote_ip":"1.1.2"} headers: {"fake-headers":"fake-value"} body: {"itemNotFound": {"message": "Volume 123 could not be found.", "code": 404}}')
- end
- end
- end
-
- context 'with sensitive data' do
- context 'with non-json text in body' do
- let(:params) {
- {
- body: 'non-json',
- headers: {
- 'Content-Type' => 'text/plain',
- },
- } }
-
- it 'returns original body' do
- redacted_params = subject.redact(params)
-
- expect(redacted_params[:body]).to eq(params[:body])
- end
- end
-
- context 'when content is not valid JSON' do
- let(:params) {
- {
- body: 'non-json',
- headers: {
- 'Content-Type' => 'application/json',
- },
- } }
-
- it 'returns the original body' do
- redacted_params = subject.redact(params)
-
- expect(redacted_params[:body]).to eq(params[:body])
- end
- end
-
- context 'with v2 password in body' do
- let(:body) {
- {
- auth: {
- passwordCredentials: {
- password: 'my-password',
- },
- },
- } }
- let(:params) {
- {
- body: JSON.dump(body),
- headers: {
- 'Content-Type' => 'application/json',
- },
- } }
-
- it 'redacts v2 password' do
- redacted_params = subject.redact(params)
-
- parsed_body = JSON.parse(redacted_params[:body])
- expect(parsed_body['auth']['passwordCredentials']['password']).to eq('')
- end
- end
-
- context 'with v3 password in body' do
- let(:body) {
- {
- auth: {
- identity: {
- password: {
- user: {
- password: 'my-password',
- },
- },
- },
- },
- } }
- let(:params) {
- {
- body: JSON.dump(body),
- headers: {
- 'Content-Type' => 'application/json',
- },
- } }
-
- it 'redacts v3 password' do
- redacted_params = subject.redact(params)
-
- parsed_body = JSON.parse(redacted_params[:body])
- expect(parsed_body['auth']['identity']['password']['user']['password']).to eq('')
- end
- end
-
- context 'with application_credential.secret in body' do
- let(:body) {
- {
- auth: {
- identity: {
- application_credential: {
- secret: 'my-application-credential-secret',
- },
- },
- },
- } }
- let(:params) {
- {
- body: JSON.dump(body),
- headers: {
- 'Content-Type' => 'application/json',
- },
- } }
-
- it 'redacts application_credential.secret' do
- redacted_params = subject.redact(params)
-
- parsed_body = JSON.parse(redacted_params[:body])
- expect(parsed_body['auth']['identity']['application_credential']['secret']).to eq('')
- end
- end
-
- context 'with server.user_data in body' do
- let(:body) {
- {
- server: {
- user_data: 'user data',
- },
- } }
- let(:params) {
- {
- body: JSON.dump(body),
- headers: {
- 'Content-Type' => 'application/json',
- },
- } }
-
- it 'redacts server.user_data' do
- redacted_params = subject.redact(params)
-
- parsed_body = JSON.parse(redacted_params[:body])
- expect(parsed_body['server']['user_data']).to eq('')
- end
- end
-
- context 'with x-auth-token in header' do
- let(:headers) {
- {
- 'X-Auth-Token' => 'token',
- } }
- let(:params) { { headers: } }
-
- it 'redacts params' do
- redacted_params = subject.redact(params)
-
- expect(redacted_params[:headers]['X-Auth-Token']).to eq('')
- end
- end
- end
-
- context 'with non-string body (could be File)' do
- it 'does nothing' do
- params_with_file_body = { body: 5 }
-
- subject.instrument(name, params_with_file_body)
-
- expect(logger).to have_received(:debug).with("#{name} #{params_with_file_body}")
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/floating_ip_spec.rb b/src/bosh_openstack_cpi/spec/unit/floating_ip_spec.rb
deleted file mode 100644
index 688f68a99..000000000
--- a/src/bosh_openstack_cpi/spec/unit/floating_ip_spec.rb
+++ /dev/null
@@ -1,253 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::FloatingIp do
- let(:logger) { double('logger', info: nil) }
-
- before(:each) {
- allow(Bosh::Clouds::Config).to receive(:logger).and_return(logger)
- allow(openstack).to receive(:with_openstack) { |&block| block.call }
- }
- let(:network) { double('network', get_server: nil, list_floating_ips: nil, associate_floating_ip: nil, disassociate_floating_ip: nil, get_port: nil, ports: nil) }
- let(:compute) { double('compute', addresses: nil) }
- let(:openstack) { double('openstack', use_nova_networking?: use_nova_networking, network:, compute:) }
-
- context 'when `use_nova_networking=false`' do
- let(:use_nova_networking) { false }
-
- let(:floating_ip_port_id) { 'old-server-port-id' }
-
- let(:floating_ips_response) {
- Struct.new(:body).new({
- 'floatingips' => floating_ips,
- })
- }
- let(:floating_ips) {
- [
- {
- 'floating_network_id' => 'some-floating-network-id',
- 'router_id' => 'some-router-id',
- 'fixed_ip_address' => 'some-fixed-ip-address',
- 'floating_ip_address' => '1.2.3.4',
- 'tenant_id' => 'some-tenant-id',
- 'status' => 'some-status',
- 'port_id' => floating_ip_port_id,
- 'id' => 'floating-ip-id',
- },
- ]
- }
-
- let(:get_port_response) {
- Struct.new(:body).new({
- 'port' => port,
- })
- }
-
- let(:port_device_id) { nil }
-
- let(:port) {
- {
- 'device_id' => port_device_id,
- } }
- before(:each) {
- allow(network).to receive(:get_port).with(floating_ip_port_id).and_return(get_port_response)
- }
-
- let(:old_server) { {} }
- let(:get_server_response) {
- Struct.new(:body).new({
- 'server' => old_server,
- })
- }
- before(:each) {
- allow(compute).to receive(:get_server_details).and_return(get_server_response)
- }
-
- let(:port_collection) { double('Fog::OpenStack::Network::Ports', all: [port_model]) }
- let(:port_model) { double('Fog::OpenStack::Network::Port', id: 'port-id') }
-
- before(:each) {
- allow(network).to receive(:ports).and_return(port_collection)
- }
-
- describe '.port_attached?' do
- context 'when the floating_ip port_id is nil' do
- let(:floating_ip) {
- {
- 'port_id' => nil,
- }
- }
- it 'returns false' do
- expect(Bosh::OpenStackCloud::FloatingIp.port_attached?(floating_ip)).to be false
- end
- end
- context 'when the floating_ip port_id is empty' do
- let(:floating_ip) {
- {
- 'port_id' => '',
- }
- }
- it 'returns false' do
- expect(Bosh::OpenStackCloud::FloatingIp.port_attached?(floating_ip)).to be false
- end
- end
- context 'when the floating_ip port_id is non-empty' do
- let(:floating_ip) {
- {
- 'port_id' => floating_ip_port_id,
- }
- }
- it 'returns true' do
- expect(Bosh::OpenStackCloud::FloatingIp.port_attached?(floating_ip)).to be true
- end
- end
- end
-
- describe '.reassociate' do
- before(:each) {
- allow(network).to receive(:list_floating_ips).with('floating_ip_address' => '1.2.3.4').and_return(floating_ips_response)
- }
-
- let(:server) {
- Struct.new(:id, :name).new('server-id', 'server-name')
- }
-
- context 'when the floating ip is already associated with a port' do
- let(:port_device_id) { old_server['id'] }
-
- let(:old_server) {
- {
- 'id' => 'old-server-id',
- 'name' => 'old-server',
- }
- }
-
- it 'disassociates the floating ip and associates it with the given server' do
- Bosh::OpenStackCloud::FloatingIp.reassociate(openstack, '1.2.3.4', server, 'network-id')
-
- expect(network).to have_received(:list_floating_ips).with('floating_ip_address' => '1.2.3.4')
-
- expect(network).to have_received(:disassociate_floating_ip).with('floating-ip-id')
- expect(logger).to have_received(:info).with("Disassociating floating IP '1.2.3.4' from server 'old-server (old-server-id)'")
- expect(port_collection).to have_received(:all).with(device_id: 'server-id', network_id: 'network-id')
- expect(logger).to have_received(:info).with("Associating floating IP '1.2.3.4' with server 'server-name (server-id)'")
- expect(network).to have_received(:associate_floating_ip).with('floating-ip-id', 'port-id')
- end
- end
-
- context 'when the floating ip is not associated with a port' do
- let(:floating_ip_port_id) { nil }
-
- it 'assigns the given floating ip to the given server' do
- Bosh::OpenStackCloud::FloatingIp.reassociate(openstack, '1.2.3.4', server, 'network-id')
-
- expect(network).to have_received(:list_floating_ips).with('floating_ip_address' => '1.2.3.4')
- expect(port_collection).to have_received(:all).with(device_id: 'server-id', network_id: 'network-id')
-
- expect(network).to have_received(:associate_floating_ip).with('floating-ip-id', 'port-id')
- end
-
- context 'when multiple ports are connected to the external network' do
- before(:each) do
- allow(port_collection).to receive(:all).and_return([double('other_port', id: 'other-port-id'), port_model])
- end
-
- it 'assigns the given floating ip to the first port' do
- Bosh::OpenStackCloud::FloatingIp.reassociate(openstack, '1.2.3.4', server, 'network-id')
-
- expect(network).to have_received(:list_floating_ips).with('floating_ip_address' => '1.2.3.4')
- expect(port_collection).to have_received(:all).with(device_id: 'server-id', network_id: 'network-id')
-
- expect(network).to have_received(:associate_floating_ip).with('floating-ip-id', 'other-port-id')
- end
- end
- end
-
- context "openstack doesn't find the given floating ip" do
- let(:floating_ips) { [] }
-
- it 'raises a cloud error' do
- expect {
- Bosh::OpenStackCloud::FloatingIp.reassociate(openstack, '1.2.3.4', server, 'network-id')
- }.to raise_error Bosh::Clouds::CloudError, "Floating IP '1.2.3.4' not allocated"
- end
- end
-
- context 'openstack finds the given floating ip more than once' do
- let(:floating_ips) { [{ 'floating_network_id' => 'id1' }, { 'floating_network_id' => 'id2' }] }
-
- it 'raises a cloud error' do
- expect {
- Bosh::OpenStackCloud::FloatingIp.reassociate(openstack, '1.2.3.4', server, 'network-id')
- }.to raise_error Bosh::Clouds::CloudError, "Floating IP '1.2.3.4' found in multiple networks: 'id1', 'id2'"
- end
- end
-
- context 'server has no port in the given network' do
- before(:each) do
- allow(port_collection).to receive(:all).and_return([])
- end
- it 'raises a cloud error' do
- expect {
- Bosh::OpenStackCloud::FloatingIp.reassociate(openstack, '1.2.3.4', server, 'network-id-not-matching-the-port')
- }.to raise_error Bosh::Clouds::CloudError, "Server has no port in network 'network-id-not-matching-the-port'"
- end
- end
- end
- end
-
- context 'when `use_nova_networking=true`' do
- let(:use_nova_networking) { true }
-
- describe '.reassociate' do
- let(:server) {
- Struct.new(:id, :name).new('server-id', 'server-name')
- }
-
- before(:each) do
- allow(compute).to receive(:addresses).and_return([address])
- end
-
- let(:server) { double('server', id: 'i-test') }
-
- context 'ip already associated with an instance' do
- let(:address) do
- double('address', :server= => nil, :id => 'network_b', :ip => '1.2.3.4', :instance_id => 'old-instance-id')
- end
-
- it 'adds floating ip to the server for vip network' do
- Bosh::OpenStackCloud::FloatingIp.reassociate(openstack, '1.2.3.4', server, 'network-id')
-
- expect(logger).to have_received(:info).with("Disassociating floating IP '1.2.3.4' from server 'old-instance-id'")
- expect(address).to have_received(:server=).with(nil)
- expect(logger).to have_received(:info).with("Associating floating IP '1.2.3.4' with server 'i-test'")
- expect(address).to have_received(:server=).with(server)
- end
- end
-
- context 'ip not already associated with an instance' do
- let(:address) do
- double('address', :server= => nil, :id => 'network_b', :ip => '1.2.3.4', :instance_id => nil)
- end
-
- it 'adds free floating ip to the server for vip network' do
- Bosh::OpenStackCloud::FloatingIp.reassociate(openstack, '1.2.3.4', server, 'network-id')
-
- expect(address).to_not have_received(:server=).with(nil)
- expect(address).to have_received(:server=).with(server)
- end
- end
-
- context 'no floating IP allocated for vip network' do
- let(:address) do
- double('address', :server= => nil, :id => 'network_b', :ip => '10.0.0.2')
- end
-
- it 'fails' do
- expect {
- Bosh::OpenStackCloud::FloatingIp.reassociate(openstack, '1.2.3.4', server, 'network-id')
- }.to raise_error Bosh::Clouds::CloudError, /Floating IP .* not allocated/
- end
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/has_disk_spec.rb b/src/bosh_openstack_cpi/spec/unit/has_disk_spec.rb
deleted file mode 100644
index e8f782791..000000000
--- a/src/bosh_openstack_cpi/spec/unit/has_disk_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- describe 'has_disk?' do
- context 'when disk is found' do
- let(:disk) { instance_double('Fog::Volume') }
-
- it 'returns true' do
- cloud = mock_cloud(mock_cloud_options['properties']) do |fog|
- allow(fog.volume.volumes).to receive(:get).with('fake-disk-uuid').and_return(disk)
- end
-
- expect(cloud.has_disk?('fake-disk-uuid')).to be(true)
- end
- end
-
- context 'when disk is not found' do
- it 'returns false' do
- cloud = mock_cloud(mock_cloud_options['properties']) do |fog|
- allow(fog.volume.volumes).to receive(:get).with('fake-disk-uuid').and_return(nil)
- end
-
- expect(cloud.has_disk?('fake-disk-uuid')).to be(false)
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/has_vm_spec.rb b/src/bosh_openstack_cpi/spec/unit/has_vm_spec.rb
deleted file mode 100644
index 64c5b9476..000000000
--- a/src/bosh_openstack_cpi/spec/unit/has_vm_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- it 'has_vm? returns true if OpenStack server exists' do
- server = double('server', id: 'i-foobar', state: :active)
- cloud = mock_cloud(mock_cloud_options['properties']) do |fog|
- allow(fog.compute.servers).to receive(:get).with('i-foobar').and_return(server)
- end
- expect(cloud.has_vm?('i-foobar')).to be(true)
- end
-
- it "has_vm? returns false if OpenStack server doesn't exists" do
- cloud = mock_cloud(mock_cloud_options['properties']) do |fog|
- allow(fog.compute.servers).to receive(:get).with('i-foobar').and_return(nil)
- end
- expect(cloud.has_vm?('i-foobar')).to be(false)
- end
-
- it 'has_vm? returns false if OpenStack server state is :terminated' do
- server = double('server', id: 'i-foobar', state: :terminated)
- cloud = mock_cloud(mock_cloud_options['properties']) do |fog|
- allow(fog.compute.servers).to receive(:get).with('i-foobar').and_return(server)
- end
- expect(cloud.has_vm?('i-foobar')).to be(false)
- end
-
- it 'has_vm? returns false if OpenStack server state is :deleted' do
- server = double('server', id: 'i-foobar', state: :deleted)
- cloud = mock_cloud(mock_cloud_options['properties']) do |fog|
- allow(fog.compute.servers).to receive(:get).with('i-foobar').and_return(server)
- end
- expect(cloud.has_vm?('i-foobar')).to be(false)
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/helpers_spec.rb b/src/bosh_openstack_cpi/spec/unit/helpers_spec.rb
deleted file mode 100644
index 0f3a87b8a..000000000
--- a/src/bosh_openstack_cpi/spec/unit/helpers_spec.rb
+++ /dev/null
@@ -1,125 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Helpers do
- let(:logger) { double('logger', error: nil) }
-
- let(:helpers_user) do
- Class.new do
- include Bosh::OpenStackCloud::Helpers
- def initialize(logger)
- @logger = logger
- end
- end
- end
-
- subject {
- helpers_user.new(logger)
- }
-
- describe '.fail_on_error' do
- context 'when no error is given' do
- it 'does not raise an error' do
- expect {
- subject.fail_on_error
- }.not_to raise_error
- end
- end
-
- context 'when error is nil' do
- it 'does not raise an error' do
- expect {
- subject.fail_on_error(nil)
- }.not_to raise_error
- end
- end
-
- context 'when a single error is given' do
- it 'creates a cloud error with the message of the single error' do
- expect {
- subject.fail_on_error(Bosh::OpenStackCloud::Helpers::ErrorWrapper.new(StandardError.new('error1')))
- }.to raise_error(Bosh::Clouds::CloudError, 'error1')
- end
- end
-
- context 'when multiple errors' do
- it 'creates a cloud error with joined error messages' do
- expect {
- subject.fail_on_error(
- Bosh::OpenStackCloud::Helpers::ErrorWrapper.new(StandardError.new('error1')),
- Bosh::OpenStackCloud::Helpers::ErrorWrapper.new(StandardError.new('error2')),
- )
- }.to raise_error(Bosh::Clouds::CloudError, "Multiple cloud errors occurred:\nerror1\nerror2")
- end
-
- it 'logs all errors' do
- allow(logger).to receive(:error)
- error_wrappers = %w[error1 error2].map do |text|
- error = StandardError.new(text)
- error.set_backtrace("backtrace #{text}")
- Bosh::OpenStackCloud::Helpers::ErrorWrapper.new(error)
- end
-
- expect {
- subject.fail_on_error(*error_wrappers)
- }.to raise_error(Bosh::Clouds::CloudError)
-
- expect(logger).to have_received(:error).with(error_wrappers[0].error)
- expect(logger).to have_received(:error).with(error_wrappers[0].error.backtrace)
- expect(logger).to have_received(:error).with(error_wrappers[1].error)
- expect(logger).to have_received(:error).with(error_wrappers[1].error.backtrace)
- end
- end
- end
-
- describe '.catch_error' do
- it 'catches an error and return the error object' do
- error_wrapper = nil
- expected_error = StandardError.new('BAAAM!')
-
- expect {
- error_wrapper = subject.catch_error { raise expected_error }
- }.to_not raise_error
-
- expect(error_wrapper.error).to eq(expected_error)
- end
-
- it 'returns nil if no exception given' do
- error = nil
-
- expect {
- error = subject.catch_error {
- # intentionally empty
- }
- }.to_not raise_error
-
- expect(error).to eq(nil)
- end
-
- context 'when a message prefix is given' do
- it 'prefixes the error message' do
- initial_error = StandardError.new('BAAM!')
- prefix = 'My current situation'
-
- error_wrapper = subject.catch_error(prefix) { raise initial_error }
-
- expect(error_wrapper.message).to eq("#{prefix}: BAAM!")
- expect(error_wrapper.error.backtrace).to eq(initial_error.backtrace)
- end
-
- context 'when Excon::Error::Socket is raised' do
- before(:each) do
- allow(logger).to receive(:error)
- end
-
- it 'does return the same exception and logs prefix' do
- initial_error = Excon::Error::Socket.new
- prefix = 'Does not raise undefined method message'
-
- error_wrapper = subject.catch_error(prefix) { raise initial_error }
-
- expect(error_wrapper.error).to be(initial_error)
- end
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/instance_type_mapper_spec.rb b/src/bosh_openstack_cpi/spec/unit/instance_type_mapper_spec.rb
deleted file mode 100644
index cba43b3eb..000000000
--- a/src/bosh_openstack_cpi/spec/unit/instance_type_mapper_spec.rb
+++ /dev/null
@@ -1,169 +0,0 @@
-require 'spec_helper'
-require 'fog/openstack/compute/models/flavors'
-
-describe Bosh::OpenStackCloud::InstanceTypeMapper do
- let(:mapper) { described_class.new }
- let(:flavors) do
- [
- instance_double(Fog::OpenStack::Compute::Flavor, id: '1', name: 'too_small', vcpus: 1, ram: 2047, disk: 2, ephemeral: 49, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '2', name: 'too_big', vcpus: 3, ram: 2049, disk: 4, ephemeral: 51, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '3', name: 'just_right', vcpus: 2, ram: 2048, disk: 3, ephemeral: 50, disabled: false),
- ]
- end
-
- context 'when user default root disk properties (`boot_from_volume` set to false or unset)' do
- context 'when flavors have adequate vCPUs/RAM/root disk/ephemeral disk' do
- it 'returns the smallest flavor that meets the vCPU/RAM/root disk/ephemeral disk requirements' do
- requirements = {
- 'ram' => 2048,
- 'cpu' => 2,
- 'ephemeral_disk_size' => 10 * 1024,
- }
- expect(mapper.map(requirements:, flavors:)['instance_type']).to eq('just_right')
- end
- end
-
- context 'when adequate flavors only differ by root disk/ephemeral disk sizes' do
- let(:flavors) do
- [
- instance_double(Fog::OpenStack::Compute::Flavor, id: '1', name: 'no_good', vcpus: 1, ram: 2048, disk: 2, ephemeral: 10, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '2', name: 'good_but_big', vcpus: 1, ram: 2048, disk: 3, ephemeral: 13, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '3', name: 'good_yet_big', vcpus: 1, ram: 2048, disk: 4, ephemeral: 12, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '4', name: 'second_best', vcpus: 1, ram: 2048, disk: 5, ephemeral: 10, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '5', name: 'best', vcpus: 1, ram: 2048, disk: 4, ephemeral: 11, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '6', name: 'good_and_big', vcpus: 1, ram: 2048, disk: 5, ephemeral: 11, disabled: false),
- ]
- end
- it 'returns the flavor that has the smallest total disk usage, and, in the event of a tie, the smallest root disk' do
- requirements = {
- 'ram' => 2048,
- 'cpu' => 1,
- 'ephemeral_disk_size' => 10 * 1024,
- }
- expect(mapper.map(requirements:, flavors:)['instance_type']).to eq('best')
- end
- end
-
- context 'when no flavor meets the ephemeral requirements but the root disk is big enough to accommodate' do
- let(:flavors) do
- [
- instance_double(Fog::OpenStack::Compute::Flavor, id: '1', name: 'too_small', vcpus: 1, ram: 2048, disk: 3, ephemeral: 9, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '2', name: 'too_small', vcpus: 1, ram: 2048, disk: 12, ephemeral: 9, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '3', name: 'zero_ephem', vcpus: 2, ram: 2048, disk: 14, ephemeral: 0, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '4', name: 'big_root', vcpus: 1, ram: 2048, disk: 13, ephemeral: 1, disabled: false),
- ]
- end
- it 'returns the flavor that has the smallest big-enough root disk and has zero-size ephemeral disk' do
- requirements = {
- 'ram' => 2048,
- 'cpu' => 1,
- 'ephemeral_disk_size' => 10 * 1024,
- }
- expect(mapper.map(requirements:, flavors:)['instance_type']).to eq('zero_ephem')
- end
- end
-
- context 'when flavors are inadequate' do
- let(:flavors) do
- [
- instance_double(Fog::OpenStack::Compute::Flavor, id: '1', name: 'way_too_small', vcpus: 1, ram: 2048, disk: 10, ephemeral: 47, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '2', name: 'too_small', vcpus: 1, ram: 2048, disk: 10, ephemeral: 48, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '3', name: 'barely_too_small', vcpus: 1, ram: 2048, disk: 10, ephemeral: 49, disabled: false),
- ]
- end
- it 'raises an error' do
- requirements = {
- 'ram' => 2048,
- 'cpu' => 1,
- 'ephemeral_disk_size' => 50 * 1024,
- }
- expect { mapper.map(requirements:, flavors:)['instance_type'] }.to raise_error(/Unable to meet requested VM requirements/)
- end
- end
- end
-
- context 'when user sets root disk properties (`boot_from_volume` set to true)' do
- context 'when only flavors with ephemeral disks exist' do
- let(:flavors) do
- [
- instance_double(Fog::OpenStack::Compute::Flavor, id: '1', name: 'big_enough_but_with_ephemeral_disk', vcpus: 1, ram: 2048, disk: 1, ephemeral: 1, disabled: false),
- ]
- end
- it 'raises an error even if ephemeral disk size would be big enough' do
- requirements = {
- 'ram' => 2048,
- 'cpu' => 1,
- 'ephemeral_disk_size' => 1 * 1024,
- }
- expect { mapper.map(requirements:, flavors:, boot_from_volume: true)['instance_type'] }.to raise_error(/Unable to meet requested VM requirements/)
- end
- end
-
- context 'when the flavors have the same CPU and RAM specs' do
- let(:flavors) do
- [
- instance_double(Fog::OpenStack::Compute::Flavor, id: '1', name: 'root_disk_small', vcpus: 2, ram: 2048, disk: 2, ephemeral: 0, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '2', name: 'root_disk_medium', vcpus: 2, ram: 2048, disk: 13, ephemeral: 0, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '3', name: 'root_disk_big', vcpus: 2, ram: 2048, disk: 20, ephemeral: 0, disabled: false),
- ]
- end
- it 'returns the smallest flavor and sets root_disk size to OS size plus ephemeral_disk_size' do
- ephemeral_disk_size = 10
- root_disk_size = 3
-
- requirements = {
- 'ram' => 2048,
- 'cpu' => 2,
- 'ephemeral_disk_size' => ephemeral_disk_size * 1024,
- }
- cloud_props = mapper.map(requirements:, flavors:, boot_from_volume: true)
- expect(cloud_props['instance_type']).to eq('root_disk_small')
- expect(cloud_props).to have_key('root_disk')
- expect(cloud_props['root_disk']['size']).to eq(root_disk_size + ephemeral_disk_size) #=> 13
- end
- end
-
- context 'when flavors are adequate (except root is too small)' do
- let(:flavors) do
- [
- instance_double(Fog::OpenStack::Compute::Flavor, id: '1', name: 'too_small', vcpus: 1, ram: 1024, disk: 2, ephemeral: 0, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '2', name: 'just_right', vcpus: 2, ram: 2048, disk: 2, ephemeral: 0, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '3', name: 'too_big', vcpus: 3, ram: 4096, disk: 2, ephemeral: 0, disabled: false),
- ]
- end
- it 'returns the smallest flavor, setting the root_disk large enough for the OS and ephemeral disk' do
- ephemeral_disk_size = 10
- root_disk_size = 3
-
- requirements = {
- 'ram' => 2048,
- 'cpu' => 2,
- 'ephemeral_disk_size' => ephemeral_disk_size * 1024,
- }
-
- cloud_props = mapper.map(requirements:, flavors:, boot_from_volume: true)
- expect(cloud_props['instance_type']).to eq('just_right')
- expect(cloud_props).to have_key('root_disk')
- expect(cloud_props['root_disk']['size']).to eq(root_disk_size + ephemeral_disk_size) #=> 13
- end
- end
-
- context 'when flavors are inadequate' do
- let(:flavors) do
- [
- instance_double(Fog::OpenStack::Compute::Flavor, id: '1', name: 'way_too_small', vcpus: 1, ram: 1024, disk: 20, ephemeral: 0, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '2', name: 'too_small', vcpus: 1, ram: 2046, disk: 20, ephemeral: 0, disabled: false),
- instance_double(Fog::OpenStack::Compute::Flavor, id: '3', name: 'barely_too_small', vcpus: 1, ram: 2047, disk: 20, ephemeral: 0, disabled: false),
- ]
- end
- it 'raises an error' do
- requirements = {
- 'ram' => 2048,
- 'cpu' => 1,
- 'ephemeral_disk_size' => 10 * 1024,
- }
- expect { mapper.map(requirements:, flavors:)['instance_type'] }.to raise_error(/Unable to meet requested VM requirements/)
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/loadbalancer_configurator_spec.rb b/src/bosh_openstack_cpi/spec/unit/loadbalancer_configurator_spec.rb
deleted file mode 100644
index ded71d5dc..000000000
--- a/src/bosh_openstack_cpi/spec/unit/loadbalancer_configurator_spec.rb
+++ /dev/null
@@ -1,635 +0,0 @@
-require 'spec_helper'
-require 'fog/openstack/compute/models/server'
-
-describe Bosh::OpenStackCloud::LoadbalancerConfigurator do
- shared_examples 'changing load balancer resource' do
- context 'when load balancer is in status PENDING_UPDATE' do
- let(:body) { { 'NeutronError' => { 'message' => 'Invalid state PENDING_UPDATE of loadbalancer resource 1234-abcd' } } }
- let(:response) { instance_double('response', body: JSON.dump(body)) }
- let(:state_timeout) { 10 }
-
- before do
- Timecop.freeze
- allow(network).to receive(openstack_method_name, &raise_times(2))
- allow(openstack).to receive(:state_timeout).and_return(state_timeout)
- end
-
- after do
- Timecop.return
- end
-
- it 'attempts to change resource again after load balancer has become active again' do
- expect(network).to receive(openstack_method_name).exactly(3)
- expect(openstack).to receive(:wait_resource).exactly(4)
-
- action.call
- end
-
- it 'logs the attempts' do
- allow(logger).to receive(:debug)
- expected_message = "Changing load balancer resource failed with 'omg pending_update', unsuccessful attempts: "
-
- action.call
-
- expect(logger).to have_received(:debug)
- .with(expected_message + "'1'")
- .with(expected_message + "'2'")
- end
-
- context 'when state_timeout has been reached exactly' do
- let(:expected_retries) { 2 }
- let(:start_time) { Time.local(2017) }
- let(:time_increment) { 1 }
- let(:state_timeout) { time_increment * expected_retries }
-
- before do
- allow(network).to receive(openstack_method_name, &raise_times(expected_retries))
- Timecop.freeze(start_time)
- allow(openstack).to receive(:wait_resource) do
- Timecop.freeze(Time.now + time_increment)
- end
- end
-
- it 'fails with a CloudError, containing elapsed time and number of attempts' do
- expect {
- action.call
- }.to raise_error Bosh::Clouds::CloudError, /Reason: Bosh::Clouds::CloudError Failed after #{expected_retries}.0s with #{expected_retries} attempts with 'omg pending_update'/
-
- expect(network).to have_received(openstack_method_name).exactly(expected_retries)
- expect(openstack).to have_received(:wait_resource).exactly(expected_retries)
- end
- end
-
- def raise_times(times)
- times_called = 0
- proc {
- times_called += 1
- raise Excon::Error::Conflict.new('omg pending_update', '', response) if times_called <= times
- success_response
- }
- end
- end
- end
-
- subject(:subject) { Bosh::OpenStackCloud::LoadbalancerConfigurator.new(openstack, logger) }
- let(:logger) { instance_double(Logger, debug: nil) }
- let(:network_spec) { {} }
- let(:options) { { 'auth_url' => '' } }
- let(:openstack) { Bosh::OpenStackCloud::Openstack.new(options) }
- let(:network) { double('network', list_lbaas_pools: loadbalancer_pools_response, get_lbaas_listener: lb_listener, get_lbaas_pool: lb_pool) }
- let(:lb_listener) { double('lb_listener', body: { 'listener' => { 'loadbalancers' => [{ 'id' => 'loadbalancer-id' }] } }) }
- let(:lb_pool) { double('lb_pool', body: { 'pool' => { 'loadbalancers' => [{ 'id' => 'loadbalancer-id' }] } }) }
- let(:loadbalancer_pools_response) { double('response', body:) }
- let(:body) {
- {
- 'pools' => [
- { 'name' => 'my-lb-pool', 'id' => 'pool-id' },
- ],
- }
- }
- let(:server) { instance_double(Fog::OpenStack::Compute::Server, id: 1234) }
- let(:pool) {
- {
- 'name' => 'my-lb-pool',
- 'port' => 8080,
- }
- }
-
- before(:each) do
- allow(openstack).to receive(:network).and_return(network)
- allow(openstack).to receive(:wait_resource)
- end
-
- describe '#create_pool_memberships' do
- context 'when a list of loadbalancer_pools is given' do
- let(:load_balancer_pools) {
- [
- { 'name' => 'my-pool-1', 'port' => 443 },
- { 'name' => 'my-pool-2', 'port' => 8080 },
- ]
- }
-
- let(:network_spec) {
- {
- 'network_a' => manual_network_spec(net_id: 'sub-net-id', ip: '10.10.10.10'),
- 'vip_network' => vip_network_spec,
- } }
-
- let(:lb_member) { double('lb_member', body: { 'member' => { 'id' => 'membership-id' } }) }
-
- it 'creates the memberships and returns the corresponding server_tags' do
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:matching_gateway_subnet_ids_for_ip).and_return(['sub-net-id'])
- allow(network).to receive(:create_lbaas_pool_member).and_return(lb_member)
-
- server_tags = subject.create_pool_memberships(server, network_spec, load_balancer_pools)
-
- expect(server_tags).to eq(
- 'lbaas_pool_1' => 'pool-id/membership-id',
- 'lbaas_pool_2' => 'pool-id/membership-id',
- )
- end
- end
-
- context 'when the given list is empty' do
- it 'does nothing' do
- allow(network).to receive(:create_lbaas_pool_member)
-
- server_tags = subject.create_pool_memberships(server, network_spec, [])
-
- expect(server_tags).to eq({})
- expect(network).to_not have_received(:create_lbaas_pool_member)
- end
- end
- end
-
- describe '#create_membership' do
- let(:lb_member) { double('lb_member', body: { 'member' => { 'id' => 'member-id' } }) }
-
- before(:each) do
- allow(logger).to receive(:info)
- allow(network).to receive(:create_lbaas_pool_member).and_return(lb_member)
- end
-
- it 'waits for loadbalancer to be active and returns the id of the existing membership' do
- loadbalancer = instance_double(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource, 'loadbalancer', provisioning_status: 'ACTIVE')
- allow(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource).to receive(:new).and_return(loadbalancer)
-
- membership_id = subject.create_membership('pool-id', '10.0.0.1', '8080', 'subnet-id')
-
- expect(membership_id).to eq('member-id')
- expect(network).to have_received(:get_lbaas_pool).with('pool-id')
- expect(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource).to have_received(:new).with('loadbalancer-id', openstack)
- expect(openstack).to have_received(:wait_resource).with(loadbalancer, :active, :provisioning_status).twice
- end
-
- it 'runs into time out while waiting for load balancer to be active before creating pool member' do
- loadbalancer = instance_double(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource, 'loadbalancer', provisioning_status: 'PENDING_UPDATE')
- allow(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource).to receive(:new).and_return(loadbalancer)
- allow(openstack).to receive(:wait_resource).with(loadbalancer, :active, :provisioning_status).and_raise(Bosh::Clouds::CloudError.new('Timed out waiting for load balancer to be ACTIVE'))
-
- expect {
- subject.create_membership('pool-id', '10.0.0.1', '8080', 'subnet-id')
- }.to raise_error(Bosh::Clouds::CloudError, /Timed out waiting for load balancer to be ACTIVE/)
-
- expect(network).to have_received(:get_lbaas_pool).with('pool-id')
- expect(network).to_not have_received(:create_lbaas_pool_member)
- expect(openstack).to have_received(:wait_resource).with(loadbalancer, :active, :provisioning_status).once
- end
-
- context 'when lbaas resource cannot be found' do
- before(:each) do
- allow(subject).to receive(:loadbalancer_id).and_raise(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource::NotFound, 'some-error-message')
- end
-
- it 'raises an error' do
- expect {
- subject.create_membership('pool-id', '10.0.0.1', '8080', 'subnet-id')
- }.to raise_error(Bosh::Clouds::VMCreationFailed, 'some-error-message')
-
- expect(network).to_not have_received(:create_lbaas_pool_member)
- end
- end
-
- context 'when lbaas resources are not in a valid state e.g. pool has more than one loadbalancer associated' do
- before(:each) do
- allow(subject).to receive(:loadbalancer_id).and_raise(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource::NotSupportedConfiguration, 'some-error-message')
- end
-
- it 'raises an error' do
- expect {
- subject.create_membership('pool-id', '10.0.0.1', '8080', 'subnet-id')
- }.to raise_error(Bosh::Clouds::VMCreationFailed, 'some-error-message')
- expect(network).to_not have_received(:create_lbaas_pool_member)
- end
- end
-
- context 'when pool membership cannot be created' do
- let(:members) {
- double('lb_member', body: {
- 'members' => [
- { 'id' => 'member-id-1', 'subnet_id' => 'subnet-id', 'address' => '10.0.0.2', 'protocol_port' => '8080' },
- { 'id' => 'member-id-2', 'subnet_id' => 'subnet-id', 'address' => '10.0.0.1', 'protocol_port' => '8080' },
- ],
- }) }
-
- let(:body) { {} }
- let(:response) { instance_double('response', body: JSON.dump(body)) }
-
- before(:each) do
- allow(network).to receive(:create_lbaas_pool_member).and_raise(Excon::Error::Conflict.new('BAM!', '', response))
- allow(network).to receive(:list_lbaas_pool_members).with('pool-id').and_return(members)
- end
-
- context 'when the membership already exists' do
- it 'returns the id of the existing membership' do
- membership_id = subject.create_membership('pool-id', '10.0.0.1', '8080', 'subnet-id')
-
- expect(membership_id).to eq('member-id-2')
- end
-
- it 'logs the fact' do
- subject.create_membership('pool-id', '10.0.0.1', '8080', 'subnet-id')
-
- expect(logger).to have_received(:info).with("Load balancer pool membership with pool id 'pool-id', ip '10.0.0.1', and port '8080' already exists. The membership has the id 'member-id-2'.")
- end
- end
-
- context 'when the membership supposedly exists, but cannot be matched' do
- it 'returns an error' do
- expect {
- subject.create_membership('pool-id', 'wrong-ip', '8080', 'subnet-id')
- }.to raise_error(Bosh::Clouds::CloudError, "Load balancer pool membership with pool id 'pool-id', ip 'wrong-ip', and port '8080' supposedly exists, but cannot be found.")
- end
- end
-
- it_behaves_like('changing load balancer resource') do
- let(:success_response) { double('lb_member', body: { 'member' => { 'id' => 'member-id' } }) }
- let(:openstack_method_name) { :create_lbaas_pool_member }
- let(:action) {
- -> { subject.create_membership('pool-id', 'wrong-ip', '8080', 'subnet-id') }
- }
- end
- end
- end
-
- describe '#add_vm_to_pool' do
- context 'when pool input invalid' do
- it 'raises an error' do
- expect {
- subject.add_vm_to_pool(server, network_spec, 'name' => 'foo')
- }.to raise_error(Bosh::Clouds::VMCreationFailed, "VM with id '1234' cannot be attached to load balancer pool 'foo'. Reason: Load balancer pool 'foo' has no port definition")
-
- expect {
- subject.add_vm_to_pool(server, network_spec, 'port' => 8080)
- }.to raise_error(Bosh::Clouds::VMCreationFailed, "VM with id '1234' cannot be attached to load balancer pool ''. Reason: Load balancer pool defined without a name")
- end
- end
-
- context 'when create_membership raises an error' do
- let(:network_spec) {
- {
- 'network_a' => manual_network_spec(net_id: 'sub-net-id', ip: '10.10.10.10'),
- }
- }
-
- before(:each) do
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:matching_gateway_subnet_ids_for_ip).and_return(['sub-net-id'])
- allow(subject).to receive(:create_membership).and_raise(Bosh::Clouds::VMCreationFailed.new(false), 'some-error-message')
- end
-
- it 'raises an VMCreationFailed error' do
- expect {
- subject.add_vm_to_pool(server, network_spec, pool)
- }.to raise_error(Bosh::Clouds::VMCreationFailed, "VM with id '1234' cannot be attached to load balancer pool 'my-lb-pool'. Reason: some-error-message")
- end
- end
-
- context 'when load balancer pool can not be associated to the VM' do
- context 'when load balancer pool name does not exist' do
- let(:body) { { 'pools' => [] } }
-
- it 'raises an error' do
- expect {
- subject.add_vm_to_pool(server, network_spec, pool)
- }.to raise_error(Bosh::Clouds::VMCreationFailed, "VM with id '1234' cannot be attached to load balancer pool 'my-lb-pool'. Reason: Load balancer pool 'my-lb-pool' does not exist")
- end
- end
-
- context 'when load balancer pool name exists multiple times' do
- let(:body) {
- {
- 'pools' => [
- { 'name' => 'my-lb-pool' },
- { 'name' => 'my-lb-pool' },
- ],
- }
- }
- it 'raises an error' do
- expect {
- subject.add_vm_to_pool(server, network_spec, pool)
- }.to raise_error(Bosh::Clouds::VMCreationFailed, "VM with id '1234' cannot be attached to load balancer pool 'my-lb-pool'. Reason: Load balancer pool 'my-lb-pool' exists multiple times. Make sure to use unique naming.")
- end
- end
- end
-
- context 'when load balancer pool name exist exactly once' do
- before(:each) do
- allow(network).to receive(:create_lbaas_pool_member).and_return(lb_member)
- end
-
- let(:lb_member) { double('lb_member', body: { 'member' => { 'id' => 'id' } }) }
-
- let(:network_spec) {
- {
- 'network_a' => manual_network_spec(net_id: 'sub-net-id', ip: '10.10.10.10'),
- 'vip_network' => vip_network_spec,
- }
- }
-
- it 'adds the VM as a member of the specified pool' do
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:matching_gateway_subnet_ids_for_ip).and_return(['sub-net-id'])
-
- loadbalancer_membership = subject.add_vm_to_pool(server, network_spec, pool)
-
- expect(network).to have_received(:create_lbaas_pool_member).with('pool-id', '10.10.10.10', 8080, subnet_id: 'sub-net-id')
- expect(loadbalancer_membership.membership_id).to eq('id')
- expect(loadbalancer_membership.port).to eq(8080)
- expect(loadbalancer_membership.name).to eq('my-lb-pool')
- expect(loadbalancer_membership.pool_id).to eq('pool-id')
- end
- end
-
- context 'when ip address cannot be determined' do
- before(:each) do
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:gateway_ip).and_raise(Bosh::Clouds::VMCreationFailed.new(false), 'Original message.')
- end
-
- it 'raises an error' do
- expect {
- subject.add_vm_to_pool(server, network_spec, pool)
- }.to raise_error(Bosh::Clouds::VMCreationFailed, "VM with id '1234' cannot be attached to load balancer pool 'my-lb-pool'. Reason: Original message.")
- end
- end
-
- context 'when multiple subnet ids match' do
- let(:network_spec) {
- {
- 'network_a' => manual_network_spec(net_id: 'net-id', ip: '10.10.10.10'),
- }
- }
-
- it 'errors' do
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:matching_gateway_subnet_ids_for_ip).and_return(['subnet-id', 'other-subnet-id'])
- expect {
- subject.add_vm_to_pool(server, network_spec, pool)
- }.to raise_error(Bosh::Clouds::VMCreationFailed, /Reason: In network 'net-id' more than one subnet CIDRs match the IP '10\.10\.10\.10'/)
- end
- end
-
- context 'when no subnet id match or no subnet exists' do
- let(:network_spec) {
- {
- 'network_a' => manual_network_spec(net_id: 'net-id', ip: '10.10.10.10'),
- }
- }
-
- it 'errors' do
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:matching_gateway_subnet_ids_for_ip).and_return([])
- expect {
- subject.add_vm_to_pool(server, network_spec, pool)
- }.to raise_error(Bosh::Clouds::VMCreationFailed, /Network 'net-id' does not contain any subnet to match the IP '10\.10\.10\.10'/)
- end
- end
- end
-
- describe '#remove_vm_from_pool' do
- let(:pool_id) { 'pool-id' }
- let(:membership_id) { 'membership-id' }
-
- before do
- allow(network).to receive(:delete_lbaas_pool_member)
- end
-
- it 'deletes load balancer pool membership' do
- loadbalancer = instance_double(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource, 'loadbalancer', provisioning_status: 'ACTIVE')
- allow(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource).to receive(:new).and_return(loadbalancer)
-
- subject.remove_vm_from_pool(pool_id, membership_id)
-
- expect(network).to have_received(:delete_lbaas_pool_member).with(pool_id, membership_id)
- expect(network).to have_received(:get_lbaas_pool).with('pool-id')
- expect(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource).to have_received(:new).with('loadbalancer-id', openstack)
- expect(openstack).to have_received(:wait_resource).with(loadbalancer, :active, :provisioning_status).twice
- end
-
- it 'runs into time out while waiting for load balancer to be active before deleting pool member' do
- loadbalancer = instance_double(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource, 'loadbalancer', provisioning_status: 'PENDING_UPDATE')
- allow(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource).to receive(:new).and_return(loadbalancer)
- allow(openstack).to receive(:wait_resource).with(loadbalancer, :active, :provisioning_status).and_raise(Bosh::Clouds::CloudError.new('Timed out waiting for load balancer to be ACTIVE'))
-
- expect {
- subject.remove_vm_from_pool(pool_id, membership_id)
- }.to raise_error(Bosh::Clouds::CloudError)
-
- expect(network).to_not have_received(:delete_lbaas_pool_member)
- expect(network).to have_received(:get_lbaas_pool).with('pool-id')
- expect(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource).to have_received(:new).with('loadbalancer-id', openstack)
- expect(openstack).to have_received(:wait_resource).with(loadbalancer, :active, :provisioning_status)
- end
-
- context 'when load balancer resources are not in a valid state e.g. pool has more than one loadbalancer associated' do
- before(:each) do
- allow(subject).to receive(:loadbalancer_id).and_raise(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource::NotSupportedConfiguration)
- end
-
- it 'raises an error' do
- expect {
- subject.remove_vm_from_pool(pool_id, membership_id)
- }.to raise_error(Bosh::Clouds::CloudError, /Deleting load balancer pool membership with pool_id 'pool-id' and membership_id 'membership-id' failed/)
-
- expect(network).to_not have_received(:delete_lbaas_pool_member)
- end
- end
-
- context 'when load balancer resource cannot be found' do
- before(:each) do
- allow(subject).to receive(:loadbalancer_id).and_raise(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource::NotFound)
- end
-
- it 'does not raise' do
- expect {
- subject.remove_vm_from_pool(pool_id, membership_id)
- }.to_not raise_error
- end
-
- it 'does not try to delete the membership' do
- subject.remove_vm_from_pool(pool_id, membership_id)
-
- expect(network).to_not have_received(:delete_lbaas_pool_member)
- end
-
- it 'logs error' do
- subject.remove_vm_from_pool(pool_id, membership_id)
-
- expect(logger).to have_received(:debug).with(/Skipping deletion of load balancer pool membership because load balancer resource cannot be found./)
- end
- end
-
- context 'when membership not found' do
- before do
- allow(network).to receive(:delete_lbaas_pool_member).and_raise(Fog::OpenStack::Network::NotFound)
- end
-
- it 'does not raise' do
- expect {
- subject.remove_vm_from_pool(pool_id, membership_id)
- }.to_not raise_error
- end
-
- it 'logs error' do
- expect {
- subject.remove_vm_from_pool(pool_id, membership_id)
- }.to_not raise_error
-
- expect(logger).to have_received(:debug).with("Skipping deletion of load balancer pool membership. Member with pool_id 'pool-id' and membership_id 'membership-id' does not exist.")
- end
- end
-
- context 'when membership deletion fails' do
- it 're-raises as CloudError' do
- allow(network).to receive(:delete_lbaas_pool_member).and_raise(Fog::OpenStack::Network::Error.new('BOOM!!!'))
-
- expect {
- subject.remove_vm_from_pool(pool_id, membership_id)
- }.to raise_error(Bosh::Clouds::CloudError, "Deleting load balancer pool membership with pool_id 'pool-id' and membership_id 'membership-id' failed. Reason: Fog::OpenStack::Network::Error BOOM!!!")
- end
- end
-
- it_behaves_like('changing load balancer resource') do
- let(:success_response) { double('lb_member', body: { 'member' => { 'id' => 'member-id' } }) }
- let(:openstack_method_name) { :delete_lbaas_pool_member }
- let(:action) {
- -> { subject.remove_vm_from_pool(pool_id, membership_id) }
- }
- end
- end
-
- describe '#loadbalancer_id' do
- let(:pool_id) { 'pool-id' }
-
- context 'when pool exists' do
- it 'returns the loadbalancer_id' do
- loadbalancer_id = subject.loadbalancer_id(pool_id)
-
- expect(loadbalancer_id).to eq('loadbalancer-id')
- end
-
- context 'when pool has no loadbalancer associated' do
- let(:lb_pool) { double('lb_pool', body: { 'pool' => { 'loadbalancers' => [] } }) }
-
- it 'raises an error' do
- expect {
- subject.loadbalancer_id(pool_id)
- }.to raise_error Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource::NotFound, "No load balancers associated with load balancer pool 'pool-id'"
- end
- end
-
- context 'when pool has more than one loadbalancer associated' do
- let(:lb_pool) { double('lb_pool', body: { 'pool' => { 'loadbalancers' => [{ 'id' => 'loadbalancer-id-1' }, { 'id' => 'loadbalancer-id-2' }] } }) }
-
- it 'raises an error' do
- expect {
- subject.loadbalancer_id(pool_id)
- }.to raise_error(Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource::NotSupportedConfiguration, "More than one load balancer is associated with load balancer pool 'pool-id'. It is not possible to verify the status of the load balancer responsible for the pool membership.")
- end
- end
-
- context 'when pool does not have loadbalancer property (before Newton)' do
- context 'when listener does exist' do
- let(:lb_pool) { double('lb_pool', body: { 'pool' => { 'loadbalancers' => nil, 'listeners' => [{ 'id' => 'listener-id' }] } }) }
-
- it 'returns loadbalancer id ' do
- loadbalancer_id = subject.loadbalancer_id(pool_id)
-
- expect(loadbalancer_id).to eq('loadbalancer-id')
- expect(network).to have_received(:get_lbaas_listener).with('listener-id')
- end
- end
-
- context 'when listener does not exist' do
- let(:lb_pool) { double('lb_pool', body: { 'pool' => { 'loadbalancers' => nil, 'listeners' => [] } }) }
-
- it 'raises an error' do
- expect {
- subject.loadbalancer_id(pool_id)
- }.to raise_error Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource::NotFound, "No listeners associated with load balancer pool 'pool-id'"
- end
- end
-
- context 'when multiple listeners do exist' do
- let(:lb_pool) do
- double('lb_pool', body: { 'pool' => { 'loadbalancers' => nil, 'listeners' => [
- { 'id' => 'listener-id' },
- { 'id' => 'other-listener-id' },
- ] } })
- end
-
- it 'raises an error' do
- expect {
- subject.loadbalancer_id(pool_id)
- }.to raise_error Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource::NotSupportedConfiguration, "More than one listener is associated with load balancer pool 'pool-id'. It is not possible to verify the status of the load balancer responsible for the pool membership."
- end
- end
- end
- end
-
- context 'when pool does not exist' do
- before(:each) do
- allow(network).to receive(:get_lbaas_pool).and_raise(Fog::OpenStack::Network::NotFound.new, 'some-error-message')
- end
-
- it 'raises an error' do
- expect {
- subject.loadbalancer_id(pool_id)
- }.to raise_error Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource::NotFound, "Load balancer ID could not be determined because pool with ID 'pool-id' was not found. Reason: some-error-message"
- end
- end
- end
-
- describe '#cleanup_memberships' do
- let(:server_metadata) {
- {
- 'lbaas_pool_0' => 'pool-id-0/membership-id-0',
- 'lbaas_pool_1' => 'pool-id-1/membership-id-1',
- 'index' => 0,
- 'job' => 'bosh',
- }
- }
-
- it 'removes all memberships found in server metadata' do
- allow(network).to receive(:delete_lbaas_pool_member).with('pool-id-0', 'membership-id-0')
- allow(network).to receive(:delete_lbaas_pool_member).with('pool-id-1', 'membership-id-1')
-
- subject.cleanup_memberships(server_metadata)
-
- expect(network).to have_received(:delete_lbaas_pool_member).with('pool-id-0', 'membership-id-0')
- expect(network).to have_received(:delete_lbaas_pool_member).with('pool-id-1', 'membership-id-1')
- end
-
- it 're-raises the exception' do
- allow(network).to receive(:delete_lbaas_pool_member).and_raise(Fog::OpenStack::Network::Error.new('BOOM!!!'))
-
- expect {
- subject.cleanup_memberships(server_metadata)
- }.to raise_error(Bosh::Clouds::CloudError)
- end
- end
-
- describe Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource do
- let(:subject) { Bosh::OpenStackCloud::LoadbalancerConfigurator::LoadBalancerResource.new('loadbalancer-id', openstack) }
- let(:loadbalancer) { double('loadbalancer', body: { 'loadbalancer' => { 'id' => 'loadbalancer-id', 'provisioning_status' => 'ACTIVE' } }) }
-
- describe '#provisioning_status' do
- it 'returns the status of the loadbalancer' do
- allow(network).to receive(:get_lbaas_loadbalancer).and_return(loadbalancer)
-
- provisioning_status = subject.provisioning_status
-
- expect(provisioning_status).to eq('ACTIVE')
- expect(network).to have_received(:get_lbaas_loadbalancer).with('loadbalancer-id')
- end
- end
-
- describe '#id' do
- it 'returns the id of the loadbalancer' do
- expect(subject.id).to eq('loadbalancer-id')
- end
- end
-
- describe '#reload' do
- it 'returns the id of the loadbalancer' do
- expect(subject.reload).to eq(true)
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/manual_network_spec.rb b/src/bosh_openstack_cpi/spec/unit/manual_network_spec.rb
deleted file mode 100644
index bfd09adbf..000000000
--- a/src/bosh_openstack_cpi/spec/unit/manual_network_spec.rb
+++ /dev/null
@@ -1,260 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::ManualNetwork do
- subject { Bosh::OpenStackCloud::ManualNetwork.new(network_name, network_spec) }
- let(:openstack) { double(Bosh::OpenStackCloud::Openstack) }
-
- before { allow(openstack).to receive(:with_openstack) { |&block| block.call } }
-
- describe '#initialize' do
- context 'when spec is not a hash' do
- let(:network_name) { 'default' }
- let(:network_spec) { [] }
- it 'should fail' do
- expect {
- subject
- }.to raise_error ArgumentError, /Invalid spec, Hash expected/
- end
- end
-
- context 'when spec is a hash' do
- let(:network_name) { 'default' }
- let(:network_spec) {
- network_spec = manual_network_spec
- network_spec['ip'] = '172.20.214.10'
- network_spec
- }
-
- it 'should set the IP' do
- expect(subject.private_ip).to eq('172.20.214.10')
- end
- end
- end
-
- describe '#prepare' do
- let(:network_name) { 'network_a' }
- let(:network_spec) { manual_network_spec(ip: '10.0.0.1') }
- let(:security_groups_to_be_used) { ['default-security-group-id'] }
-
- context "with 'use_nova_networking=false'" do
- before(:each) do
- port_result_net = double('ports1', id: '117717c1-81cb-4ac4-96ab-99aaf1be9ca8', network_id: 'net', mac_address: 'AA:AA:AA:AA:AA:AA')
- allow(openstack).to receive(:network).and_return(neutron)
- allow(ports).to receive(:create).and_return(port_result_net)
- allow(neutron).to receive(:ports).and_return(ports)
- end
-
- let(:neutron) { double(Fog::Network) }
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack, use_nova_networking?: false) }
- let(:ports) { double('Fog::OpenStack::Network::Ports') }
-
- it 'adds port_ids to nic' do
- subject.prepare(openstack, security_groups_to_be_used)
-
- expect(subject.nic).to eq('net_id' => 'net', 'port_id' => '117717c1-81cb-4ac4-96ab-99aaf1be9ca8')
- end
-
- it 'adds MAC addresses to network spec' do
- subject.prepare(openstack, security_groups_to_be_used)
-
- expect(subject.spec['mac']).to eq('AA:AA:AA:AA:AA:AA')
- end
-
- it 'sets the given security groups for the port' do
- subject.prepare(openstack, security_groups_to_be_used)
-
- expect(ports).to have_received(:create).once.with(network_id: anything, fixed_ips: anything, security_groups: ['default-security-group-id'])
- end
-
- context 'allowed_address_pair' do
- context 'is configured to disable IP source check' do
- let(:network_spec) { manual_network_spec(ip: '10.0.0.1', overwrites: { 'cloud_properties' => { "security_groups"=>["default"], "net_id"=>"net",'vrrp_port_check'=> false} }) }
- let(:allowed_address_pairs) { '1.1.1.1/0' }
-
- before(:each) do
- subject.allowed_address_pairs = allowed_address_pairs
- end
-
- it 'configures to disable port check allowed_address_pair' do
- allow(ports).to receive(:all)
- subject.prepare(openstack, security_groups_to_be_used)
-
- expect(ports).to_not have_received(:all).with(fixed_ips: "ip_address=#{allowed_address_pairs}")
- end
- end
-
- context 'is configured' do
- let(:network_spec) { manual_network_spec(ip: '10.0.0.1') }
- let(:allowed_address_pairs) { '10.0.0.10' }
-
- before(:each) do
- subject.allowed_address_pairs = allowed_address_pairs
- end
-
- it 'configures allowed_address_pair to the port' do
- allow(ports).to receive(:all).and_return([{ 'name' => 'vrrp-port' }])
-
- subject.prepare(openstack, security_groups_to_be_used)
-
- expect(ports).to have_received(:create).once.with(network_id: anything, fixed_ips: anything, security_groups: ['default-security-group-id'], allowed_address_pairs: [{ ip_address: allowed_address_pairs }])
- expect(ports).to have_received(:all).with(fixed_ips: "ip_address=#{allowed_address_pairs}")
- end
-
- context 'and vrrp port does not exist' do
- it 'raises an error' do
- allow(ports).to receive(:all).and_return([])
-
- expect {
- subject.prepare(openstack, security_groups_to_be_used)
- }.to raise_error(Bosh::Clouds::CloudError, "Configured VRRP port with ip '#{allowed_address_pairs}' does not exist.")
- end
- end
- end
-
- context 'is not configured' do
- it 'configures allowed_address_pair to the port' do
- subject.prepare(openstack, security_groups_to_be_used)
-
- expect(ports).to have_received(:create).once.with(network_id: anything, fixed_ips: anything, security_groups: ['default-security-group-id'])
- end
- end
- end
-
- context 'when Excon::Error::Conflict is raised' do
- let(:error) { Excon::Error::Conflict.new('some error message') }
- let(:network_spec) { manual_network_spec(net_id: 'net', ip: '10.0.0.1') }
- let(:all_ports) {
- [
- double('port1', id: 'id-1', network_id: 'net', status: 'DOWN', device_id: '', device_owner: ''),
- double('port2', id: 'id-2', network_id: 'net', status: 'ACTIVE', device_id: '', device_owner: ''),
- double('port3', id: 'id-3', network_id: 'net', status: 'DOWN', device_id: 'd_id', device_owner: ''),
- double('port4', id: 'id-4', network_id: 'net', status: 'DOWN', device_id: '', device_owner: 'd_owner'),
- double('port5', id: 'id-5', network_id: 'net', status: 'ACTIVE', device_id: 'd_id', device_owner: 'd_owner'),
- double('port6', id: 'id-6', network_id: 'net', status: 'DOWN', device_id: '', device_owner: ''),
- double('port7', id: 'id-7', network_id: 'net', status: 'DOWN', device_id: 'd_id', device_owner: 'd_owner'),
- double('port8', id: 'id-8', network_id: 'net', status: 'ACTIVE', device_id: 'd_id', device_owner: ''),
- double('port9', id: 'id-9', network_id: 'net', status: 'ACTIVE', device_id: '', device_owner: 'd_owner'),
- ]
- }
- let(:new_port) { double('new-port', id: 'new-port-id', mac_address: 'mac') }
-
- before(:each) do
- retried = false
- allow(ports).to receive(:create) do
- unless retried
- retried = true
- raise error
- end
-
- new_port
- end
-
- allow(ports).to receive(:all).and_return(all_ports)
- allow(openstack).to receive(:parse_openstack_response).and_return('type' => 'IpAddressAlreadyAllocated')
- allow(Bosh::OpenStackCloud::NetworkConfigurator).to receive(:cleanup_ports)
- end
-
- it 'retrieves ports with the correct filter' do
- subject.prepare(openstack, [])
-
- expect(ports).to have_received(:all).with(fixed_ips: ["ip_address=10.0.0.1", "network_id=net"])
- end
-
- it 'deletes only detached ports' do
- subject.prepare(openstack, [])
-
- expect(Bosh::OpenStackCloud::NetworkConfigurator).to have_received(:cleanup_ports)
- .once.with(openstack, %w[id-1 id-6])
- end
-
- context 'when it has retried once and the error persists' do
- it 're-raises the error' do
- allow(ports).to receive(:create).and_raise(error)
- allow(openstack).to receive(:parse_openstack_response).and_return('type' => 'IpAddressAlreadyAllocated')
- allow(ports).to receive(:all).and_return([])
-
- expect {
- subject.prepare(openstack, [])
- }.to raise_error(error)
-
- expect(ports).to have_received(:create).exactly(2).times
- expect(ports).to have_received(:all).once
- end
- end
- end
- end
-
- context "with 'use_nova_networking=true'" do
- let(:network_spec) { manual_network_spec(ip: '10.0.0.1') }
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack, use_nova_networking?: true, network: double('Fog::Network')) }
-
- it 'does not use Fog::Network' do
- subject.prepare(openstack, security_groups_to_be_used)
-
- expect(openstack).to_not have_received(:network)
- end
-
- it "adds 'v4_fixed_ip' to nic" do
- subject.prepare(openstack, security_groups_to_be_used)
-
- expect(subject.nic).to eq('net_id' => 'net', 'v4_fixed_ip' => '10.0.0.1')
- end
- end
- end
-
- describe '#cleanup' do
- let(:network_name) { 'network_a' }
- let(:network_spec) { manual_network_spec(ip: '10.0.0.1') }
-
- context "with 'use_nova_networking=false'" do
- before(:each) do
- allow(openstack).to receive(:network).and_return(neutron)
- allow(ports).to receive(:create).with({network_id: 'net', fixed_ips: [{ ip_address: '10.0.0.1' }], security_groups: []}).and_return(port)
- allow(ports).to receive(:get).with('117717c1-81cb-4ac4-96ab-99aaf1be9ca8').and_return(port)
- allow(neutron).to receive(:ports).and_return(ports)
- end
-
- let(:port) { double('ports1', id: '117717c1-81cb-4ac4-96ab-99aaf1be9ca8', network_id: 'net', mac_address: 'AA:AA:AA:AA:AA:AA', destroy: nil) }
- let(:neutron) { double(Fog::Network) }
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack, use_nova_networking?: false, network: double('Fog::Network')) }
- let(:ports) { double('Fog::OpenStack::Network::Ports') }
-
- before(:each) do
- subject.prepare(openstack, [])
- end
-
- it 'should delete port' do
- subject.cleanup(openstack)
-
- expect(port).to have_received(:destroy)
- end
-
- context 'when ports are destroyed by OpenStack (versions < Mitaka)' do
- before(:each) do
- allow(ports).to receive(:get).with('117717c1-81cb-4ac4-96ab-99aaf1be9ca8').and_return(nil)
- end
-
- it 'should not fail try to destroy port' do
- expect {
- subject.cleanup(openstack)
- }.to_not raise_error
- end
- end
- end
-
- context "with 'use_nova_networking=true'" do
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack, use_nova_networking?: true, network: double('Fog::Network')) }
- let(:security_groups_to_be_used) { [] }
-
- before(:each) do
- subject.prepare(openstack, [])
- end
-
- it 'should not call Fog::Network' do
- subject.cleanup(openstack)
-
- expect(openstack).to_not have_received(:network)
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/network_configurator_spec.rb b/src/bosh_openstack_cpi/spec/unit/network_configurator_spec.rb
deleted file mode 100644
index 9cd0a0e8a..000000000
--- a/src/bosh_openstack_cpi/spec/unit/network_configurator_spec.rb
+++ /dev/null
@@ -1,667 +0,0 @@
-require 'spec_helper'
-require 'fog/openstack/compute/models/server'
-
-describe Bosh::OpenStackCloud::NetworkConfigurator do
- def set_security_groups(spec, security_groups)
- spec['cloud_properties'] ||= {}
- spec['cloud_properties']['security_groups'] = security_groups
- end
-
- def set_nics(spec, _net_id)
- spec['cloud_properties'] ||= {}
- end
-
- let(:several_manual_networks) do
- {
- 'network_a' => manual_network_spec(ip: '10.0.0.1'),
- 'network_b' => manual_network_spec(net_id: 'bar', ip: '10.0.0.2'),
- }
- end
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack) }
- let(:spec) {
- {
- 'network_a' => { 'type' => 'dynamic' },
- }
- }
-
-
- before { allow(openstack).to receive(:with_openstack) { |&block| block.call } }
-
- it 'exposes network_spec as attribute' do
- nc = Bosh::OpenStackCloud::NetworkConfigurator.new(spec)
- expect(nc.network_spec).to eq(spec)
- end
-
- describe '#initialize' do
- context 'when spec is not a hash' do
- it 'should raise an error' do
- expect {
- Bosh::OpenStackCloud::NetworkConfigurator.new('foo')
- }.to raise_error ArgumentError, /Invalid spec, Hash expected,/
- end
- end
-
- context 'when no net_id defined in manual networks' do
- it 'should raise a CloudError' do
- spec = {}
- spec['network_b'] = manual_network_without_netid_spec
-
- expect {
- Bosh::OpenStackCloud::NetworkConfigurator.new(spec)
- }.to raise_error Bosh::Clouds::CloudError, 'Manual network must have net_id'
- end
- end
-
- context 'when several manual networks have the same net_id' do
- it 'should raise a CloudError' do
- spec = several_manual_networks
- spec['network_b']['cloud_properties']['net_id'] = 'net'
-
- expect {
- Bosh::OpenStackCloud::NetworkConfigurator.new(spec)
- }.to raise_error Bosh::Clouds::CloudError, 'Manual network with id net is already defined'
- end
- end
-
- context 'when several dynamic networks are defined' do
- it 'should raise a CloudError' do
- spec = {}
- spec['network_a'] = dynamic_network_spec
- spec['network_b'] = dynamic_network_spec
-
- expect {
- Bosh::OpenStackCloud::NetworkConfigurator.new(spec)
- }.to raise_error Bosh::Clouds::CloudError, 'Only one dynamic network per instance should be defined'
- end
- end
-
- context 'when several VIP networks are defined' do
- it 'should raise a CloudError' do
- spec = {}
- spec['network_a'] = vip_network_spec
- spec['network_b'] = vip_network_spec
-
- expect {
- Bosh::OpenStackCloud::NetworkConfigurator.new(spec)
- }.to raise_error Bosh::Clouds::CloudError, 'Only one VIP network per instance should be defined'
- end
- end
-
- context 'when only VIP network is defined' do
- it 'should raise a CloudError' do
- spec = {}
- spec['network_a'] = vip_network_spec
-
- expect {
- Bosh::OpenStackCloud::NetworkConfigurator.new(spec)
- }.to raise_error Bosh::Clouds::CloudError, 'At least one dynamic or manual network should be defined'
- end
- end
-
- context 'when vrrp' do
- context 'is configured' do
- it 'should set allowed_address_pair to the default network' do
- vrrp_port = '10.0.0.10'
- network_configurator = Bosh::OpenStackCloud::NetworkConfigurator.new({
- 'network_a' => manual_network_spec(ip: '10.0.0.1'),
- 'network_b' => manual_network_spec(net_id: 'bar', ip: '10.0.0.2', default: ['gateway']),
- 'network_c' => dynamic_network_spec,
- }, vrrp_port)
-
- network_configurator.networks.each do |network|
- if network.name == 'network_b'
- expect(network.allowed_address_pairs).to eq(vrrp_port)
- else
- expect(network.allowed_address_pairs).to eq(nil)
- end
- end
- end
- end
-
- context 'is not configured' do
- it 'should set allowed_address_pair to the default network' do
- network_configurator = Bosh::OpenStackCloud::NetworkConfigurator.new(
- 'network_a' => manual_network_spec(ip: '10.0.0.1'),
- 'network_b' => manual_network_spec(net_id: 'bar', ip: '10.0.0.2', default: ['gateway']),
- 'network_c' => dynamic_network_spec,
- )
-
- network_configurator.networks.each do |network|
- expect(network.allowed_address_pairs).to eq(nil)
- end
- end
- end
- end
- end
-
- describe '#security_groups' do
- context 'when security_groups are defined in all networks' do
- it 'extracts all unique ones from all networks' do
- spec = {}
- spec['network_a'] = dynamic_network_spec
- set_security_groups(spec['network_a'], %w[foo])
- spec['network_b'] = vip_network_spec
- set_security_groups(spec['network_b'], %w[bar])
- spec['network_c'] = manual_network_spec
- set_security_groups(spec['network_c'], %w[foo])
-
- nc = Bosh::OpenStackCloud::NetworkConfigurator.new(spec)
- expect(nc.security_groups).to eq(%w[bar foo])
- end
- end
-
- context 'when security_groups is not an array' do
- it 'should raise an ArgumentError' do
- spec = {}
- spec['network_a'] = dynamic_network_spec
- set_security_groups(spec['network_a'], 'foo')
-
- expect {
- Bosh::OpenStackCloud::NetworkConfigurator.new(spec)
- }.to raise_error ArgumentError, 'security groups must be an Array'
- end
- end
- end
-
- describe '#nics' do
- context 'when dynamic network' do
- it 'should extract net_id' do
- spec = {}
- spec['network_a'] = dynamic_network_spec
- spec['network_a']['cloud_properties']['net_id'] = 'foo'
-
- nc = Bosh::OpenStackCloud::NetworkConfigurator.new(spec)
- expect(nc.nics).to eq([{ 'net_id' => 'foo' }])
- end
-
- it 'should not extract ip address' do
- spec = {}
- spec['network_a'] = dynamic_network_spec
- spec['network_a']['ip'] = '10.0.0.1'
- spec['network_a']['cloud_properties']['net_id'] = 'foo'
-
- nc = Bosh::OpenStackCloud::NetworkConfigurator.new(spec)
- expect(nc.nics).to eq([{ 'net_id' => 'foo' }])
- end
- end
-
- context 'when manual network' do
- let(:nc) do
- manual_network = { 'network_a' => manual_network_spec(ip: '10.0.0.1') }
- Bosh::OpenStackCloud::NetworkConfigurator.new(manual_network)
- end
-
- context 'and no port id is available in network spec' do
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack, use_nova_networking?: true) }
- it 'should set fixed ip only' do
- nc.prepare(openstack)
-
- expect(nc.nics).to eq([{ 'net_id' => 'net', 'v4_fixed_ip' => '10.0.0.1' }])
- end
- end
-
- context 'and port id is available in network spec' do
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack, use_nova_networking?: false) }
- before(:each) do
- allow_any_instance_of(Bosh::OpenStackCloud::ManualNetwork).to receive(:nic).and_return('net_id' => 'net', 'port_id' => '117717c1-81cb-4ac4-96ab-99aaf1be9ca8')
- allow_any_instance_of(Bosh::OpenStackCloud::ManualNetwork).to receive(:prepare)
- end
-
- it 'should set port id only' do
- nc.prepare(openstack)
-
- expect(nc.nics).to eq([{ 'net_id' => 'net', 'port_id' => '117717c1-81cb-4ac4-96ab-99aaf1be9ca8' }])
- end
- end
-
- context 'when multiple networks' do
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack, use_nova_networking?: true) }
- it 'should extract net_id and IP address from all' do
- nc = Bosh::OpenStackCloud::NetworkConfigurator.new(several_manual_networks)
- nc.prepare(openstack)
-
- expect(nc.nics).to eq([
- { 'net_id' => 'net', 'v4_fixed_ip' => '10.0.0.1' },
- { 'net_id' => 'bar', 'v4_fixed_ip' => '10.0.0.2' },
- ])
- end
- end
- end
- end
-
- describe '#prepare' do
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack, use_nova_networking?: true) }
- let(:networks) { [] }
-
- before(:each) do
- [Bosh::OpenStackCloud::ManualNetwork, Bosh::OpenStackCloud::DynamicNetwork].each do |class_name|
- allow(class_name).to receive(:new) do |name, spec|
- network = instance_double(class_name, prepare: nil, name:, spec:)
- networks << network
- network
- end
- end
- end
-
- it 'should delegate to all private networks' do
- nc = Bosh::OpenStackCloud::NetworkConfigurator.new(
- 'network_a' => manual_network_spec(ip: '10.0.0.1'),
- 'network_b' => manual_network_spec(net_id: 'bar', ip: '10.0.0.2'),
- 'network_c' => dynamic_network_spec,
- )
-
- nc.prepare(openstack)
-
- networks.each do |network|
- expect(network).to have_received(:prepare).with(anything, anything)
- end
- end
- end
-
- describe '#pick_groups' do
- let(:default_security_groups) { 'fake-group' }
- let(:resource_pool_groups) { 'fake-group' }
- let(:security_groups) { [double('security_-group', name: 'group')] }
- let(:openstack_security_groups) { instance_double(Bosh::OpenStackCloud::SecurityGroups) }
-
- before(:each) do
- allow(Bosh::OpenStackCloud::SecurityGroups).to receive(:new).with(openstack).and_return(openstack_security_groups)
- end
-
- it 'picks a group and logs it' do
- allow(openstack_security_groups).to receive(:select_and_retrieve).and_return(security_groups)
- nc = Bosh::OpenStackCloud::NetworkConfigurator.new(spec)
- nc.pick_groups(openstack, default_security_groups, resource_pool_groups)
- expect(openstack_security_groups).to have_received(:select_and_retrieve).with(default_security_groups,
- [],
- resource_pool_groups)
- expect(Bosh::Clouds::Config.logger).to have_received(:debug).with("Using security groups: `group'")
- end
- end
-
- describe '#cleanup' do
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack, use_nova_networking?: true) }
- let(:networks) { [] }
-
- before(:each) do
- [Bosh::OpenStackCloud::ManualNetwork, Bosh::OpenStackCloud::DynamicNetwork].each do |class_name|
- allow(class_name).to receive(:new) do
- network = instance_double(class_name, cleanup: nil)
- networks << network
- network
- end
- end
- end
-
- it 'should delegate to all private networks' do
- nc = Bosh::OpenStackCloud::NetworkConfigurator.new(
- 'network_a' => manual_network_spec(ip: '10.0.0.1'),
- 'network_b' => manual_network_spec(net_id: 'bar', ip: '10.0.0.2'),
- 'network_c' => dynamic_network_spec,
- )
-
- nc.cleanup(openstack)
-
- networks.each do |network|
- expect(network).to have_received(:cleanup)
- end
- end
- end
-
- describe '#configure' do
- let(:vip_network) do
- network = double('vip_network')
- allow(Bosh::OpenStackCloud::VipNetwork).to receive(:new).and_return(network)
- network
- end
- let(:dynamic_network) do
- network = double('dynamic_network')
- allow(Bosh::OpenStackCloud::DynamicNetwork).to receive(:new).and_return(network)
- network
- end
- let(:manual_network) do
- network = double('manual_network')
- allow(Bosh::OpenStackCloud::ManualNetwork).to receive(:new).and_return(network)
- network
- end
-
- context 'With vip network' do
- let(:network_spec) do
- {
- 'network_a' => dynamic_network_spec,
- 'network_b' => manual_network_spec(net_id: 'net_b', default: ['gateway']),
- 'network_c' => vip_network_spec,
- }
- end
-
- it 'configures the vip network and all other networks too' do
- expect(vip_network).to receive(:configure).with(anything, anything, 'net_b')
- expect(manual_network).to receive(:configure)
- expect(dynamic_network).to receive(:configure)
- network_configurator = Bosh::OpenStackCloud::NetworkConfigurator.new(network_spec)
- network_configurator.configure(nil, nil)
- end
- end
-
- context 'when no vip network' do
- let(:network_spec) do
- {
- 'network_a' => dynamic_network_spec,
- 'network_b' => manual_network_spec,
- }
- end
-
- context 'when no floating IP is associated' do
- it 'should not configure the vip_network' do
- expect(manual_network).to receive(:configure)
- expect(dynamic_network).to receive(:configure)
- expect(vip_network).to_not receive(:configure)
-
- network_configurator = Bosh::OpenStackCloud::NetworkConfigurator.new(network_spec)
- network_configurator.configure(nil, nil)
- end
- end
- end
- end
-
- describe '.port_ids' do
- let(:neutron) { double(Fog::Network) }
-
- context 'when neutron is available' do
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack, use_nova_networking?: false) }
-
- it 'should return all device ports' do
- port = double('port', id: 'port_id')
- ports = double('ports', all: [])
- allow(openstack).to receive(:network).and_return(neutron)
- allow(neutron).to receive(:ports).and_return(ports)
- allow(ports).to receive(:all).with(device_id: 'server_id').and_return([port])
-
- expect(Bosh::OpenStackCloud::NetworkConfigurator.port_ids(openstack, 'server_id')).to eq(['port_id'])
- end
- end
-
- context 'when neutron returns error or is not available' do
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack, use_nova_networking?: true) }
-
- it 'should return no ports' do
- allow(openstack).to receive(:network)
-
- expect(Bosh::OpenStackCloud::NetworkConfigurator.port_ids(openstack, 'server_id')).to eq([])
-
- expect(openstack).to_not have_received(:network)
- end
- end
- end
-
- describe '.cleanup_ports' do
- let(:neutron) { double(Fog::Network) }
- let(:port_a) { double('port_a', id: 'port_a_id') }
- let(:port_b) { double('port_b', id: 'port_b_id') }
-
- context 'when neutron is available' do
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack, use_nova_networking?: false) }
- it 'should delete all ports' do
- ports = double('ports')
- allow(openstack).to receive(:network).and_return(neutron).exactly(2).times
- allow(neutron).to receive(:ports).and_return(ports).exactly(2).times
- allow(ports).to receive(:get).with('port_a_id').and_return(port_a)
- allow(ports).to receive(:get).with('port_b_id').and_return(port_b)
- allow(port_a).to receive(:destroy)
- allow(port_b).to receive(:destroy)
-
- expect(Bosh::OpenStackCloud::NetworkConfigurator.cleanup_ports(openstack, %w[port_a_id port_b_id]))
- end
-
- it 'should not fail on already deleted ports' do
- ports = double('ports')
- allow(openstack).to receive(:network).and_return(neutron).exactly(2).times
- allow(neutron).to receive(:ports).and_return(ports).exactly(2).times
- allow(ports).to receive(:get).with('port_a_id').and_return(nil)
- allow(ports).to receive(:get).with('port_b_id').and_return(nil)
-
- expect {
- Bosh::OpenStackCloud::NetworkConfigurator.cleanup_ports(openstack, %w[port_a_id port_b_id])
- }.to_not raise_error
- end
- end
-
- context 'when neutron is not available' do
- let(:openstack) { instance_double(Bosh::OpenStackCloud::Openstack, use_nova_networking?: true) }
- it 'should not raise any error' do
- allow(openstack).to receive(:network)
-
- expect {
- Bosh::OpenStackCloud::NetworkConfigurator.cleanup_ports(openstack, [port_a, port_b])
- }.to_not raise_error
-
- expect(openstack).to_not have_received(:network)
- end
- end
- end
-
- describe '.get_gateway_network_id' do
- context 'only one network configured' do
- let(:network_spec) do
- {
- 'vip_network' => vip_network_spec,
- 'network_a' => manual_network_spec(net_id: 'net_id'),
- }
- end
-
- it 'should return network id' do
- expect(Bosh::OpenStackCloud::NetworkConfigurator.get_gateway_network_id(network_spec)).to eq('net_id')
- end
- end
-
- context 'multiple network configured' do
- let(:network_spec) do
- {
- 'network_a' => manual_network_spec(net_id: 'net_id_a'),
- 'network_b' => manual_network_spec(net_id: 'net_id_b', default: ['gateway']),
- 'vip_network' => vip_network_spec,
- }
- end
-
- it 'should return default gateway network id' do
- expect(Bosh::OpenStackCloud::NetworkConfigurator.get_gateway_network_id(network_spec)).to eq('net_id_b')
- end
- end
- end
-
- describe '.gateway_ip' do
- let(:server) { instance_double(Fog::OpenStack::Compute::Server) }
-
- context 'when gateway network is a manual network' do
- let(:network_spec) {
- {
- 'network_a' => manual_network_spec(net_id: 'net_id_a', ip: '10.10.10.10', default: ['gateway']),
- 'vip_network' => vip_network_spec,
- }
- }
-
- it 'returns the IP address from the gateway network' do
- expect(Bosh::OpenStackCloud::NetworkConfigurator.gateway_ip(network_spec, openstack, server)).to eq('10.10.10.10')
- end
-
- context 'when other private networks exist' do
- let(:network_spec) {
- {
- 'network_a' => manual_network_spec(net_id: 'net_id_a', ip: '10.10.10.10', default: ['gateway']),
- 'network_b' => manual_network_spec(net_id: 'net_id_b', ip: '20.20.20.20'),
- 'network_c' => dynamic_network_with_netid_spec,
- 'vip_network' => vip_network_spec,
- }
- }
-
- it 'returns the IP address from the gateway network' do
- expect(Bosh::OpenStackCloud::NetworkConfigurator.gateway_ip(network_spec, openstack, server)).to eq('10.10.10.10')
- end
- end
- end
-
- context 'when gateway network is a dynamic network' do
- let(:network_spec) {
- {
- 'network_a' => dynamic_network_with_netid_spec.merge('default' => ['gateway']),
- 'vip_network' => vip_network_spec,
- }
- }
-
- before(:each) do
- allow(server).to receive(:addresses).and_return('network_a' => [{ 'addr' => '10.20.20.20' }])
- end
-
- it 'returns the IP address from the gateway network by calling OpenStack' do
- expect(Bosh::OpenStackCloud::NetworkConfigurator.gateway_ip(network_spec, openstack, server)).to eq('10.20.20.20')
- expect(server).to have_received(:addresses)
- end
-
- context 'when other private networks exist' do
- let(:network_spec) {
- {
- 'network_a' => dynamic_network_with_netid_spec.merge('default' => ['gateway']),
- 'network_b' => manual_network_spec(net_id: 'net_id_b', ip: '10.10.10.10'),
- 'vip_network' => vip_network_spec,
- }
- }
-
- it 'raises an error' do
- expect {
- Bosh::OpenStackCloud::NetworkConfigurator.gateway_ip(network_spec, openstack, server)
- }.to raise_error(Bosh::Clouds::VMCreationFailed, 'Gateway IP address could not be determined. Gateway network is dynamic, but additional private networks exist.')
- end
- end
- end
- end
-
- describe '.matching_gateway_subnet_ids_for_ip' do
- let(:neutron) { double(Fog::OpenStack::Network) }
- let(:list_subnets_response) { double('list_subnets', body: { 'subnets' => subnets }) }
-
- before(:each) do
- allow(openstack).to receive(:network).and_return(neutron)
- allow(neutron).to receive(:list_subnets).and_return(list_subnets_response)
- end
-
- context 'when no sub-networks exist' do
- let(:network_spec) { { 'network_a' => manual_network_spec(net_id: 'net_id_a', ip: '10.10.10.10', default: ['gateway']) } }
- let(:subnets) { [] }
-
- it 'returns an empty list' do
- subnet_ids = Bosh::OpenStackCloud::NetworkConfigurator.matching_gateway_subnet_ids_for_ip(network_spec, openstack, '10.0.0.4')
-
- expect(subnet_ids.empty?).to be_truthy
- end
- end
-
- context 'when only one sub-network exists' do
- let(:network_spec) { { 'network_a' => manual_network_spec(net_id: 'net_id_a', ip: '10.10.10.10', default: ['gateway']) } }
- let(:subnets) { [{ 'id' => 'subnet_id', 'cidr' => '10.0.0.0/24' }] }
-
- it 'returns the gateway sub-network id' do
- subnet_ids = Bosh::OpenStackCloud::NetworkConfigurator.matching_gateway_subnet_ids_for_ip(network_spec, openstack, '10.0.0.2')
-
- expect(subnet_ids).to eq(['subnet_id'])
- end
- end
-
- context 'when more than one sub-network exist' do
- let(:network_spec) {
- {
- 'network_a' => manual_network_spec(net_id: 'net_id_a', ip: '10.10.10.10', default: ['gateway']),
- }
- }
- let(:subnets) { [{ 'id' => 'subnet_id', 'cidr' => '10.0.0.0/24' }, { 'id' => 'second_subnet_id', 'cidr' => '20.20.20.0/24' }] }
- it 'returns the sub-network id that matches the ip' do
- subnet_ids = Bosh::OpenStackCloud::NetworkConfigurator.matching_gateway_subnet_ids_for_ip(network_spec, openstack, '20.20.20.2')
-
- expect(subnet_ids).to eq(['second_subnet_id'])
- end
-
- context 'when sub-networks are with overlapping ranges' do
- let(:subnets) { [{ 'id' => 'subnet_id', 'cidr' => '10.0.0.0/16' }, { 'id' => 'second_subnet_id', 'cidr' => '10.0.0.0/24' }] }
-
- it 'returns a list of matching subnets' do
- subnet_ids = Bosh::OpenStackCloud::NetworkConfigurator.matching_gateway_subnet_ids_for_ip(network_spec, openstack, '10.0.0.4')
-
- expect(subnet_ids).to eq(%w[subnet_id second_subnet_id])
- end
- end
- end
- end
-
- describe '#check_preconditions' do
- context 'when multiple manual networks' do
- subject do
- network_spec = {
- 'network_a' => manual_network_spec(net_id: 'network_a', ip: '10.0.0.1'),
- 'network_b' => manual_network_spec(net_id: 'network_b', ip: '10.1.0.1'),
- }
- Bosh::OpenStackCloud::NetworkConfigurator.new(network_spec)
- end
-
- let(:use_nova_networking) { false }
- let(:use_config_drive) { true }
- let(:use_dhcp) { false }
-
- it 'does not raise error when preconditions are met' do
- expect {
- subject.check_preconditions(use_nova_networking, use_config_drive, use_dhcp)
- }.to_not raise_error
- end
-
- context "when 'use_nova_networking' is true" do
- let(:use_nova_networking) { true }
-
- it 'raises VMCreationFailed' do
- expect {
- subject.check_preconditions(use_nova_networking, use_config_drive, use_dhcp)
- }.to(raise_error { |e|
- expect(e).to be_a(Bosh::Clouds::VMCreationFailed)
- expect(e.ok_to_retry).to be(false)
- expect(e.message).to eq("Multiple manual networks can only be used with 'openstack.use_nova_networking=false'. Multiple networks require Neutron.")
- })
- end
- end
-
- context "when 'use_dhcp' is true" do
- let(:use_dhcp) { true }
-
- it 'raises VMCreationFailed' do
- expect {
- subject.check_preconditions(use_nova_networking, use_config_drive, use_dhcp)
- }.to(raise_error { |e|
- expect(e).to be_a(Bosh::Clouds::VMCreationFailed)
- expect(e.message).to eq("Multiple manual networks can only be used with 'openstack.use_dhcp=false' and 'openstack.config_drive=cdrom|disk'")
- })
- end
- end
-
- context "when 'config_drive' is not set" do
- let(:use_config_drive) { false }
-
- it 'raises VMCreationFailed' do
- expect {
- subject.check_preconditions(use_nova_networking, use_config_drive, use_dhcp)
- }.to(raise_error { |e|
- expect(e).to be_a(Bosh::Clouds::VMCreationFailed)
- expect(e.message).to eq("Multiple manual networks can only be used with 'openstack.use_dhcp=false' and 'openstack.config_drive=cdrom|disk'")
- })
- end
- end
- end
-
- context 'when single manual network' do
- subject do
- network_spec = { 'network_a' => manual_network_spec(ip: '10.0.0.1') }
- Bosh::OpenStackCloud::NetworkConfigurator.new(network_spec)
- end
- it 'does not raise' do
- expect {
- subject.check_preconditions(false, false, false)
- }.to_not raise_error
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/noop_registry_spec.rb b/src/bosh_openstack_cpi/spec/unit/noop_registry_spec.rb
deleted file mode 100644
index a3d8b91eb..000000000
--- a/src/bosh_openstack_cpi/spec/unit/noop_registry_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require 'spec_helper'
-
-shared_examples 'a registry' do
- it { is_expected.to respond_to(:update_settings).with(2).arguments }
- it { is_expected.to respond_to(:read_settings).with(1).arguments }
- it { is_expected.to respond_to(:delete_settings).with(1).arguments }
- it { is_expected.to respond_to(:endpoint) }
-end
-
-describe Bosh::OpenStackCloud::NoopRegistry do
- it_behaves_like 'a registry'
- describe '#read_settings' do
- it 'returns a hash' do
- expect(subject.read_settings('registry-key')).to be_instance_of(Hash)
- end
- end
-end
-
-describe Bosh::Cpi::RegistryClient do
- subject { Bosh::Cpi::RegistryClient.new('fake_endpoint', 'fake_user', 'fake_password') }
- it_behaves_like 'a registry'
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/openstack_spec.rb b/src/bosh_openstack_cpi/spec/unit/openstack_spec.rb
deleted file mode 100644
index 8217512a0..000000000
--- a/src/bosh_openstack_cpi/spec/unit/openstack_spec.rb
+++ /dev/null
@@ -1,902 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Openstack do
- let(:openstack_options_v2) { mock_cloud_options['properties']['openstack'] }
- let(:openstack_options_v2_devstack) { mock_cloud_options(2, true)['properties']['openstack'] }
- let(:openstack_options_v3) { mock_cloud_options(3)['properties']['openstack'] }
- let(:openstack_options_v3_devstack) { mock_cloud_options(3, true)['properties']['openstack'] }
- let(:openstack_options) { openstack_options_v2 }
- subject(:subject) { Bosh::OpenStackCloud::Openstack.new(openstack_options) }
-
- describe 'is_v3' do
- it 'should identify keystone v3 URIs' do
- expect(Bosh::OpenStackCloud::Openstack.is_v3('http://fake-auth-url/v3')).to be_truthy
- end
-
- it 'should identify keystone v2 URIs' do
- expect(Bosh::OpenStackCloud::Openstack.is_v3('http://fake-auth-url/v2.0')).to be_falsey
- end
- end
-
- describe :project_name do
-
- context 'when keystone version is v2' do
- let(:openstack_options) { openstack_options_v2 }
- it 'returns the project name' do
- expect(subject.project_name).to eq('dummy_tenant')
- end
- end
-
- context 'when keystone version is v3' do
- let(:openstack_options) { openstack_options_v3 }
- it 'returns the tenant name' do
- expect(subject.project_name).to eq('dummy_project')
- end
- end
- end
-
- describe :new do
- context 'when auth_url does not include tokens' do
- context 'when auth_url is v2' do
- it 'should remove the auth_url version' do
- expect(subject.auth_url).to eq('http://127.0.0.1:5000')
- end
- end
-
- context 'when auth_url is a devstack v2' do
- let(:openstack_options) { openstack_options_v2_devstack }
-
- it 'should remove the auth_url version' do
- expect(subject.auth_url).to eq('http://127.0.0.1:5000/identity')
- end
- end
-
- context 'when auth_url is v3' do
- let(:openstack_options) { openstack_options_v3 }
-
- it 'should remove the auth_url version' do
- expect(subject.auth_url).to eq('http://127.0.0.1:5000')
- end
- end
-
- context 'when auth_url is a devstack v3 url' do
- let(:openstack_options) { openstack_options_v3_devstack }
-
- it 'should remove the auth_url version' do
- expect(subject.auth_url).to eq('http://127.0.0.1:5000/identity')
- end
- end
- end
-
- context 'when the full auth_url was specified' do
- context 'when auth_url is v2' do
- before do
- openstack_options_v2['auth_url'] = 'http://fake-auth-url/v2.0/tokens'
- end
-
- it 'removes everything beginning from auth_url version' do
- expect(subject.auth_url).to eq('http://fake-auth-url')
- end
- end
-
- context 'when auth_url is v2 devstack url' do
- before do
- openstack_options_v2['auth_url'] = 'http://fake-auth-url/identity/v2.0/tokens'
- end
-
- it 'removes everything beginning from the auth_url version' do
- expect(subject.auth_url).to eq('http://fake-auth-url/identity')
- end
- end
-
- context 'when auth_url is v3' do
- let(:openstack_options) { openstack_options_v3 }
- before do
- openstack_options_v3['auth_url'] = 'http://fake-auth-url/v3/auth/tokens'
- end
-
- it 'removes everything beginning from the auth_url version' do
- expect(subject.auth_url).to eq('http://fake-auth-url')
- end
- end
-
- context 'when auth_url is v3 devstack url' do
- let(:openstack_options) { openstack_options_v3 }
- before do
- openstack_options_v3['auth_url'] = 'http://fake-auth-url/identity/v3/auth/tokens'
- end
-
- it 'removes everything beginning from the auth_url version' do
- expect(subject.auth_url).to eq('http://fake-auth-url/identity')
- end
- end
-
- context 'and it ends with a slash' do
- before do
- openstack_options_v2['auth_url'] = 'http://fake-auth-url/v2.0/'
- end
-
- it 'removes the trailing slash and version' do
- expect(subject.auth_url).to eq('http://fake-auth-url')
- end
- end
- end
-
- context 'excon instrumentor' do
- context 'default instrumentor' do
- it 'set the default instrumentor' do
- openstack = Bosh::OpenStackCloud::Openstack.new(openstack_options)
-
- expect(openstack.params[:connection_options]['instrumentor']).to eq(Bosh::OpenStackCloud::ExconLoggingInstrumentor)
- end
- end
-
- context 'no instrumentor' do
- it 'set the default instrumentor' do
- openstack = Bosh::OpenStackCloud::Openstack.new(openstack_options, {}, {})
-
- expect(openstack.params[:connection_options].key?('instrumentor')).to be(false)
- end
- end
- end
- end
-
- describe :use_nova_networking? do
- context 'when the manifest contains `use_nova_networking=true`' do
- let(:openstack_options_with_nova) { openstack_options_v3['use_nova_networking'] = true; openstack_options_v3 }
- let(:openstack_options) { openstack_options_with_nova }
- it 'returns true' do
- expect(subject.use_nova_networking?).to eq(true)
- end
- end
-
- context 'when the manifest contains `use_nova_networking=false`' do
- let(:openstack_options_with_nova) { openstack_options_v3['use_nova_networking'] = false; openstack_options_v3 }
- let(:openstack_options) { openstack_options_with_nova }
- it 'returns false' do
- expect(subject.use_nova_networking?).to eq(false)
- end
- end
-
- context 'when the manifest does not contain `use_nova_networking`' do
- let(:openstack_options) { openstack_options_v3 }
- it 'returns false' do
- expect(subject.use_nova_networking?).to eq(false)
- end
- end
- end
-
- context 'when the service is not available' do
- describe 'Network' do
- it 'raises a CloudError exception if cannot connect to the service API' do
- allow(Fog::OpenStack::Network).to receive(:new).and_raise(Fog::Errors::NotFound, 'Not found message')
- expect {
- Bosh::OpenStackCloud::Openstack.new(openstack_options).network
- }.to raise_error(Bosh::Clouds::CloudError,
- 'Unable to connect to the OpenStack Network Service API: Not found message. Check task debug log for details.')
- end
- end
- end
-
- [{ clazz: Fog::OpenStack::Compute, name: 'Compute', method_name: :compute },
- { clazz: Fog::OpenStack::Image, name: 'Image', method_name: :image },
- { clazz: Fog::OpenStack::Volume, name: 'Volume', method_name: :volume },
- { clazz: Fog::OpenStack::Network, name: 'Network', method_name: :network }].each do |fog|
- describe (fog[:name]).to_s do
- let(:retry_options_overwrites) {
- {
- sleep: 0,
- } }
-
- context 'when the service returns Unauthorized' do
- it 'raises a CloudError exception if cannot connect to the service API 5 times' do
- allow(fog[:clazz]).to receive(:new).and_raise(Excon::Error::Unauthorized, 'Unauthorized')
- expect {
- Bosh::OpenStackCloud::Openstack.new(openstack_options, retry_options_overwrites).send(fog[:method_name])
- }.to raise_error(Bosh::Clouds::CloudError,
- "Unable to connect to the OpenStack #{fog[:name]} Service API: Unauthorized. Check task debug log for details.")
- end
- end
-
- context 'when the backend call raises a SocketError' do
- let(:socket_error) { Excon::Error::Socket.new(SocketError.new('getaddrinfo: nodename nor servname provided, or not known')) }
- let(:expected_error_message) { "Unable to connect to the OpenStack Keystone API http://127.0.0.1:5000\ngetaddrinfo: nodename nor servname provided, or not known (SocketError)" }
-
- it 'raises a CloudError exception enriched with the targeted OpenStack KeyStone API url for service API' do
- allow(fog[:clazz]).to receive(:new).and_raise(socket_error)
-
- expect {
- Bosh::OpenStackCloud::Openstack.new(openstack_options, retry_options_overwrites).send(fog[:method_name])
- }.to raise_error(Bosh::Clouds::CloudError, expected_error_message)
- end
- end
-
- context 'with connection options' do
- let(:connection_options) { { 'ssl_verify_peer' => false } }
- let(:default_connection_options) {
- { 'instrumentor' => Bosh::OpenStackCloud::ExconLoggingInstrumentor }
- }
- let(:merged_connection_options) {
- default_connection_options.merge(connection_options)
- }
-
- it 'should add optional options to the Fog connection' do
- openstack_options['connection_options'] = connection_options
-
- allow(fog[:clazz]).to receive(:new).and_return(instance_double(fog[:clazz]))
- Bosh::OpenStackCloud::Openstack.new(openstack_options).send(fog[:method_name])
-
- expect(fog[:clazz]).to have_received(:new).with(hash_including(connection_options: merged_connection_options))
- end
- end
-
- context 'when keystone V3 API is used' do
- let(:openstack_options) { openstack_options_v3 }
- it 'should add optional options to the Fog connection' do
- allow(fog[:clazz]).to receive(:new).and_return(instance_double(fog[:clazz]))
- Bosh::OpenStackCloud::Openstack.new(openstack_options).send(fog[:method_name])
-
- expect(fog[:clazz]).to have_received(:new).with(hash_including(openstack_project_name: 'dummy_project'))
- expect(fog[:clazz]).to have_received(:new).with(hash_including(openstack_domain_name: 'some_domain'))
- end
- end
-
- context 'when keystone V2 API is used' do
- it 'should add optional options to the Fog connection' do
- allow(fog[:clazz]).to receive(:new).and_return(instance_double(fog[:clazz]))
- Bosh::OpenStackCloud::Openstack.new(openstack_options).send(fog[:method_name])
-
- expect(fog[:clazz]).to have_received(:new).with(hash_including(openstack_tenant: 'dummy_tenant'))
- end
- end
-
- context 'when last retry succeeds' do
- before do
- retry_count = 0
- allow(fog[:clazz]).to receive(:new) do
- retry_count += 1
- if retry_count < Bosh::OpenStackCloud::Cloud::CONNECT_RETRY_COUNT
- raise Excon::Error::GatewayTimeout, 'Gateway Timeout'
- end
- instance_double(fog[:clazz])
- end
- end
-
- it 'does not raise a GatewayTimeout error' do
- expect {
- Bosh::OpenStackCloud::Openstack.new(openstack_options)
- }.to_not raise_error
- end
- end
-
- context 'when used multiple times' do
- it 'creates the connection lazy and caches it' do
- expect(fog[:clazz]).to receive(:new).once.and_return(instance_double(fog[:clazz]))
- openstack = Bosh::OpenStackCloud::Openstack.new(openstack_options)
-
- fog_class_1st_call = openstack.send(fog[:method_name])
- fog_class_2nd_call = openstack.send(fog[:method_name])
-
- expect(fog_class_1st_call).to eq fog_class_2nd_call
- end
- end
- end
- end
-
- describe 'wait_resource' do
- let(:resource) { double('resource', id: 'foobar', reload: {}) }
- before { allow(resource).to receive(:status).and_return(:start, :stop) }
- before { allow(subject).to receive(:sleep) }
-
- it 'does not raise if one of the target states is reached' do
- expect {
- subject.wait_resource(resource, %i[stop deleted], :status, false)
- }.to_not raise_error
- end
-
- it 'waits for configured amount of time' do
- expect(subject).to receive(:sleep).with(3)
-
- subject.wait_resource(resource, %i[stop deleted], :status, false)
- end
-
- context 'when the resource status never changes' do
- it 'times out' do
- start_time = Time.now
- timeout_time = start_time + subject.state_timeout + 1
- Timecop.freeze(start_time)
-
- allow(resource).to receive(:status) do
- Timecop.freeze(timeout_time)
- :start
- end
-
- expect {
- subject.wait_resource(resource, :stop, :status, false)
- }.to raise_error Bosh::Clouds::CloudError, /Timed out/
- end
- end
-
- context 'when the resource status is error' do
- before { allow(resource).to receive(:status).and_return(:error) }
- context 'when no additional fault is provided by OpenStack' do
- before { allow(resource).to receive(:fault).and_return(nil) }
-
- it 'raises Bosh::Clouds::CloudError' do
- expect {
- subject.wait_resource(resource, :stop, :status, false)
- }.to raise_error Bosh::Clouds::CloudError, /state is error/
- end
- end
-
- context 'when no additional fault supported by resource' do
- it 'raises Bosh::Clouds::CloudError' do
- expect {
- subject.wait_resource(resource, :stop, :status, false)
- }.to raise_error Bosh::Clouds::CloudError, /state is error/
- end
- end
-
- context 'when additional fault is provided by OpenStack' do
- let(:resource) { double('resource', id: 'foobar', reload: {}, fault: { 'message' => 'fault message ', 'details' => 'fault details' }) }
-
- it 'raises Bosh::Clouds::CloudError' do
- expect {
- subject.wait_resource(resource, :stop, :status, false)
- }.to raise_error Bosh::Clouds::CloudError, /state is error, expected stop\nfault message fault details/
- end
- end
- end
-
- context 'when the resource status is failed' do
- before { allow(resource).to receive(:status).and_return(:failed) }
- context 'when no additional fault is provided by OpenStack' do
- before { allow(resource).to receive(:fault).and_return(nil) }
-
- it 'raises Bosh::Clouds::CloudError' do
- expect {
- subject.wait_resource(resource, :stop, :status, false)
- }.to raise_error Bosh::Clouds::CloudError, /state is failed/
- end
- end
-
- context 'when no additional fault supported by resource' do
- it 'raises Bosh::Clouds::CloudError' do
- expect {
- subject.wait_resource(resource, :stop, :status, false)
- }.to raise_error Bosh::Clouds::CloudError, /state is failed/
- end
- end
-
- context 'when additional fault is provided by OpenStack' do
- let(:resource) { double('resource', id: 'foobar', reload: {}, fault: { 'message' => 'fault message ', 'details' => 'fault details' }) }
-
- it 'raises Bosh::Clouds::CloudError' do
- expect {
- subject.wait_resource(resource, :stop, :status, false)
- }.to raise_error Bosh::Clouds::CloudError, /state is failed, expected stop\nfault message fault details/
- end
- end
- end
-
- context 'when the resource status is killed' do
- before { allow(resource).to receive(:status).and_return(:killed) }
- context 'when no additional fault is provided by OpenStack' do
- before { allow(resource).to receive(:fault).and_return(nil) }
-
- it 'raises Bosh::Clouds::CloudError' do
- expect {
- subject.wait_resource(resource, :stop, :status, false)
- }.to raise_error Bosh::Clouds::CloudError, /state is killed/
- end
- end
-
- context 'when no additional fault supported by resource' do
- it 'raises Bosh::Clouds::CloudError' do
- expect {
- subject.wait_resource(resource, :stop, :status, false)
- }.to raise_error Bosh::Clouds::CloudError, /state is killed/
- end
- end
-
- context 'when additional fault is provided by OpenStack' do
- let(:resource) { double('resource', id: 'foobar', reload: {}, fault: { 'message' => 'fault message ', 'details' => 'fault details' }) }
-
- it 'raises Bosh::Clouds::CloudError' do
- expect {
- subject.wait_resource(resource, :stop, :status, false)
- }.to raise_error Bosh::Clouds::CloudError, /state is killed, expected stop\nfault message fault details/
- end
- end
- end
-
- context 'when the resource is not found' do
- before { allow(resource).to receive(:reload).and_return(nil) }
-
- it 'should raise Bosh::Clouds::CloudError if resource not found' do
- expect {
- subject.wait_resource(resource, :deleted, :status, false)
- }.to raise_error Bosh::Clouds::CloudError, /Resource not found/
- end
-
- context 'when the resource does not need to be found' do
- it 'does not raise' do
- expect { subject.wait_resource(resource, :deleted, :status, true) }.not_to raise_error
- end
- end
- end
- end
-
- describe 'with_openstack' do
- context 'when openstack raises an unexpected exception' do
- before { allow(subject).to receive(:servers).and_raise(NoMemoryError) }
-
- it 'raises the exception without waiting' do
- expect(subject).not_to receive(:sleep)
-
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(NoMemoryError)
- end
- end
-
- context 'when openstack raises ServiceUnavailable' do
- let(:headers) { {} }
- let(:body) do
- {
- 'overLimit' => {
- 'message' => 'No server is available to handle this request.',
- 'code' => 503,
- },
- }
- end
- let(:response) { Excon::Response.new(body: JSON.dump(body), headers:) }
-
- before do
- allow(subject).to receive(:servers) do
- # next time don't raise the same exception to avoid looping
- allow(subject).to receive(:servers).and_return(nil)
-
- raise Excon::Error::ServiceUnavailable.new('', '', response)
- end
- end
-
- it 'retries until the max number of retries is reached' do
- allow(subject).to receive(:servers).exactly(11).times
- .and_raise(Excon::Error::ServiceUnavailable.new('', '', response))
- expect(subject).to receive(:sleep).with(3).exactly(10).times
-
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API ServiceUnavailable.\nCheck task debug log for details.")
- end
- end
-
- context 'when openstack raises RequestEntityTooLarge' do
- let(:headers) { {} }
- let(:body) do
- {
- 'overLimit' => {
- 'message' => 'This request was rate-limited.',
- 'code' => 413,
- 'details' => 'Only 10 POST request(s) can be made to * every minute.',
- },
- }
- end
- let(:response) { Excon::Response.new(body: JSON.dump(body), headers:) }
-
- before do
- allow(subject).to receive(:servers) do
- # next time don't raise the same exception to avoid looping
- allow(subject).to receive(:servers).and_return(nil)
-
- raise Excon::Error::RequestEntityTooLarge.new('', '', response)
- end
- end
-
- it 'retries after waiting a default number of seconds' do
- expect_any_instance_of(Kernel).to receive(:sleep).with(3)
-
- subject.with_openstack do
- subject.servers
- end
- end
-
- it 'retries until the max number of retries is reached' do
- allow(subject).to receive(:servers).exactly(11).times
- .and_raise(Excon::Error::RequestEntityTooLarge.new('', '', response))
- expect_any_instance_of(Kernel).to receive(:sleep).with(3).exactly(10).times
-
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- /OpenStack API RequestEntityTooLarge/)
- end
-
- context 'when the response includes a retryAfter in the body' do
- before { body['overLimit']['retryAfter'] = 5 }
-
- it 'retries after waiting the amount of seconds received at the response body' do
- expect_any_instance_of(Kernel).to receive(:sleep).with(5)
-
- subject.with_openstack do
- subject.servers
- end
- end
- end
-
- context 'when the response includes a Retry-After header' do
- before { headers['Retry-After'] = 5 }
-
- it 'retries after waiting the amount of seconds received in the Retry-After header' do
- expect_any_instance_of(Kernel).to receive(:sleep).with(5)
-
- subject.with_openstack do
- subject.servers
- end
- end
- end
-
- context 'when OpenStack error message contains overLimit,' do
- let(:body) do
- {
- 'overLimit' => {
- 'message' => 'Specific OpenStack error message',
- 'code' => 413,
- 'details' => 'Only 10 POST request(s) can be made to * every minute.',
- 'retryAfter' => 0,
- },
- }
- end
-
- it 'enriches the BOSH error message' do
- allow(subject).to receive(:servers).and_raise(Excon::Error::RequestEntityTooLarge.new('', '', response))
-
- expected_message = "OpenStack API RequestEntityTooLarge Specific OpenStack error message.\nCheck task debug log for details."
-
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError, expected_message)
- end
- end
-
- context 'when OpenStack error message does not contain overLimit,' do
- let(:body) do
- {
- 'notOverLimit' => 'arbitrary content',
- }
- end
-
- it 'enriches the BOSH error message with the whole response body' do
- expected_response_body = JSON.dump({'notOverLimit' => 'arbitrary content'})
- expected_message = "OpenStack API RequestEntityTooLarge #{expected_response_body}.\nCheck task debug log for details."
-
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError, expected_message)
- end
- end
- end
-
- context 'when openstack raises BadRequest' do
- before do
- response = Excon::Response.new(body:)
- expect(subject).to receive(:servers).and_raise(Excon::Error::BadRequest.new('', '', response))
- end
-
- let(:body) { JSON.dump({}) }
-
- context 'when the error includes a `message` property on 2nd level of body' do
- let(:body) { JSON.dump({'SomeError' => { 'message' => 'some-message' }}) }
-
- it 'should raise a CloudError exception with OpenStack API message' do
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API BadRequest (some-message).\nCheck task debug log for details.")
- end
- end
-
- context 'when the error does not include a message' do
- let(:body) { JSON.dump({'SomeError' => { 'some_key' => 'some_val' }}) }
-
- it 'should raise a CloudError exception with OpenStack API message without anything from body' do
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API BadRequest.\nCheck task debug log for details.")
- end
- end
-
- context 'when the response has an empty body' do
- let(:body) { '' }
-
- it 'should raise a CloudError exception without OpenStack API message' do
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API BadRequest.\nCheck task debug log for details.")
- end
- end
- end
-
- context 'when openstack raises Conflict' do
- before do
- response = Excon::Response.new(body:)
- expect(subject).to receive(:servers).and_raise(Excon::Error::Conflict.new('', '', response))
- end
-
- let(:body) { JSON.dump({}) }
-
- context 'when the error includes a `message` property on 2nd level of body' do
- let(:body) { JSON.dump({'SomeError' => { 'message' => 'some-message' }}) }
-
- it 'should raise a CloudError exception with OpenStack API message' do
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API Conflict (some-message).\nCheck task debug log for details.")
- end
- end
-
- context 'when the error does not include a message' do
- let(:body) { JSON.dump({'SomeError' => { 'some_key' => 'some_val' }}) }
-
- it 'should raise a CloudError exception with OpenStack API message without anything from body' do
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API Conflict.\nCheck task debug log for details.")
- end
- end
-
- context 'when the response has an empty body' do
- let(:body) { '' }
-
- it 'should raise a CloudError exception without OpenStack API message' do
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API Conflict.\nCheck task debug log for details.")
- end
- end
- end
-
- context 'when openstack raises InternalServerError' do
- it 'should retry the max number of retries before raising a CloudError exception' do
- expect(subject).to receive(:servers).exactly(11)
- .and_raise(Excon::Error::InternalServerError.new('InternalServerError'))
- expect_any_instance_of(Kernel).to receive(:sleep).with(3).exactly(10)
-
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API InternalServerError.\nCheck task debug log for details.")
- end
- end
-
- context 'when openstack raises Fog::Errors::NotFound' do
- it 'should raise a CloudError with the original OpenStack message' do
- openstack_error_message = 'Could not find service network. Have compute, compute_legacy, identity, image, volume'
-
- expect {
- subject.with_openstack { raise Fog::Errors::NotFound, openstack_error_message }
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API NotFound #{openstack_error_message}.\nCheck task debug log for details.")
- end
-
- context 'when NotFound is ignored' do
- it 'should not raise a CloudError' do
- expect {
- subject.with_openstack(ignore_not_found: true) { raise Fog::Errors::NotFound }
- }.to_not raise_error
- end
- end
- end
-
- context 'when openstack raises Forbidden' do
- before do
- response = Excon::Response.new(body:)
- expect(subject).to receive(:servers).and_raise(Excon::Error::Forbidden.new('', '', response))
- end
-
- let(:body) { JSON.dump({}) }
-
- context 'when the error includes a `message` property on 2nd level of body' do
- let(:body) { JSON.dump({'Forbidden' => { 'message' => 'some-message' }}) }
-
- it 'should raise a CloudError exception with OpenStack API message' do
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API Forbidden (some-message).\nCheck task debug log for details.")
- end
- end
-
- context 'when the error does not include a message' do
- let(:body) { JSON.dump({'SomeError' => { 'some_key' => 'some_val' }}) }
-
- it 'should raise a CloudError exception with OpenStack API message without anything from body' do
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API Forbidden.\nCheck task debug log for details.")
- end
- end
-
- context 'when the response has an empty body' do
- let(:body) { '' }
-
- it 'should raise a CloudError exception with OpenStack API message without anything from body' do
- expect {
- subject.with_openstack do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API Forbidden.\nCheck task debug log for details.")
- end
- end
- end
-
- context 'when error is Excon::Error::Timeout' do
- before do
- allow(subject).to receive(:servers).and_raise(Excon::Error::Timeout.new('foo'))
- stub_const("Bosh::OpenStackCloud::Openstack::DEFAULT_RETRY_TIMEOUT", 0)
- end
-
- context 'when request is retryable' do
- it 'should retry request MAX_RETRIES times' do
- expect {
- subject.with_openstack(retryable: true) do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API Timeout foo.\nCheck task debug log for details.")
-
- expect(subject).to have_received(:servers).exactly(Bosh::OpenStackCloud::Openstack::MAX_RETRIES + 1).times
- end
- end
-
- context 'when request is not retryable' do
- it 'should retry request MAX_RETRIES times' do
- expect {
- subject.with_openstack(retryable: false) do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API Timeout foo.\nCheck task debug log for details.")
-
- expect(subject).to have_received(:servers).once
- end
- end
- end
-
- context 'when error is Excon::Error::Socket' do
- before do
- stub_const("Bosh::OpenStackCloud::Openstack::DEFAULT_RETRY_TIMEOUT", 0)
- end
-
- context "when a SocketError is raised with 'getaddrinfo'" do
- before do
- allow(subject).to receive(:servers).and_raise(Excon::Error::Socket.new(SocketError.new('getaddrinfo: nodename nor servname provided, or not known')))
- end
-
- it 'should retry request MAX_RETRIES times' do
- expect {
- subject.with_openstack(retryable: false) do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API Socket getaddrinfo: nodename nor servname provided, or not known (SocketError).\nCheck task debug log for details.")
-
- expect(subject).to have_received(:servers).exactly(Bosh::OpenStackCloud::Openstack::MAX_RETRIES + 1).times
- end
- end
-
- context "when a SocketError is not raised with 'getaddrinfo'" do
- before do
- allow(subject).to receive(:servers).and_raise(Excon::Error::Socket.new(SocketError.new('foo')))
- end
-
- context 'when request is retryable' do
- it 'should retry request MAX_RETRIES times' do
- expect {
- subject.with_openstack(retryable: true) do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API Socket foo (SocketError).\nCheck task debug log for details.")
-
- expect(subject).to have_received(:servers).exactly(Bosh::OpenStackCloud::Openstack::MAX_RETRIES + 1).times
- end
- end
-
- context 'when request is not retryable' do
- it 'should not retry request' do
- expect {
- subject.with_openstack(retryable: false) do
- subject.servers
- end
- }.to raise_error(Bosh::Clouds::CloudError,
- "OpenStack API Socket foo (SocketError).\nCheck task debug log for details.")
-
- expect(subject).to have_received(:servers).once
- end
- end
- end
- end
- end
-
- describe 'parse_openstack_response' do
- it 'should return nil if response has no body' do
- response = Excon::Response.new
-
- expect(subject.parse_openstack_response(response, 'key')).to be_nil
- end
-
- it 'should return nil if response has an empty string body' do
- response = Excon::Response.new(body: JSON.dump(''))
-
- expect(subject.parse_openstack_response(response, 'key')).to be_nil
- end
-
- it 'should return nil if response has a nil body' do
- response = Excon::Response.new(body: JSON.dump(nil))
-
- expect(subject.parse_openstack_response(response, 'key')).to be_nil
- end
-
- it 'should return nil if response is not JSON' do
- response = Excon::Response.new(body: 'foo = bar')
-
- expect(subject.parse_openstack_response(response, 'key')).to be_nil
- end
-
- it 'should return nil if response is no key is found' do
- response = Excon::Response.new(body: JSON.dump({'foo' => 'bar'}))
-
- expect(subject.parse_openstack_response(response, 'key')).to be_nil
- end
-
- it 'should return the contents if key is found' do
- response = Excon::Response.new(body: JSON.dump({'key' => 'foo'}))
-
- expect(subject.parse_openstack_response(response, 'key')).to eql('foo')
- end
-
- it 'should return the contents of the first key found' do
- response = Excon::Response.new(body: JSON.dump({'key1' => 'foo', 'key2' => 'bar'}))
-
- expect(subject.parse_openstack_response(response, 'key2', 'key1')).to eql('bar')
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/reboot_vm_spec.rb b/src/bosh_openstack_cpi/spec/unit/reboot_vm_spec.rb
deleted file mode 100644
index 50e0e2d81..000000000
--- a/src/bosh_openstack_cpi/spec/unit/reboot_vm_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- before :each do
- @server = double('server', id: 'i-foobar')
-
- @cloud = mock_cloud(mock_cloud_options['properties']) do |fog|
- allow(fog.compute.servers).to receive(:get).with('i-foobar').and_return(@server)
- end
- end
-
- it 'reboots an OpenStack server (CPI call picks soft reboot)' do
- expect(@cloud).to receive(:soft_reboot).with(@server)
- @cloud.reboot_vm('i-foobar')
- end
-
- it 'soft reboots an OpenStack server' do
- expect(@server).to receive(:reboot)
- expect(@cloud.openstack).to receive(:wait_resource).with(@server, :active, :state)
- @cloud.send(:soft_reboot, @server)
- end
-
- it 'hard reboots an OpenStack server' do
- expect(@server).to receive(:reboot)
- expect(@cloud.openstack).to receive(:wait_resource).with(@server, :active, :state)
- @cloud.send(:hard_reboot, @server)
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/request_message_spec.rb b/src/bosh_openstack_cpi/spec/unit/request_message_spec.rb
deleted file mode 100644
index 4a3a5d9ff..000000000
--- a/src/bosh_openstack_cpi/spec/unit/request_message_spec.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::RequestMessage do
- describe '.format' do
- subject { Bosh::OpenStackCloud::RequestMessage.new(params) }
-
- let(:params) {
- {
- ciphers: 'fake-ciphers',
- connection: 'connection-class',
- stack: 'stack-class',
- hostname: 'fake-host.fqdn',
- __construction_args: 'fake-args',
- uri_parser: 'URI',
- instrumentor: 'CLASS',
- method: 'PUT',
- scheme: 'https',
- port: '8774',
- path: '/v1',
- headers: { 'fake-headers' => 'fake-value' },
- body: '{"fake-body":"fake-value"}',
- other_important_key: '1234',
- }
- }
- let(:output) { subject.format }
-
- it 'removes clutter from params' do
- expect(output).not_to include('"ciphers":')
- expect(output).not_to include('"connection":')
- expect(output).not_to include('"stack":')
- expect(output).not_to include('"instrumentor":')
- expect(output).not_to include('"uri_parser":')
- expect(output).not_to include('"__construction_args":')
- end
-
- it 'keeps everything else in the params' do
- expect(output).to include('params: {"other_important_key":"1234"}')
- end
-
- it 'includes url' do
- expect(output).to include('PUT https://fake-host.fqdn:8774/v1')
- end
-
- it 'includes the headers as json' do
- expect(output).to include('headers: {"fake-headers":"fake-value"}')
- end
-
- it 'includes the body as json' do
- expect(output).to include('body: {"fake-body":"fake-value"}')
- end
-
- it 'orders correctly' do
- expect(output).to match(%r(^PUT https://fake-host.fqdn:8774/v1 params: {.*} headers: {.*} body: {.*}$))
- end
-
- context 'when body is empty' do
- it 'outputs null for body' do
- params.delete(:body)
- expect(output).to match(%r(^PUT https://fake-host.fqdn:8774/v1 params: {.*} headers: {.*} body: null$))
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/resize_disk_spec.rb b/src/bosh_openstack_cpi/spec/unit/resize_disk_spec.rb
deleted file mode 100644
index c03670584..000000000
--- a/src/bosh_openstack_cpi/spec/unit/resize_disk_spec.rb
+++ /dev/null
@@ -1,109 +0,0 @@
-require 'spec_helper'
-require 'excon'
-
-describe Bosh::OpenStackCloud::Cloud, 'resize_disk' do
- let(:volume) { double('volume', id: 'disk-id') }
- let(:cloud) {
- mock_cloud do |fog|
- expect(fog.volume.volumes).to receive(:get)
- .with('disk-id').and_return(volume)
- end
- }
-
- before do
- allow(volume).to receive(:size).and_return(2)
- allow(volume).to receive(:attachments).and_return([])
- allow(volume).to receive(:metadata).and_return(double('metadata'))
- end
-
- it 'uses the OpenStack endpoint to resize a disk' do
- allow(volume).to receive(:extend)
- allow(cloud.openstack).to receive(:wait_resource).with(volume, :available)
-
- return_value = cloud.resize_disk('disk-id', 4096)
-
- expect(return_value).to eq(nil)
- expect(volume).to have_received(:extend).with(4)
- expect(Bosh::Clouds::Config.logger).to have_received(:info).with('Resizing disk-id from 2 GiB to 4 GiB')
- expect(cloud.openstack).to have_received(:wait_resource).with(volume, :available)
- expect(Bosh::Clouds::Config.logger).to have_received(:info).with('Disk disk-id resized from 2 GiB to 4 GiB')
- end
-
- context 'when trying to resize to the same disk size' do
- it 'does not call extend on disk and writes to the log' do
- allow(volume).to receive(:extend)
- allow(Bosh::Clouds::Config.logger).to receive(:info)
-
- cloud.resize_disk('disk-id', 2048)
-
- expect(volume).to_not have_received(:extend).with(2)
- expect(Bosh::Clouds::Config.logger).to have_received(:info).with('Skipping resize of disk disk-id because current value 2 GiB is equal new value 2 GiB')
- end
- end
-
- context 'when trying to resize disk to a new size with an not even size in MiB' do
- it 'does call extend on disk with rounding up to the next higher number and writes to the log' do
- allow(volume).to receive(:extend)
- allow(Bosh::Clouds::Config.logger).to receive(:info)
- allow(cloud.openstack).to receive(:wait_resource).with(volume, :available)
-
- cloud.resize_disk('disk-id', 4097)
-
- expect(Bosh::Clouds::Config.logger).to have_received(:info).with('Resizing disk-id from 2 GiB to 5 GiB')
- expect(cloud.openstack).to have_received(:wait_resource).with(volume, :available)
- expect(volume).to have_received(:extend).with(5)
- expect(Bosh::Clouds::Config.logger).to have_received(:info).with('Disk disk-id resized from 2 GiB to 5 GiB')
- end
- end
-
- context 'when trying to resize a non existing disk' do
- let(:cloud) {
- mock_cloud do |fog|
- allow(fog.volume.volumes).to receive(:get)
- .with('non-existing-disk-id').and_return(nil)
- end
- }
-
- it 'fails' do
- expect {
- cloud.resize_disk('non-existing-disk-id', 1024)
- }.to raise_error(Bosh::Clouds::CloudError, 'Cannot resize volume because volume with non-existing-disk-id not found')
- end
- end
-
- context 'when trying to resize to a smaller disk' do
- it 'fails' do
- expect {
- cloud.resize_disk('disk-id', 1024)
- }.to raise_error(Bosh::Clouds::NotSupported, 'Cannot resize volume to a smaller size from 2 GiB to 1 GiB')
- end
- end
-
- context 'when volume is still attached' do
- before do
- allow(volume).to receive(:attachments).and_return([{}])
- end
-
- it 'fails' do
- expect {
- cloud.resize_disk('disk-id', 4096)
- }.to raise_error(Bosh::Clouds::CloudError, "Cannot resize volume 'disk-id' it still has 1 attachment(s)")
- end
- end
-
- context 'when extending volume fails on IaaS' do
- before do
- body
- response = Excon::Response.new(body:)
- allow(volume).to receive(:extend).and_raise(Excon::Error::BadRequest.new('', '', response))
- end
-
- let(:body) { JSON.dump({'badRequest' => { 'message' => 'some-message' }}) }
-
- it 'raises an error' do
- expect {
- cloud.resize_disk('disk-id', 4096)
- }.to raise_error(Bosh::Clouds::CloudError, "OpenStack API BadRequest (some-message).\nCheck task debug log for details.")
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/resource_pool_spec.rb b/src/bosh_openstack_cpi/spec/unit/resource_pool_spec.rb
deleted file mode 100644
index 920fdbce7..000000000
--- a/src/bosh_openstack_cpi/spec/unit/resource_pool_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::ResourcePool do
- describe '.security_groups' do
- context 'when given resource_pool_spec is nil' do
- it 'returns an empty array' do
- expect(Bosh::OpenStackCloud::ResourcePool.security_groups(nil)).to eq([])
- end
- end
-
- context "when given resource_pool_spec contains no 'security_group'" do
- it 'returns an empty array' do
- expect(Bosh::OpenStackCloud::ResourcePool.security_groups(nil)).to eq([])
- end
- end
-
- context 'when security_group is not an array' do
- it 'raises an error' do
- expect {
- Bosh::OpenStackCloud::ResourcePool.security_groups('security_groups' => 'not an array')
- }.to raise_error ArgumentError, 'security groups must be an Array'
- end
- end
-
- context 'when security_groups is an array' do
- it 'returns the security_group array' do
- expect(Bosh::OpenStackCloud::ResourcePool.security_groups(
- 'security_groups' => ['some-security-group'],
- )).to eq(['some-security-group'])
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/response_message_spec.rb b/src/bosh_openstack_cpi/spec/unit/response_message_spec.rb
deleted file mode 100644
index 8970ce390..000000000
--- a/src/bosh_openstack_cpi/spec/unit/response_message_spec.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::ResponseMessage do
- describe '.format' do
- subject { Bosh::OpenStackCloud::ResponseMessage.new(params) }
-
- let(:params) {
- {
- port: 1234,
- host: 'hostname.fqdn',
- path: '/api',
- headers: { 'other_important_key' => '' },
- status_line: "HTTP/1.0 200 OK\r\n",
- body: {},
- cookies: [],
- status: '200',
- reason_phrase: 'OK',
- other_important_key: '10.1',
- }
- }
- let(:output) { subject.format }
-
- it 'removes clutter from params' do
- expect(output).not_to include('"cookies":')
- expect(output).not_to include('"status":')
- expect(output).not_to include('"reason_phrase":')
- end
-
- it 'includes host, port and everything else in the params' do
- expect(output).to include('params: {"port":1234,"host":"hostname.fqdn","other_important_key":"10.1"}')
- end
-
- it 'includes the response status line' do
- expect(output).to include('HTTP/1.0 200 OK')
- end
-
- it 'removes the response status line from headers' do
- expect(output).to include('headers: {"other_important_key":""}')
- end
-
- it 'includes the path' do
- expect(output).to include('/api')
- end
-
- it 'includes the params which include headers' do
- expect(output).to match(/headers: {.*}/)
- end
-
- it 'includes the params which include body' do
- expect(output).to match(/body: {.*}/)
- end
-
- it 'orders correctly' do
- expect(output).to match(%r(^HTTP/1.0 200 OK /api params: {.*} headers: {.*} body: {.*}$))
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/security_groups_spec.rb b/src/bosh_openstack_cpi/spec/unit/security_groups_spec.rb
deleted file mode 100644
index bbcddfe3b..000000000
--- a/src/bosh_openstack_cpi/spec/unit/security_groups_spec.rb
+++ /dev/null
@@ -1,148 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::SecurityGroups do
- let(:security_groups) { [] }
- let(:compute) { double('compute') }
- let(:network) { double('network') }
- let(:use_nova_networking?) { false }
- let(:openstack) { double('openstack', compute:, network:, use_nova_networking?: use_nova_networking?) }
-
- subject(:openstack_security_groups) {
- Bosh::OpenStackCloud::SecurityGroups.new(openstack)
- }
-
- before do
- allow(openstack).to receive(:with_openstack) { |&block| block.call }
- mock_sec_groups(network, security_groups)
- mock_sec_groups(compute, security_groups)
- end
-
-
- describe '.retrieve_and_validate_security_groups' do
- context 'security group picking' do
- let(:security_groups) {
- [
- double('default-security-group', name: 'default-security-group', id: 'default-security-group-id'),
- double('network-spec-security-group', name: 'network-spec-security-group'),
- double('resource-pool-spec-security-group', name: 'resource-pool-spec-security-group'),
- ]
- }
-
- context 'when security groups specified in resource pool spec' do
- it 'picks those' do
- picked_security_groups = openstack_security_groups.select_and_retrieve(
- ['default-security-group'],
- [],
- ['resource-pool-spec-security-group'],
- )
- expect(picked_security_groups.size).to eq(1)
- expect(picked_security_groups.first.name).to eq('resource-pool-spec-security-group')
- end
- end
-
- context 'when security group id is specified instead of name' do
- it 'picks the security group by id' do
- picked_security_groups = openstack_security_groups.select_and_retrieve(
- ['default-security-group-id'],
- [],
- [],
- )
- expect(picked_security_groups.size).to eq(1)
- expect(picked_security_groups.first.name).to eq('default-security-group')
- end
- end
-
- context 'when security groups specified in network spec' do
- it 'picks those' do
- picked_security_groups = openstack_security_groups.select_and_retrieve(
- ['default-security-group'],
- ['network-spec-security-group'],
- [],
- )
- expect(picked_security_groups.size).to eq(1)
- expect(picked_security_groups.first.name).to eq('network-spec-security-group')
- end
- end
-
- context 'when resource pool spec and network spec define security groups' do
- it 'picks the resource pool security groups' do
- picked_security_groups = openstack_security_groups.select_and_retrieve(
- ['default security group'],
- ['network-spec-security-group'],
- ['resource-pool-spec-security-group'],
- )
- expect(picked_security_groups.size).to eq(1)
- expect(picked_security_groups.first.name).to eq('resource-pool-spec-security-group')
- end
- end
-
- context 'when security groups are neither specified in network spec nor resource pool spec' do
- it 'picks the default security group' do
- picked_security_groups = openstack_security_groups.select_and_retrieve(
- ['default-security-group'],
- [],
- [],
- )
- expect(picked_security_groups.size).to eq(1)
- expect(picked_security_groups.first.name).to eq('default-security-group')
- end
- end
- end
-
- context 'when a picked security group does not exist in openstack' do
- let(:security_groups) { [] }
-
- it 'raises an error' do
- expect {
- openstack_security_groups.select_and_retrieve(
- ['default-security-group'],
- [],
- [],
- )
- }.to raise_error Bosh::Clouds::CloudError, "Security group `default-security-group' not found"
- end
- end
-
- context 'when openstack is configured with `use_nova_networking`' do
- let(:use_nova_networking?) { true }
-
- let(:security_groups) {
- [
- double('default-security-group', name: 'default-security-group'),
- ]
- }
-
- it 'uses nova to retrieve the security groups' do
- openstack_security_groups.select_and_retrieve(
- ['default-security-group'],
- [],
- [],
- )
-
- expect(compute).to have_received(:security_groups)
- expect(network).to_not have_received(:security_groups)
- end
- end
-
- context 'when openstack is configured without `use_nova_networking` (default)' do
- let(:use_nova_networking?) { false }
-
- let(:security_groups) {
- [
- double('default-security-group', name: 'default-security-group'),
- ]
- }
-
- it 'uses neutron to retrieve the security groups' do
- openstack_security_groups.select_and_retrieve(
- ['default-security-group'],
- [],
- [],
- )
-
- expect(network).to have_received(:security_groups)
- expect(compute).to_not have_received(:security_groups)
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/set_disk_metadata_spec.rb b/src/bosh_openstack_cpi/spec/unit/set_disk_metadata_spec.rb
deleted file mode 100644
index 9f3565f3d..000000000
--- a/src/bosh_openstack_cpi/spec/unit/set_disk_metadata_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- let(:disk) { double('disk', id: 'i-foobar', metadata: double('metadata')) }
- let(:metadata) { { 'deployment' => 'deployment-x' } }
-
- context 'when disk exists' do
- before(:each) do
- @cloud = mock_cloud do |fog|
- allow(fog.volume.volumes).to receive(:get).with('i-foobar').and_return(disk)
- end
- allow(@cloud.volume).to receive(:update_metadata)
- end
-
- it 'should tag with given metadata' do
- @cloud.set_disk_metadata('i-foobar', metadata)
- expect(@cloud.volume).to have_received(:update_metadata).with('i-foobar', 'deployment' => 'deployment-x')
- end
- end
-
- context 'when disk does not exist' do
- before(:each) do
- @cloud = mock_cloud do |fog|
- allow(fog.volume.volumes).to receive(:get).with('i-foobar')
- end
- end
-
- it 'raises a cloud error' do
- expect {
- @cloud.set_disk_metadata('i-foobar', metadata)
- }.to raise_error(Bosh::Clouds::CloudError, "Disk `i-foobar' not found")
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/set_vm_metadata_spec.rb b/src/bosh_openstack_cpi/spec/unit/set_vm_metadata_spec.rb
deleted file mode 100644
index d3bd67527..000000000
--- a/src/bosh_openstack_cpi/spec/unit/set_vm_metadata_spec.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- before(:each) { allow(Bosh::OpenStackCloud::TagManager).to receive(:tag_server) }
-
- let(:server) { double('server', id: 'i-foobar', metadata: double('metadata')) }
-
- context 'without registry_key set' do
- before(:each) do
- @cloud = mock_cloud do |fog|
- allow(fog.compute.servers).to receive(:get).with('i-foobar').and_return(server)
- end
- allow(server.metadata).to receive(:get)
- end
-
- it 'should only tag with metadata' do
- metadata = { job: 'job', index: 'index' }
-
- expect(Bosh::OpenStackCloud::TagManager).to receive(:tag_server).with(server, { job: 'job', index: 'index'})
-
- @cloud.set_vm_metadata('i-foobar', metadata)
- end
-
- it "logs 'compiling/x'" do
- @cloud.set_vm_metadata('i-foobar', {})
- expect(Bosh::Clouds::Config.logger).to have_received(:debug).with("VM with id 'i-foobar' has no 'registry_key' tag")
- end
- end
-
- context 'with registry_key set' do
- before(:each) do
- @cloud = mock_cloud do |fog|
- allow(fog.compute.servers).to receive(:get).with('i-foobar').and_return(server)
- allow(fog.compute).to receive(:update_server)
- end
- allow(server.metadata).to receive(:get).with(:registry_key).and_return(double('metadatum'))
- end
-
- context 'for normal job' do
- context "when bosh provides NO 'name' property" do
- let(:metadata) { { 'job' => 'job', 'index' => 'index' } }
-
- it "sets the vm name 'job/index'" do
- @cloud.set_vm_metadata('i-foobar', metadata)
- expect(@cloud.compute).to have_received(:update_server).with('i-foobar', 'name' => 'job/index')
- end
-
- it 'logs job name & index' do
- @cloud.set_vm_metadata('i-foobar', metadata)
- expect(Bosh::Clouds::Config.logger).to have_received(:debug).with("Rename VM with id 'i-foobar' to 'job/index'")
- end
- end
-
- context "when bosh provides a 'name' property" do
- let(:metadata) { { 'name' => 'job/id' } }
-
- it "sets the vm name 'job/id'" do
- @cloud.set_vm_metadata('i-foobar', metadata)
- expect(@cloud.compute).to have_received(:update_server).with('i-foobar', 'name' => 'job/id')
- end
-
- it 'logs instance name' do
- @cloud.set_vm_metadata('i-foobar', metadata)
- expect(Bosh::Clouds::Config.logger).to have_received(:debug).with("Rename VM with id 'i-foobar' to 'job/id'")
- end
- end
- end
-
- context 'for compilation vms' do
- let(:metadata) { { 'compiling' => 'x' } }
-
- it "sets the vm name 'compiling/x'" do
- @cloud.set_vm_metadata('i-foobar', metadata)
- expect(@cloud.compute).to have_received(:update_server).with('i-foobar', 'name' => 'compiling/x')
- end
-
- it "logs 'compiling/x'" do
- @cloud.set_vm_metadata('i-foobar', metadata)
- expect(Bosh::Clouds::Config.logger).to have_received(:debug).with("Rename VM with id 'i-foobar' to 'compiling/x'")
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/snapshot_disk_spec.rb b/src/bosh_openstack_cpi/spec/unit/snapshot_disk_spec.rb
deleted file mode 100644
index c7e6d05a4..000000000
--- a/src/bosh_openstack_cpi/spec/unit/snapshot_disk_spec.rb
+++ /dev/null
@@ -1,201 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::Cloud do
- it 'creates an OpenStack snapshot' do
- unique_name = SecureRandom.uuid
- volume = double('volume', id: 'v-foobar')
- attachment = { 'device' => '/dev/vdc' }
- snapshot = double('snapshot', id: 'snap-foobar', update_metadata: nil)
- snapshot_params = {
- display_name: "snapshot-#{unique_name}",
- display_description: 'deployment/job/0/vdc',
- name: "snapshot-#{unique_name}",
- description: 'deployment/job/0/vdc',
- volume_id: 'v-foobar',
- force: true,
- }
- metadata = {
- agent_id: 'agent',
- instance_id: 'instance',
- director_name: 'Test Director',
- director_uuid: '6d06b0cc-2c08-43c5-95be-f1b2dd247e18',
- deployment: 'deployment',
- job: 'job',
- index: '0',
- }
-
- cloud = mock_cloud do |fog|
- expect(fog.volume.volumes).to receive(:get).with('v-foobar').and_return(volume)
- expect(fog.volume.snapshots).to receive(:new).with(snapshot_params).and_return(snapshot)
- end
-
- expect(cloud).to receive(:generate_unique_name).and_return(unique_name)
-
- expect(volume).to receive(:attachments).and_return([attachment])
-
- expect(snapshot).to receive(:save)
-
- expect(cloud.openstack).to receive(:wait_resource).with(snapshot, :available)
-
- expect(cloud.snapshot_disk('v-foobar', metadata)).to eq('snap-foobar')
- end
-
- context "when volume doesn't have any attachment" do
- let(:volume) { double('volume', id: 'v-foobar', attachments: [{}]) }
-
- it 'creates an OpenStack snapshot' do
- unique_name = SecureRandom.uuid
- snapshot = double('snapshot', id: 'snap-foobar', update_metadata: nil)
- snapshot_params = {
- display_name: "snapshot-#{unique_name}",
- display_description: 'deployment/job/0',
- name: "snapshot-#{unique_name}",
- description: 'deployment/job/0',
- volume_id: 'v-foobar',
- force: true,
- }
- metadata = {
- agent_id: 'agent',
- instance_id: 'instance',
- director_name: 'Test Director',
- director_uuid: '6d06b0cc-2c08-43c5-95be-f1b2dd247e18',
- deployment: 'deployment',
- job: 'job',
- index: '0',
- }
-
- cloud = mock_cloud do |fog|
- expect(fog.volume.volumes).to receive(:get).with('v-foobar').and_return(volume)
- expect(fog.volume.snapshots).to receive(:new).with(snapshot_params).and_return(snapshot)
- end
-
- expect(cloud).to receive(:generate_unique_name).and_return(unique_name)
-
- expect(snapshot).to receive(:save)
-
- expect(cloud.openstack).to receive(:wait_resource).with(snapshot, :available)
-
- expect(cloud.snapshot_disk('v-foobar', metadata)).to eq('snap-foobar')
- end
- end
-
- it 'handles string keys in metadata' do
- unique_name = SecureRandom.uuid
- volume = double('volume', id: 'v-foobar')
- snapshot = double('snapshot', id: 'snap-foobar', update_metadata: nil)
- snapshot_params = {
- display_name: "snapshot-#{unique_name}",
- display_description: 'deployment/job/0',
- name: "snapshot-#{unique_name}",
- description: 'deployment/job/0',
- volume_id: 'v-foobar',
- force: true,
- }
- metadata = {
- 'agent_id' => 'agent',
- 'instance_id' => 'instance',
- 'director_name' => 'Test Director',
- 'director_uuid' => '6d06b0cc-2c08-43c5-95be-f1b2dd247e18',
- 'deployment' => 'deployment',
- 'job' => 'job',
- 'index' => '0',
- }
-
- cloud = mock_cloud do |fog|
- expect(fog.volume.volumes).to receive(:get).with('v-foobar').and_return(volume)
- expect(fog.volume.snapshots).to receive(:new).with(snapshot_params).and_return(snapshot)
- end
-
- expect(cloud).to receive(:generate_unique_name).and_return(unique_name)
-
- expect(volume).to receive(:attachments).and_return([{}])
-
- expect(snapshot).to receive(:save)
-
- expect(cloud.openstack).to receive(:wait_resource).with(snapshot, :available)
-
- expect(cloud.snapshot_disk('v-foobar', metadata)).to eq('snap-foobar')
- end
-
- it 'should raise an Exception if OpenStack volume is not found' do
- cloud = mock_cloud do |fog|
- expect(fog.volume.volumes).to receive(:get).with('v-foobar').and_return(nil)
- end
-
- expect {
- cloud.snapshot_disk('v-foobar', {})
- }.to raise_error(Bosh::Clouds::CloudError, "Volume `v-foobar' not found")
- end
-
- it 'creates snapshot metadata with converted metadata' do
- volume = double('volume', id: 'v-foobar', attachments: [])
- snapshot = double('snapshot', id: 'snap-foobar', save: nil, update_metadata: nil)
- cloud = mock_cloud do |fog|
- allow(fog.volume.volumes).to receive(:get).and_return(volume)
- allow(fog.volume.snapshots).to receive(:new).and_return(snapshot)
- end
- allow(cloud.openstack).to receive(:wait_resource)
-
- metadata = {
- 'deployment' => 'deployment',
- 'job' => 'job',
- 'index' => 0,
- 'director_name' => 'Test Director',
- 'director_uuid' => '1234',
- 'agent_id' => 'agent0',
- 'instance_id' => 'some-uuid',
- }
-
- expected_snapshot_metadata = {
- 'director' => 'Test Director',
- 'director_uuid' => '1234',
- 'deployment' => 'deployment',
- 'instance_id' => 'some-uuid',
- 'instance_index' => '0',
- 'instance_name' => 'job/some-uuid',
- 'agent_id' => 'agent0',
- }
-
- cloud.snapshot_disk('v-foobar', metadata)
-
- expect(snapshot).to have_received(:update_metadata).with(expected_snapshot_metadata)
- end
-
- it 'creates snapshot metadata keeping user-defined tags without changing them' do
- volume = double('volume', id: 'v-foobar', attachments: [])
- snapshot = double('snapshot', id: 'snap-foobar', save: nil, update_metadata: nil)
- cloud = mock_cloud do |fog|
- allow(fog.volume.volumes).to receive(:get).and_return(volume)
- allow(fog.volume.snapshots).to receive(:new).and_return(snapshot)
- end
- allow(cloud.openstack).to receive(:wait_resource)
-
- metadata = {
- 'deployment' => 'deployment',
- 'job' => 'job',
- 'index' => 0,
- 'director_name' => 'Test Director',
- 'director_uuid' => '1234',
- 'agent_id' => 'agent0',
- 'instance_id' => 'some-uuid',
- 'tag1' => 'value1',
- 'tag2' => 'value2',
- }
-
- expected_snapshot_metadata = {
- 'director' => 'Test Director',
- 'director_uuid' => '1234',
- 'deployment' => 'deployment',
- 'instance_id' => 'some-uuid',
- 'instance_index' => '0',
- 'instance_name' => 'job/some-uuid',
- 'agent_id' => 'agent0',
- 'tag1' => 'value1',
- 'tag2' => 'value2',
- }
-
- cloud.snapshot_disk('v-foobar', metadata)
-
- expect(snapshot).to have_received(:update_metadata).with(expected_snapshot_metadata)
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/stemcell_creator_spec.rb b/src/bosh_openstack_cpi/spec/unit/stemcell_creator_spec.rb
deleted file mode 100644
index c9827243e..000000000
--- a/src/bosh_openstack_cpi/spec/unit/stemcell_creator_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-describe Bosh::OpenStackCloud::HeavyStemcellCreator do
- subject { described_class }
-
- describe '#normalize_image_properties' do
- it 'rejects nil values' do
- properties = {
- 'version' => nil,
- }
-
- expect(subject.normalize_image_properties(properties)).to_not have_key(:version)
- end
-
- it 'converts keys to symbols' do
- properties = {
- 'version' => '123',
- }
-
- expect(subject.normalize_image_properties(properties)).to have_key(:version)
- end
-
- it 'supports virtio-scsi properties' do
- properties = {
- 'hw_disk_bus_model' => 'virtio-scsi',
- 'hw_scsi_model' => 'virtio-scsi',
- 'hw_disk_bus' => 'scsi',
- }
-
- expect(subject.normalize_image_properties(properties)).to include(
- :hw_disk_bus_model,
- :hw_scsi_model,
- :hw_disk_bus,
- )
- end
-
- it 'supports virtio multiqueue network' do
- properties = {
- 'hw_vif_multiqueue_enabled' => true,
- }
-
- expect(subject.normalize_image_properties(properties)).to include(
- :hw_vif_multiqueue_enabled,
- )
- end
-
- it 'maps hypervisor key to hypervisor_type' do
- properties = {
- 'hypervisor' => 'kvm',
- }
-
- image_properties = subject.normalize_image_properties(properties)
-
- expect(image_properties[:hypervisor_type]).to eq('kvm')
- expect(image_properties).to_not have_key(:hypervisor)
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/tag_manager_spec.rb b/src/bosh_openstack_cpi/spec/unit/tag_manager_spec.rb
deleted file mode 100644
index c0af11244..000000000
--- a/src/bosh_openstack_cpi/spec/unit/tag_manager_spec.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::TagManager do
- describe '.tag_server' do
- let(:server) { double('server', id: 'i-foobar') }
- let(:metadata) { double('metadata') }
-
- before do
- allow(server).to receive(:metadata).and_return(metadata)
- allow(metadata).to receive(:update)
- end
-
- it 'sets multiple metadata tags' do
- Bosh::OpenStackCloud::TagManager.tag_server(server, 'key1' => 'value1', 'key2' => 'value2')
-
- expect(metadata).to have_received(:update).with('key1' => 'value1', 'key2' => 'value2')
- end
-
- it 'formats the tags' do
- Bosh::OpenStackCloud::TagManager.tag_server(server, 'key1' => 'value1', 2 => 2, 'key3' => nil)
-
- expect(metadata).to have_received(:update).with('key1' => 'value1', '2' => '2')
- end
- end
-
- describe '.tag_volume' do
- let(:volume) { double('volume') }
-
- before do
- allow(volume).to receive(:update_metadata)
- end
-
- it 'sets multiple metadata tags' do
- Bosh::OpenStackCloud::TagManager.tag_volume(volume, 'volume-id', 'key1' => 'value1', 'key2' => 'value2')
-
- expect(volume).to have_received(:update_metadata).with('volume-id', 'key1' => 'value1', 'key2' => 'value2')
- end
-
- it 'formats the tags' do
- Bosh::OpenStackCloud::TagManager.tag_volume(volume, 'volume-id', 'key1' => 'value1', 2 => 2, 'key3' => nil)
-
- expect(volume).to have_received(:update_metadata).with('volume-id', 'key1' => 'value1', '2' => '2')
- end
- end
-
- describe '.tag_snapshot' do
- let(:snapshot) { double('snapshot') }
-
- before do
- allow(snapshot).to receive(:update_metadata)
- end
-
- it 'sets multiple metadata tags' do
- Bosh::OpenStackCloud::TagManager.tag_snapshot(snapshot, 'key1' => 'value1', 'key2' => 'value2')
-
- expect(snapshot).to have_received(:update_metadata).with('key1' => 'value1', 'key2' => 'value2')
- end
-
- it 'formats the tags' do
- Bosh::OpenStackCloud::TagManager.tag_snapshot(snapshot, 'key1' => 'value1', 2 => 2, 'key3' => nil)
-
- expect(snapshot).to have_received(:update_metadata).with('key1' => 'value1', '2' => '2')
- end
- end
-
- describe '.format' do
- it 'trims key and value length' do
- formatted_tags = Bosh::OpenStackCloud::TagManager.format('x' * 256 => 'y' * 256)
-
- expect(formatted_tags).to eq('x' * 255 => 'y' * 255)
- end
-
- it 'converts all keys and value to strings' do
- formatted_tags = Bosh::OpenStackCloud::TagManager.format(1 => 5)
-
- expect(formatted_tags).to eq('1' => '5')
- end
-
- it 'does nothing if key is nil' do
- formatted_tags = Bosh::OpenStackCloud::TagManager.format(nil => 'value')
-
- expect(formatted_tags).to eq({})
- end
-
- it 'does nothing if value is nil' do
- formatted_tags = Bosh::OpenStackCloud::TagManager.format('key' => nil)
-
- expect(formatted_tags).to eq({})
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/vip_network_spec.rb b/src/bosh_openstack_cpi/spec/unit/vip_network_spec.rb
deleted file mode 100644
index c857b3c38..000000000
--- a/src/bosh_openstack_cpi/spec/unit/vip_network_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::VipNetwork do
- describe 'configure' do
- subject do
- described_class.new('network_b', network_spec)
- end
-
- let(:network_spec) { vip_network_spec }
-
- context 'no floating IP provided for vip network' do
- before(:each) do
- network_spec['ip'] = nil
- end
-
- it 'fails' do
- expect {
- subject.configure(nil, nil, nil)
- }.to raise_error Bosh::Clouds::CloudError, /No IP provided for vip network/
- end
- end
-
- context 'floating IP is provided' do
- let(:openstack) { double('openstack') }
- before { allow(openstack).to receive(:with_openstack) { |&block| block.call } }
-
- it 'calls FloatingIp.reassiciate' do
- server = double('server')
- allow(Bosh::OpenStackCloud::FloatingIp).to receive(:reassociate)
-
- subject.configure(openstack, server, 'network_id')
-
- expect(Bosh::OpenStackCloud::FloatingIp).to have_received(:reassociate).with(openstack, '10.0.0.1', server, 'network_id')
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/vm_creator_spec.rb b/src/bosh_openstack_cpi/spec/unit/vm_creator_spec.rb
deleted file mode 100644
index 467a76f4d..000000000
--- a/src/bosh_openstack_cpi/spec/unit/vm_creator_spec.rb
+++ /dev/null
@@ -1,130 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::VmCreator do
- subject(:vm_creator) do
- described_class.new(
- cloud,
- network_configurator,
- server,
- az_provider,
- cloud_properties,
- agent_settings,
- create_vm_params,
- )
- end
-
- let(:cloud) { double }
- let(:network_configurator) { instance_double(Bosh::OpenStackCloud::NetworkConfigurator, prepare: nil, cleanup: nil) }
- let(:server) { double }
- let(:multiple_azs) { false }
- let(:az_provider) do
- instance_double(
- Bosh::OpenStackCloud::AvailabilityZoneProvider,
- use_multiple_azs?: multiple_azs,
- select: nil,
- )
- end
- let(:cloud_properties) { {} }
- let(:agent_settings) { double }
- let(:create_vm_params) { {} }
- let(:manual_network) { { 'network_a' => manual_network_spec(ip: '10.0.0.1') } }
- let(:environment) { { 'test_env' => 'value' } }
-
- describe 'perform' do
- before do
- allow(server).to receive(:create)
- end
-
- context 'when vm creation fails' do
- before(:each) do
- allow(server).to receive(:create).and_raise 'BOOM!!!'
- allow(network_configurator).to receive(:prepare)
- end
-
- it 'cleans up network resources' do
- expect(network_configurator).to receive(:cleanup)
-
- expect {
- subject.perform
- }.to raise_error RuntimeError, 'BOOM!!!'
- end
-
- it 'ignores but warns about network resource cleanup failures' do
- allow(network_configurator).to receive(:cleanup).and_raise 'BOOM Cleanup!!!'
-
- expect {
- subject.perform
- }.to raise_error RuntimeError, 'BOOM!!!'
- end
- end
-
- context 'when using availability_zone' do
- before do
- allow(az_provider).to receive(:select).and_return('az1')
- end
-
- it 'calls create server once' do
- subject.perform
- expect(server).to have_received(:create).with(anything, anything, anything, include(availability_zone: 'az1'))
- end
- end
-
- context 'when using availability_zones' do
- let(:multiple_azs) { true }
-
- before do
- allow(az_provider).to receive(:select_azs).and_return(['az1', 'az2'])
- end
-
- it 'calls create server with the first zone' do
- vm_creator.perform
- expect(server).to have_received(:create).with(anything, anything, anything, include(availability_zone: 'az1'))
- end
-
- context 'when the first create server fails' do
- it 'calls create server with the second zone and logs retrying' do
- expect(network_configurator).to receive(:prepare).once
- expect(server).to receive(:create)
- .with(anything, anything, anything, include(availability_zone: 'az1'))
- .and_raise('create-error')
-
- expect(server).to receive(:create).with(anything, anything, anything, include(availability_zone: 'az2'))
-
- vm_creator.perform
-
- expect(Bosh::Clouds::Config.logger).to have_received(:warn)
- .with("Failed to create VM in AZ 'az1' with error 'create-error', retrying in a different AZ")
- end
- end
-
- context 'when all create servers fails' do
- before do
- expect(network_configurator).to receive(:cleanup).once
- expect(network_configurator).to receive(:prepare).once
-
- expect(server).to receive(:create)
- .with(anything, anything, anything, include(availability_zone: 'az1'))
- .and_raise('create-error-1')
- expect(server).to receive(:create)
- .with(anything, anything, anything, include(availability_zone: 'az2'))
- .and_raise('create-error-2')
- end
-
- it 'raises an error and logs the number of retries' do
- expect { vm_creator.perform }.to raise_error('create-error-2')
-
- expect(Bosh::Clouds::Config.logger).to have_received(:error)
- .with("Failed to create VM in AZ 'az2' with error 'create-error-2' after 2 retries. No AZs left to retry.")
- end
-
- it 'ignores but warns about network resource cleanup failures' do
- allow(network_configurator).to receive(:cleanup).and_raise 'BOOM Cleanup!!!'
- expect(Bosh::Clouds::Config.logger).to receive(:warn)
- .with('Failed to cleanup network resources: BOOM Cleanup!!!')
-
- expect { subject.perform }.to raise_error('create-error-2')
- end
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/spec/unit/volume_configurator_spec.rb b/src/bosh_openstack_cpi/spec/unit/volume_configurator_spec.rb
deleted file mode 100644
index 82b68252d..000000000
--- a/src/bosh_openstack_cpi/spec/unit/volume_configurator_spec.rb
+++ /dev/null
@@ -1,182 +0,0 @@
-require 'spec_helper'
-
-describe Bosh::OpenStackCloud::VolumeConfigurator do
- let(:logger) do
- logger = double('logger')
- allow(logger).to receive(:debug)
- allow(logger).to receive(:error)
- logger
- end
- subject { Bosh::OpenStackCloud::VolumeConfigurator.new(logger) }
- describe 'select_boot_volume_size' do
- context 'when the flavor has no disk' do
- let(:flavor) { double('flavor', disk: 0, name: 'mock_flavor_without_disk') }
-
- context 'and resource pool contains root_disk.size > 1' do
- let(:resource_pool) { { 'root_disk' => { 'size' => 50 } } }
-
- it 'takes root disk size from resource pool as boot_volume size' do
- boot_volume_size = subject.select_boot_volume_size(flavor, resource_pool)
- expect(boot_volume_size).to be(50)
- end
- end
-
- context 'and resource pool contains root_disk.size = 1' do
- let(:resource_pool) { { 'root_disk' => { 'size' => 1 } } }
-
- it 'takes root disk size from resource pool as boot_volume size' do
- boot_volume_size = subject.select_boot_volume_size(flavor, resource_pool)
- expect(boot_volume_size).to be(1)
- end
- end
-
- context 'and resource pool contains root_disk.size < 1' do
- let(:resource_pool) { { 'root_disk' => { 'size' => 0 } } }
-
- it 'throw an error' do
- expect {
- subject.select_boot_volume_size(flavor, resource_pool)
- }.to raise_error(ArgumentError, 'Minimum root_disk size is 1 GiB')
- end
- end
-
- context 'root_disk not defined in resource pool' do
- let(:resource_pool) { {} }
-
- it 'takes the root disk size from the flavor' do
- expect {
- subject.select_boot_volume_size(flavor, resource_pool)
- }.to raise_error(Bosh::Clouds::CloudError, "Flavor 'mock_flavor_without_disk' has a root disk size of 0. Either pick a different flavor or define root_disk.size in your VM cloud_properties")
- end
- end
-
- context 'root_disk.size not defined in resource pool' do
- let(:resource_pool) { { 'root_disk' => {} } }
-
- it 'throw an error' do
- expect {
- subject.select_boot_volume_size(flavor, resource_pool)
- }.to raise_error(ArgumentError, 'Minimum root_disk size is 1 GiB')
- end
- end
- end
-
- context 'when the flavor has disk' do
- let(:flavor) { double('flavor', disk: 10) }
-
- context 'and resource pool contains root_disk.size > 1' do
- let(:resource_pool) { { 'root_disk' => { 'size' => 50 } } }
-
- it 'takes root disk size from resource pool as boot_volume size' do
- boot_volume_size = subject.select_boot_volume_size(flavor, resource_pool)
- expect(boot_volume_size).to be(50)
- end
- end
-
- context 'and resource pool contains root_disk.size = 1' do
- let(:resource_pool) { { 'root_disk' => { 'size' => 1 } } }
-
- it 'takes root disk size from resource pool as boot_volume size' do
- boot_volume_size = subject.select_boot_volume_size(flavor, resource_pool)
- expect(boot_volume_size).to be(1)
- end
- end
-
- context 'and resource pool contains root_disk.size < 1' do
- let(:resource_pool) { { 'root_disk' => { 'size' => 0 } } }
-
- it 'throw an error' do
- expect {
- subject.select_boot_volume_size(flavor, resource_pool)
- }.to raise_error(ArgumentError, 'Minimum root_disk size is 1 GiB')
- end
- end
-
- context 'root_disk not defined in resource pool' do
- let(:resource_pool) { {} }
-
- it 'takes the root disk size from the flavor' do
- boot_volume_size = subject.select_boot_volume_size(flavor, resource_pool)
-
- expect(boot_volume_size).to be(10)
- end
- end
-
- context 'root_disk.size not defined in resource pool' do
- let(:resource_pool) { { 'root_disk' => {} } }
-
- it 'throw an error' do
- expect {
- subject.select_boot_volume_size(flavor, resource_pool)
- }.to raise_error(ArgumentError, 'Minimum root_disk size is 1 GiB')
- end
- end
- end
- end
-
- describe 'boot_from_volume?' do
- context 'when global setting for boot_from_volume is false' do
- context 'when boot_from_volume set for vm type' do
- let(:resource_pool) { { 'boot_from_volume' => true } }
-
- it 'returns true' do
- boot_from_volume = subject.boot_from_volume?(false, resource_pool)
-
- expect(boot_from_volume).to be(true)
- end
- end
-
- context 'when boot_from_volume set to false for vm type' do
- let(:resource_pool) { { 'boot_from_volume' => false } }
-
- it 'returns false' do
- boot_from_volume = subject.boot_from_volume?(false, resource_pool)
-
- expect(boot_from_volume).to be(false)
- end
- end
-
- context 'when boot_from_volume is not set for vm type' do
- let(:resource_pool) { {} }
-
- it 'returns false' do
- boot_from_volume = subject.boot_from_volume?(false, resource_pool)
-
- expect(boot_from_volume).to be(false)
- end
- end
- end
-
- context 'when global setting for boot_from_volume is true' do
- context 'when boot_from_volume is not set for vm type' do
- let(:resource_pool) { {} }
-
- it 'it returns true' do
- boot_from_volume = subject.boot_from_volume?(true, resource_pool)
-
- expect(boot_from_volume).to be(true)
- end
- end
-
- context 'when boot_from_volume is set to false for vm type' do
- let(:resource_pool) { { 'boot_from_volume' => false } }
-
- it 'it returns true' do
- boot_from_volume = subject.boot_from_volume?(true, resource_pool)
-
- expect(boot_from_volume).to be(false)
- end
- end
-
- context 'when boot_from_volume is set to true for vm type' do
- let(:resource_pool) { { 'boot_from_volume' => true } }
-
- it 'it returns true' do
- boot_from_volume = subject.boot_from_volume?(true, resource_pool)
-
- expect(boot_from_volume).to be(true)
- end
- end
- end
- end
-end
diff --git a/src/bosh_openstack_cpi/vendor/package/addressable-2.8.7.gem b/src/bosh_openstack_cpi/vendor/package/addressable-2.8.7.gem
deleted file mode 100644
index c355e1246..000000000
--- a/src/bosh_openstack_cpi/vendor/package/addressable-2.8.7.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:462986537cf3735ab5f3c0f557f14155d778f4b43ea4f485a9deb9c8f7c58232
-size 106496
diff --git a/src/bosh_openstack_cpi/vendor/package/ast-2.4.3.gem b/src/bosh_openstack_cpi/vendor/package/ast-2.4.3.gem
deleted file mode 100644
index d623cef02..000000000
--- a/src/bosh_openstack_cpi/vendor/package/ast-2.4.3.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
-size 11776
diff --git a/src/bosh_openstack_cpi/vendor/package/bigdecimal-3.2.2.gem b/src/bosh_openstack_cpi/vendor/package/bigdecimal-3.2.2.gem
deleted file mode 100644
index 84667edcc..000000000
--- a/src/bosh_openstack_cpi/vendor/package/bigdecimal-3.2.2.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:39085f76b495eb39a79ce07af716f3a6829bc35eb44f2195e2753749f2fa5adc
-size 88576
diff --git a/src/bosh_openstack_cpi/vendor/package/bosh-template-2.4.0.gem b/src/bosh_openstack_cpi/vendor/package/bosh-template-2.4.0.gem
deleted file mode 100644
index b51ec4e5f..000000000
--- a/src/bosh_openstack_cpi/vendor/package/bosh-template-2.4.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:2d8ff9a4bac75ab166c9ab44364b8b4bcc33831238003edf02cc95f99fe201e5
-size 10240
diff --git a/src/bosh_openstack_cpi/vendor/package/bosh_common-2.0.0.gem b/src/bosh_openstack_cpi/vendor/package/bosh_common-2.0.0.gem
deleted file mode 100644
index c18a262fe..000000000
--- a/src/bosh_openstack_cpi/vendor/package/bosh_common-2.0.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:364f205d802fd43e15c3583e70176e2d7ce7b3ab9338c4239860fc75308011c2
-size 12288
diff --git a/src/bosh_openstack_cpi/vendor/package/bosh_cpi-2.6.0.gem b/src/bosh_openstack_cpi/vendor/package/bosh_cpi-2.6.0.gem
deleted file mode 100644
index 0daa21736..000000000
--- a/src/bosh_openstack_cpi/vendor/package/bosh_cpi-2.6.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:c6303e85420d0e3a77a4481117f3bed2beb3ffb563e367b2b73beb1496272d6f
-size 10752
diff --git a/src/bosh_openstack_cpi/vendor/package/builder-3.3.0.gem b/src/bosh_openstack_cpi/vendor/package/builder-3.3.0.gem
deleted file mode 100644
index 8fee94b74..000000000
--- a/src/bosh_openstack_cpi/vendor/package/builder-3.3.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
-size 30208
diff --git a/src/bosh_openstack_cpi/vendor/package/byebug-12.0.0.gem b/src/bosh_openstack_cpi/vendor/package/byebug-12.0.0.gem
deleted file mode 100644
index 9244b7d2f..000000000
--- a/src/bosh_openstack_cpi/vendor/package/byebug-12.0.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:d4a150d291cca40b66ec9ca31f754e93fed8aa266a17335f71bb0afa7fca1a1e
-size 84992
diff --git a/src/bosh_openstack_cpi/vendor/package/coderay-1.1.3.gem b/src/bosh_openstack_cpi/vendor/package/coderay-1.1.3.gem
deleted file mode 100644
index ea8d4e656..000000000
--- a/src/bosh_openstack_cpi/vendor/package/coderay-1.1.3.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b
-size 92672
diff --git a/src/bosh_openstack_cpi/vendor/package/crack-1.0.0.gem b/src/bosh_openstack_cpi/vendor/package/crack-1.0.0.gem
deleted file mode 100644
index 50ed66033..000000000
--- a/src/bosh_openstack_cpi/vendor/package/crack-1.0.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:c83aefdb428cdc7b66c7f287e488c796f055c0839e6e545fec2c7047743c4a49
-size 10752
diff --git a/src/bosh_openstack_cpi/vendor/package/diff-lcs-1.6.2.gem b/src/bosh_openstack_cpi/vendor/package/diff-lcs-1.6.2.gem
deleted file mode 100644
index 3d7b961cd..000000000
--- a/src/bosh_openstack_cpi/vendor/package/diff-lcs-1.6.2.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
-size 59392
diff --git a/src/bosh_openstack_cpi/vendor/package/excon-1.2.8.gem b/src/bosh_openstack_cpi/vendor/package/excon-1.2.8.gem
deleted file mode 100644
index dee2814f2..000000000
--- a/src/bosh_openstack_cpi/vendor/package/excon-1.2.8.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:150f57a0f3919b8d2b3f74535596f9876389c6dde157e0bfac8f26631eb135d0
-size 171008
diff --git a/src/bosh_openstack_cpi/vendor/package/fog-core-2.6.0.gem b/src/bosh_openstack_cpi/vendor/package/fog-core-2.6.0.gem
deleted file mode 100644
index b1df95156..000000000
--- a/src/bosh_openstack_cpi/vendor/package/fog-core-2.6.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:3fe08aa83a23cddce42f4ba412040c08f890d7ff04c175c0ee59119371245be6
-size 47104
diff --git a/src/bosh_openstack_cpi/vendor/package/fog-json-1.2.0.gem b/src/bosh_openstack_cpi/vendor/package/fog-json-1.2.0.gem
deleted file mode 100644
index 5c90c82ef..000000000
--- a/src/bosh_openstack_cpi/vendor/package/fog-json-1.2.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:dd4f5ab362dbc72b687240bba9d2dd841d5dfe888a285797533f85c03ea548fe
-size 8704
diff --git a/src/bosh_openstack_cpi/vendor/package/fog-openstack-1.1.5.gem b/src/bosh_openstack_cpi/vendor/package/fog-openstack-1.1.5.gem
deleted file mode 100644
index 0b235b625..000000000
--- a/src/bosh_openstack_cpi/vendor/package/fog-openstack-1.1.5.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:46472a9a50416b99086d67e038f476d57fc5064805fe6ea60ccdf2ec0f13bd46
-size 233472
diff --git a/src/bosh_openstack_cpi/vendor/package/formatador-1.1.1.gem b/src/bosh_openstack_cpi/vendor/package/formatador-1.1.1.gem
deleted file mode 100644
index 4405a7f2d..000000000
--- a/src/bosh_openstack_cpi/vendor/package/formatador-1.1.1.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:cd0870fb00738204c98e9239f81fadc6f7966724d8037ba471684ed180fabbeb
-size 14336
diff --git a/src/bosh_openstack_cpi/vendor/package/hashdiff-1.2.0.gem b/src/bosh_openstack_cpi/vendor/package/hashdiff-1.2.0.gem
deleted file mode 100644
index a96465111..000000000
--- a/src/bosh_openstack_cpi/vendor/package/hashdiff-1.2.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:c984f13e115bfc9953332e8e83bd9d769cfde9944e2d54e07eb9df7b76e140b5
-size 17408
diff --git a/src/bosh_openstack_cpi/vendor/package/httpclient-2.8.3.gem b/src/bosh_openstack_cpi/vendor/package/httpclient-2.8.3.gem
deleted file mode 100644
index 1865ae043..000000000
--- a/src/bosh_openstack_cpi/vendor/package/httpclient-2.8.3.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:2951e4991214464c3e92107e46438527d23048e634f3aee91c719e0bdfaebda6
-size 385536
diff --git a/src/bosh_openstack_cpi/vendor/package/json-2.13.0.gem b/src/bosh_openstack_cpi/vendor/package/json-2.13.0.gem
deleted file mode 100644
index 0df5124b1..000000000
--- a/src/bosh_openstack_cpi/vendor/package/json-2.13.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:a4bdf1ce8db5617ec6c59e021db4a398e54b57b335e1fa417ac7badc3fb7c1a0
-size 77312
diff --git a/src/bosh_openstack_cpi/vendor/package/language_server-protocol-3.17.0.5.gem b/src/bosh_openstack_cpi/vendor/package/language_server-protocol-3.17.0.5.gem
deleted file mode 100644
index d32baa7c1..000000000
--- a/src/bosh_openstack_cpi/vendor/package/language_server-protocol-3.17.0.5.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
-size 78336
diff --git a/src/bosh_openstack_cpi/vendor/package/lint_roller-1.1.0.gem b/src/bosh_openstack_cpi/vendor/package/lint_roller-1.1.0.gem
deleted file mode 100644
index d8a70e584..000000000
--- a/src/bosh_openstack_cpi/vendor/package/lint_roller-1.1.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
-size 9728
diff --git a/src/bosh_openstack_cpi/vendor/package/little-plugger-1.1.4.gem b/src/bosh_openstack_cpi/vendor/package/little-plugger-1.1.4.gem
deleted file mode 100644
index 389443155..000000000
--- a/src/bosh_openstack_cpi/vendor/package/little-plugger-1.1.4.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:d5f347c00d9d648040ef7c17d6eb09d3d0719adf19ca30d1a3b6fb26d0a631bb
-size 10240
diff --git a/src/bosh_openstack_cpi/vendor/package/logger-1.7.0.gem b/src/bosh_openstack_cpi/vendor/package/logger-1.7.0.gem
deleted file mode 100644
index 6f07b5902..000000000
--- a/src/bosh_openstack_cpi/vendor/package/logger-1.7.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
-size 16896
diff --git a/src/bosh_openstack_cpi/vendor/package/logging-2.2.2.gem b/src/bosh_openstack_cpi/vendor/package/logging-2.2.2.gem
deleted file mode 100644
index 4ca0c72f5..000000000
--- a/src/bosh_openstack_cpi/vendor/package/logging-2.2.2.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:963359dbdab725a3320eab179017d20d5b9731d7148e1efa8432c184a48a461a
-size 87552
diff --git a/src/bosh_openstack_cpi/vendor/package/membrane-1.1.0.gem b/src/bosh_openstack_cpi/vendor/package/membrane-1.1.0.gem
deleted file mode 100644
index b14d7e56a..000000000
--- a/src/bosh_openstack_cpi/vendor/package/membrane-1.1.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:ab84429a9ea9e90e1a568b81f8ed4b03ad388b0aa2202ab97c5b30d210c9c7ff
-size 20480
diff --git a/src/bosh_openstack_cpi/vendor/package/method_source-1.1.0.gem b/src/bosh_openstack_cpi/vendor/package/method_source-1.1.0.gem
deleted file mode 100644
index 59abbed7e..000000000
--- a/src/bosh_openstack_cpi/vendor/package/method_source-1.1.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:181301c9c45b731b4769bc81e8860e72f9161ad7d66dd99103c9ab84f560f5c5
-size 13824
diff --git a/src/bosh_openstack_cpi/vendor/package/mime-types-3.7.0.gem b/src/bosh_openstack_cpi/vendor/package/mime-types-3.7.0.gem
deleted file mode 100644
index 6cb3bb394..000000000
--- a/src/bosh_openstack_cpi/vendor/package/mime-types-3.7.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:dcebf61c246f08e15a4de34e386ebe8233791e868564a470c3fe77c00eed5e56
-size 41984
diff --git a/src/bosh_openstack_cpi/vendor/package/mime-types-data-3.2025.0715.gem b/src/bosh_openstack_cpi/vendor/package/mime-types-data-3.2025.0715.gem
deleted file mode 100644
index 6b107a9b1..000000000
--- a/src/bosh_openstack_cpi/vendor/package/mime-types-data-3.2025.0715.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:865f9759d5db11f983086a70379f8282e2e64fba7b82058b928c63a7ab79871d
-size 169472
diff --git a/src/bosh_openstack_cpi/vendor/package/multi_json-1.17.0.gem b/src/bosh_openstack_cpi/vendor/package/multi_json-1.17.0.gem
deleted file mode 100644
index ba9130ec1..000000000
--- a/src/bosh_openstack_cpi/vendor/package/multi_json-1.17.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:76581f6c96aebf2e85f8a8b9854829e0988f335e8671cd1a56a1036eb75e4a1b
-size 22016
diff --git a/src/bosh_openstack_cpi/vendor/package/netaddr-2.0.6.gem b/src/bosh_openstack_cpi/vendor/package/netaddr-2.0.6.gem
deleted file mode 100644
index f6c98c278..000000000
--- a/src/bosh_openstack_cpi/vendor/package/netaddr-2.0.6.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:e7c3970ec2c2665aa25c4cbf268011d01f5d98c33182e600759a49961e63f1b4
-size 23552
diff --git a/src/bosh_openstack_cpi/vendor/package/openssl-3.3.0.gem b/src/bosh_openstack_cpi/vendor/package/openssl-3.3.0.gem
deleted file mode 100644
index 5cfa59107..000000000
--- a/src/bosh_openstack_cpi/vendor/package/openssl-3.3.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:ff3a573fc97ab30f69483fddc80029f91669bf36532859bd182d1836f45aee79
-size 207872
diff --git a/src/bosh_openstack_cpi/vendor/package/parallel-1.27.0.gem b/src/bosh_openstack_cpi/vendor/package/parallel-1.27.0.gem
deleted file mode 100644
index e4a6ff778..000000000
--- a/src/bosh_openstack_cpi/vendor/package/parallel-1.27.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
-size 10752
diff --git a/src/bosh_openstack_cpi/vendor/package/parser-3.3.8.0.gem b/src/bosh_openstack_cpi/vendor/package/parser-3.3.8.0.gem
deleted file mode 100644
index e5c969590..000000000
--- a/src/bosh_openstack_cpi/vendor/package/parser-3.3.8.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:2476364142b307fa5a1b1ece44f260728be23858a9c71078e956131a75453c45
-size 911872
diff --git a/src/bosh_openstack_cpi/vendor/package/prism-1.4.0.gem b/src/bosh_openstack_cpi/vendor/package/prism-1.4.0.gem
deleted file mode 100644
index 90ce6a1eb..000000000
--- a/src/bosh_openstack_cpi/vendor/package/prism-1.4.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:dc0e3e00e93160213dc2a65519d9002a4a1e7b962db57d444cf1a71565bb703e
-size 632832
diff --git a/src/bosh_openstack_cpi/vendor/package/pry-0.15.2.gem b/src/bosh_openstack_cpi/vendor/package/pry-0.15.2.gem
deleted file mode 100644
index 3183ecfb4..000000000
--- a/src/bosh_openstack_cpi/vendor/package/pry-0.15.2.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:12d54b8640d3fa29c9211dd4ffb08f3fd8bf7a4fd9b5a73ce5b59c8709385b6b
-size 155648
diff --git a/src/bosh_openstack_cpi/vendor/package/pry-byebug-3.11.0.gem b/src/bosh_openstack_cpi/vendor/package/pry-byebug-3.11.0.gem
deleted file mode 100644
index 581104428..000000000
--- a/src/bosh_openstack_cpi/vendor/package/pry-byebug-3.11.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:0b0abb7d309bc7f00044d512a3c8567274f7012b944b38becc8440439a1cea72
-size 15872
diff --git a/src/bosh_openstack_cpi/vendor/package/public_suffix-6.0.2.gem b/src/bosh_openstack_cpi/vendor/package/public_suffix-6.0.2.gem
deleted file mode 100644
index acb6e46e2..000000000
--- a/src/bosh_openstack_cpi/vendor/package/public_suffix-6.0.2.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:bfa7cd5108066f8c9602e0d6d4114999a5df5839a63149d3e8b0f9c1d3558394
-size 104960
diff --git a/src/bosh_openstack_cpi/vendor/package/racc-1.8.1.gem b/src/bosh_openstack_cpi/vendor/package/racc-1.8.1.gem
deleted file mode 100644
index 95c198e66..000000000
--- a/src/bosh_openstack_cpi/vendor/package/racc-1.8.1.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
-size 65536
diff --git a/src/bosh_openstack_cpi/vendor/package/rainbow-3.1.1.gem b/src/bosh_openstack_cpi/vendor/package/rainbow-3.1.1.gem
deleted file mode 100644
index 261f3d0e6..000000000
--- a/src/bosh_openstack_cpi/vendor/package/rainbow-3.1.1.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
-size 13824
diff --git a/src/bosh_openstack_cpi/vendor/package/rake-13.3.0.gem b/src/bosh_openstack_cpi/vendor/package/rake-13.3.0.gem
deleted file mode 100644
index 319c2a13a..000000000
--- a/src/bosh_openstack_cpi/vendor/package/rake-13.3.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:96f5092d786ff412c62fde76f793cc0541bd84d2eb579caa529aa8a059934493
-size 86528
diff --git a/src/bosh_openstack_cpi/vendor/package/rb-readline-0.5.5.gem b/src/bosh_openstack_cpi/vendor/package/rb-readline-0.5.5.gem
deleted file mode 100644
index 54142d62f..000000000
--- a/src/bosh_openstack_cpi/vendor/package/rb-readline-0.5.5.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:9e9bd7e198bdef0822c46902f6c592b882c1f9777894a4c3dcf5b320824a8793
-size 96768
diff --git a/src/bosh_openstack_cpi/vendor/package/regexp_parser-2.10.0.gem b/src/bosh_openstack_cpi/vendor/package/regexp_parser-2.10.0.gem
deleted file mode 100644
index 799292169..000000000
--- a/src/bosh_openstack_cpi/vendor/package/regexp_parser-2.10.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:cb6f0ddde88772cd64bff1dbbf68df66d376043fe2e66a9ef77fcb1b0c548c61
-size 58880
diff --git a/src/bosh_openstack_cpi/vendor/package/rexml-3.4.1.gem b/src/bosh_openstack_cpi/vendor/package/rexml-3.4.1.gem
deleted file mode 100644
index 69ff1e000..000000000
--- a/src/bosh_openstack_cpi/vendor/package/rexml-3.4.1.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:c74527a9a0a04b4ec31dbe0dc4ed6004b960af943d8db42e539edde3a871abca
-size 104960
diff --git a/src/bosh_openstack_cpi/vendor/package/rspec-3.13.1.gem b/src/bosh_openstack_cpi/vendor/package/rspec-3.13.1.gem
deleted file mode 100644
index 5d42482d3..000000000
--- a/src/bosh_openstack_cpi/vendor/package/rspec-3.13.1.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:b9f9a58fa915b8d94a1d6b3195fe6dd28c4c34836a6097015142c4a9ace72140
-size 10752
diff --git a/src/bosh_openstack_cpi/vendor/package/rspec-core-3.13.5.gem b/src/bosh_openstack_cpi/vendor/package/rspec-core-3.13.5.gem
deleted file mode 100644
index 8a8f32f01..000000000
--- a/src/bosh_openstack_cpi/vendor/package/rspec-core-3.13.5.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:ab3f682897c6131c67f9a17cfee5022a597f283aebe654d329a565f9937a4fa3
-size 167424
diff --git a/src/bosh_openstack_cpi/vendor/package/rspec-expectations-3.13.5.gem b/src/bosh_openstack_cpi/vendor/package/rspec-expectations-3.13.5.gem
deleted file mode 100644
index 7dbc9e488..000000000
--- a/src/bosh_openstack_cpi/vendor/package/rspec-expectations-3.13.5.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
-size 89600
diff --git a/src/bosh_openstack_cpi/vendor/package/rspec-its-2.0.0.gem b/src/bosh_openstack_cpi/vendor/package/rspec-its-2.0.0.gem
deleted file mode 100644
index a65c4511e..000000000
--- a/src/bosh_openstack_cpi/vendor/package/rspec-its-2.0.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:a88e8bc38149f2835e93533591ec4f5c829aacbfd41269a2e6f9f5b82f5260df
-size 15360
diff --git a/src/bosh_openstack_cpi/vendor/package/rspec-mocks-3.13.5.gem b/src/bosh_openstack_cpi/vendor/package/rspec-mocks-3.13.5.gem
deleted file mode 100644
index 026c87c75..000000000
--- a/src/bosh_openstack_cpi/vendor/package/rspec-mocks-3.13.5.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:e4338a6f285ada9fe56f5893f5457783af8194f5d08884d17a87321d5195ea81
-size 82944
diff --git a/src/bosh_openstack_cpi/vendor/package/rspec-support-3.13.4.gem b/src/bosh_openstack_cpi/vendor/package/rspec-support-3.13.4.gem
deleted file mode 100644
index a6d2213dc..000000000
--- a/src/bosh_openstack_cpi/vendor/package/rspec-support-3.13.4.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:184b1814f6a968102b57df631892c7f1990a91c9a3b9e80ef892a0fc2a71a3f7
-size 40448
diff --git a/src/bosh_openstack_cpi/vendor/package/rubocop-1.78.0.gem b/src/bosh_openstack_cpi/vendor/package/rubocop-1.78.0.gem
deleted file mode 100644
index c1aeff66b..000000000
--- a/src/bosh_openstack_cpi/vendor/package/rubocop-1.78.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:8b74a6f912eb4fd3e6878851f7f7f45dcad8c7185c34250d4f952b0ee80d6bc0
-size 713216
diff --git a/src/bosh_openstack_cpi/vendor/package/rubocop-ast-1.46.0.gem b/src/bosh_openstack_cpi/vendor/package/rubocop-ast-1.46.0.gem
deleted file mode 100644
index ed8cd011c..000000000
--- a/src/bosh_openstack_cpi/vendor/package/rubocop-ast-1.46.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:0da7f6ad5b98614f89b74f11873c191059c823eae07d6ffd40a42a3338f2232b
-size 61440
diff --git a/src/bosh_openstack_cpi/vendor/package/ruby-progressbar-1.13.0.gem b/src/bosh_openstack_cpi/vendor/package/ruby-progressbar-1.13.0.gem
deleted file mode 100644
index 04a8e4b00..000000000
--- a/src/bosh_openstack_cpi/vendor/package/ruby-progressbar-1.13.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
-size 19456
diff --git a/src/bosh_openstack_cpi/vendor/package/semi_semantic-1.2.0.gem b/src/bosh_openstack_cpi/vendor/package/semi_semantic-1.2.0.gem
deleted file mode 100644
index 4fb71c727..000000000
--- a/src/bosh_openstack_cpi/vendor/package/semi_semantic-1.2.0.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:1fa2d74b075b0dbd2c055cb2a033685a2b79c9c2207afa5c072c207797aaa040
-size 6656
diff --git a/src/bosh_openstack_cpi/vendor/package/timecop-0.9.10.gem b/src/bosh_openstack_cpi/vendor/package/timecop-0.9.10.gem
deleted file mode 100644
index 8032df241..000000000
--- a/src/bosh_openstack_cpi/vendor/package/timecop-0.9.10.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:12ba45ce57cdcf6b1043cb6cdffa6381fd89ce10d369c28a7f6f04dc1b0cd8eb
-size 12800
diff --git a/src/bosh_openstack_cpi/vendor/package/unicode-display_width-3.1.4.gem b/src/bosh_openstack_cpi/vendor/package/unicode-display_width-3.1.4.gem
deleted file mode 100644
index 44c2450ad..000000000
--- a/src/bosh_openstack_cpi/vendor/package/unicode-display_width-3.1.4.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:8caf2af1c0f2f07ec89ef9e18c7d88c2790e217c482bfc78aaa65eadd5415ac1
-size 18432
diff --git a/src/bosh_openstack_cpi/vendor/package/unicode-emoji-4.0.4.gem b/src/bosh_openstack_cpi/vendor/package/unicode-emoji-4.0.4.gem
deleted file mode 100644
index 37cbb19d7..000000000
--- a/src/bosh_openstack_cpi/vendor/package/unicode-emoji-4.0.4.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:2c2c4ef7f353e5809497126285a50b23056cc6e61b64433764a35eff6c36532a
-size 167936
diff --git a/src/bosh_openstack_cpi/vendor/package/webmock-3.25.1.gem b/src/bosh_openstack_cpi/vendor/package/webmock-3.25.1.gem
deleted file mode 100644
index d57ec4f0f..000000000
--- a/src/bosh_openstack_cpi/vendor/package/webmock-3.25.1.gem
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:ab9d5d9353bcbe6322c83e1c60a7103988efc7b67cd72ffb9012629c3d396323
-size 71168