Giter Site home page Giter Site logo

terraform-provider-cloudfoundry's Introduction

terraform-provider-cloudfoundry Build Status

Depreciation and migration steps

This provider is being deprecated in favor of https://github.com/mevansam/terraform-provider-cf which aims at moving to the https://github.com/terraform-providers github organization and becoming an official terraform provider.

The migration from terraform-provider-cloudfoundry to terraform-provider-cf can follow the procedure below:

  • manually convert the config file from the terraform-provider-cloudfoundry resource to terraform-provider-cf resources. This can be made easier through IDE completion, see cloudfoundry-community/terraform-provider-cloudfoundry#4
  • import CF resources into TF state. For each resource type:
    • Identify current resources and their ids, e.g. terraform state list | grep cloudfoundry_domain | xargs -n 1 terraform state show
    • Import the resource in TF state (manually for through upcoming importeability support in terraform-provider-cf
    • Remove the terraform-provider-cloudfoundry resource from tfstate e.g. terraform state list | grep cloudfoundry_domain | xargs -n 1 terraform state remove

Potentially, such migration steps can be automated and scheduled into CI/CD such as ljfranklin/terraform-resource#41

Overview

This terraform provider supports the use-case of managing a Cloud Foundry instance, with current support for:

You can also find useful terraform modules at https://github.com/orange-cloudfoundry/terraform-cloudfoundry-modules.

Installations

Requirements: You need, of course, terraform (>=0.8) which is available here: https://www.terraform.io/downloads.html

Automatic

To install a specific version, set PROVIDER_CLOUDFOUNDRY_VERSION before executing the following command

$ export PROVIDER_CLOUDFOUNDRY_VERSION="v0.9.1"

via curl

$ bash -c "$(curl -fsSL https://raw.github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/master/bin/install.sh)"

via wget

$ bash -c "$(wget https://raw.github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/master/bin/install.sh -O -)"

Manually

  1. Get the build for your system in releases: https://github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/releases/latest
  2. Create a providers directory inside terraform user folder: mkdir -p ~/.terraform.d/providers
  3. Move the provider previously downloaded in this folder: mv /path/to/download/directory/terraform-provider-cloudfoundry ~/.terraform.d/providers
  4. Ensure provider is executable: chmod +x ~/.terraform.d/providers/terraform-provider-cloudfoundry
  5. add providers path to your .terraformrc:
cat <<EOF > ~/.terraformrc
providers {
    cloudfoundry = "/full/path/to/.terraform.d/providers/terraform-provider-cloudfoundry"
}
EOF
  1. you can now performs any terraform action on Cloud Foundry resources

provider configuration

provider "cloudfoundry" {
  api_endpoint = "https://api.of.your.cloudfoundry.com"
  username = "user"
  password = "mypassword"
  skip_ssl_validation = true
  enc_private_key = "${file("secring_b64.gpg")}"
  enc_passphrase = "mypassphrase"
  verbose = false
  user_access_token = "bearer key"
  user_refresh_token = "bearer key"
}
  • name: (Required, Env Var: CF_API) Your Cloud Foundry api url.
  • username: (Optional, default: null, Env Var: CF_USERNAME) The username of an admin user. (Optional if you use an access token)
  • password: (Optional, default: null, Env Var: CF_PASSWORD) The password of an admin user. (Optional if you use an access token)
  • skip_ssl_validation: (Optional, default: false) Set to true to skip verification of the API endpoint. Not recommended!.
  • enc_private_key: (Optional, default: null, Env Var: CF_ENC_PRIVATE_KEY) A GPG private key(s) generate from gpg --export-secret-key -a <real name> . Need a passphrase with enc_passphrase..
  • enc_passphrase: (Optional, default: null, Env Var: CF_ENC_PASSPHRASE) The passphrase for your gpg key.
  • verbose: (Optional, default: null) Set to true to see requests sent to Cloud Foundry. (Use TF_LOG=1 to see them)
  • user_access_token: (Optional, default: null, Env Var: CF_TOKEN) The OAuth token used to connect to a Cloud Foundry. (Optional if you use 'username' and 'password')
  • user_refresh_token: (Optional, default: null) The OAuth refresh token used to refresh your token.

Resources and Data sources


Organizations

Resource

resource "cloudfoundry_organization" "org_mysuperorg" {
  name = "mysuperorg"
  is_system_domain = true
  quota_id = "${cloudfoundry_quota.quota_mysuperquota.id}"
}
  • name: (Required) Name of your organization.
  • is_system_domain: (Optional, default: false) set it to true only if this organization is a system_domain organization, it will prevent deletion on Cloud Foundry.
  • quota_id: (Optional, default: null) Give a quota id (created from resource cloudfoundry_quota) to set a quota on this org.

Data source

Get one org with all details

Note: every parameters from resource which are not used here are marked as computed and will be filled.

data "cloudfoundry_organization" "org_mysuperorg" {
  name = "mysuperorg"
  // or by_id = "a-guid"
}

// get quota id for example: ${data.cloudfoundry_organization.cloudfoundry_organization.quota_id}
  • name: (Required if by_id not set) Name of your organization.
  • by_id: (Required if name not set) by_id of your organization.
Get all orgs
data "cloudfoundry_organizations" "available" {}

data "cloudfoundry_organization" "cloudfoundry_organization" {
    name = "${data.cloudfoundry_organizations.available.names[0]}"
}
  • names: (Computed) List of the organizations name found.
  • ids: (Computed) List of the organizations id found. (same order as names)

Spaces

Resource

resource "cloudfoundry_space" "space_mysuperspace" {
    name = "mysuperspace"
    org_id = "${cloudfoundry_organization.org_mysuperorg.id}"
    quota_id = "${cloudfoundry_quota.quota_mysuperquota.id}"
    sec_groups = ["${cloudfoundry_sec_group.sec_group_mysupersecgroup.id}"]
    allow_ssh = true
}
  • name: (Required) Name of your space.
  • org_id: (Required) Organization id created from resource or data source cloudfoundry_organization.
  • allow_ssh: (Optional, default: true) Set to false to remove ssh access on app instances inside this space.
  • sec_groups: (Optional, default: null) This is a list of security groups id created from cloudfoundry_sec_group, it will bind each security group on this space.
  • quota_id: (Optional, default: null) Give a quota id (created from resource cloudfoundry_quota) to set a quota on this space.

Data source

Get one space with all details

Note: every parameters from resource which are not used here are marked as computed and will be filled.

data "cloudfoundry_space" "space_mysuperspace" {
    name = "mysuperspace"
    org_id = "${cloudfoundry_organization.org_mysuperorg.id}"
    // or by_id = "a-guid"
}
  • name: (Required if by_id not set) Name of your space.
  • org_id: (Required if by_id not set) Organization id created from resource or data source cloudfoundry_organization.
  • by_id: (Required if name not set) by_id of your space.
Get all spaces
data "cloudfoundry_spaces" "available" {
  org_id = "${cloudfoundry_organization.org_mysuperorg.id}"
}

data "cloudfoundry_space" "space_mysuperspace" {
    name = "${data.cloudfoundry_spaces.available.names[0]}"
    org_id = "${cloudfoundry_organization.org_mysuperorg.id}"
}
  • org_id: (Optional, Default: Empty) Organization id created from resource or data source cloudfoundry_organization. If not set all spaces will be retrieve.
  • names: (Computed) List of the spaces name found.
  • ids: (Computed) List of the spaces id found. (same order as names)

Quotas

Resource

Note: There is two kinds of quotas inside Cloud Foundry: a space's quota, an organization's quota. This resource is able to find what kind of quota you defined. If you omit org_id the resource will consider this quota as an organization's quota. With it will consider it's a space's quota.

resource "cloudfoundry_quota" "quota_for_ahalet" {
  name = "quotaAhalet"
  org_id = "${cloudfoundry_organization.org_mysuperorg.id}"
  total_memory = "10G"
  instance_memory = "1G"
  routes = 200
  service_instances = 10
  app_instances = -1
  allow_paid_service_plans = true
  reserved_route_ports = 0
}
  • name: (Required) Name of your quota.
  • org_id: (Optional, default: null) If set to an organization id created from resource or data source cloudfoundry_organization, it will be considered as organization quota, else it will be a space quota.
  • total_memory: (Optional, default: 20G) Total amount of memory a space can have (e.g. 1024M, 1G, 10G).
  • total_instance_memory: (Optional, default: -1) Maximum amount of memory an application instance can have (e.g. 1024M, 1G, 10G). -1 represents an unlimited amount.
  • routes: (Optional, default: 2000) Total number of routes that a space can have.
  • service_instances: (Optional, default: 200) Total number of service instances which can be created that a space can have.
  • app_instances: (Optional, default: -1) Total number of application instances that a space can have. -1 represents an unlimited amount.
  • app_allow_paid_service_plans: (Optional, default: true) Can provision instances of paid service plans.
  • reserved_route_ports: (Optional, default: 0) Maximum number of routes that may be created with reserved ports in a space.

Data source

Note: every parameters from resource which are not used here are marked as computed and will be filled.

data "cloudfoundry_quota" "quota_for_ahalet" {
  name = "quotaAhalet"
  org_id = "${cloudfoundry_organization.org_mysuperorg.id}"
  // or by_id = "a-guid"
}
  • name: (Required if by_id not set) Name of your quota.
  • org_id: (Optional, default: null) If set to an organization id created from resource or data source cloudfoundry_organization, it will be considered as organization quota, else it will be a space quota.
  • by_id: (Required if name not set) by_id of your quota.

Security groups

Resource

resource "cloudfoundry_sec_group" "sec_group_mysupersecgroup" {
  name = "mysupersecgroup"
  on_staging = false
  on_running = false
  rules {
    protocol = "tcp"
    destination = "10.0.0.2"
    ports = "65000"
    log = false
    description = "my description"
  }
  rules {
    protocol = "icmp"
    destination = "192.0.2.0-192.0.1-4"
    type = 3
    code = 1
  }
  rules {
      protocol = "all"
      destination = "10.0.0.0/24"
      log = true
    }
}
  • name: (Required) Name of your security group.
  • on_staging: (Optional, default: false) Set to true to apply this security group during staging an app.
  • on_running: (Optional, default: false) Set to true to apply this security group during running an app.
  • rules: (Optional, default: null) Add rules as many as you need:
    • protocol: (Required) The protocol to use, it can be tcp, udp, icmp, or all
    • destination: (Optional, default: null) A single IP address, an IP address range (e.g. 192.0.2.0-192.0.1-4), or a CIDR block to allow network access to.
    • ports: (Optional, default: null) A single port, multiple comma-separated ports, or a single range of ports that can receive traffic, e.g. "443", "80,8080,8081", "8080-8081". Required when protocol is tcp or udp.
    • code: (Optional, default: null) ICMP code. Required when protocol is icmp.
    • type: (Optional, default: null) ICMP type. Required when protocol is icmp.
    • log: (Optional, default: false) Set to true to enable logging. For more information about how to configure system logs to be sent to a syslog drain, see Using Log Management Services topic.
    • description: (Optional, default: null) This is an optional field that contains useful text for operators to manage security group rules. This field is available in Cloud Foundry v238 and later.

Data source

Note: every parameters from resource which are not used here are marked as computed and will be filled.

data "cloudfoundry_sec_group" "sec_group_mysupersecgroup" {
  name = "mysupersecgroup"
  // or by_id = "a-guid"
}
  • name: (Required if by_id not set) Name of your security group.
  • by_id: (Required if name not set) by_id of your security group.

Buildpacks

Resource

resource "cloudfoundry_buildpack" "buildpack_mysuperbuildpack" {
  name = "mysuperbuildpack"
  path = "https://github.com/cloudfoundry/staticfile-buildpack/releases/download/v1.3.13/staticfile_buildpack-cached-v1.3.13.zip"
  position = 13
  locked = false
  enabled = false
}
  • name: (Required) Name of your buildpack. Note: if there is only name inside your buildpack the provider will consider your buildpack as a system managed buildpack (e.g.: php_buildpack, java_buildpack), so if you remove it from your tf file it will not be removed from your Cloud Foundry.
  • path: (Optional, default: null) Path should be a zip file, a url to a zip file, or a local directory which contains your buildpack code.
  • position: (Optional, default: null) Position is a positive integer, sets priority, and is sorted from lowest to highest.
  • enabled: (Optional, default: true) Set to false to disable the buildpack to be used for staging.
  • locked: (Optional, default: false) Set to true to lock the buildpack to prevent updates.

Data source

Note: every parameters from resource which are not used here are marked as computed and will be filled.

resource "cloudfoundry_buildpack" "buildpack_mysuperbuildpack" {
  name = "mysuperbuildpack"
  // or by_id = "a-guid"
}
  • name: (Required if by_id not set) Name of your buildpack.
  • by_id: (Required if name not set) by_id of your buildpack.

Feature flags

Resource

resource "cloudfoundry_feature_flags" "feature_flags" {
  diego_docker = true
  custom_flag {
    name = "my_flag"
    enabled = true
  }
}

List of default feature flags:

  • user_org_creation: (Optional, default: false)
  • private_domain_creation: (Optional, default: true)
  • app_bits_upload: (Optional, default: true)
  • app_scaling: (Optional, default: true)
  • route_creation: (Optional, default: true)
  • service_instance_creation: (Optional, default: true)
  • diego_docker: (Optional, default: false)
  • set_roles_by_username: (Optional, default: true)
  • unset_roles_by_username: (Optional, default: true)
  • task_creation: (Optional, default: false)
  • env_var_visibility: (Optional, default: true)
  • space_scoped_private_broker_creation: (Optional, default: true)
  • space_developer_env_var_visibility: (Optional, default: true)

Custom flags made for feature flags not in the default resource:

  • custom_flag: (Optional, default: null) Add cutom feature flags as many as you need:
    • name: (Required) Name of the feature
    • enabled: (Required) Set to true to enable the feature in your cloud foundry.

Data source

Feature flags cannot be used as data source


Services

Resource

Service from marketplace:

resource "cloudfoundry_service" "svc_db" {
  name = "my-db"
  space_id = "${cloudfoundry_space.space_mysuperspace.id}"
  service = "p-mysql"
  plan = "100mb"
  params = "{ \"my-param\": 1}"
  update_params = "{ \"my-param\": 1}"
  tags = [ "tag1", "tag2" ]
}

An user provided service:

resource "cloudfoundry_service" "svc_ups" {
  name = "my-ups"
  space_id = "${cloudfoundry_space.space_mysuperspace.id}"
  user_provided = true
  params = "{ \"my-credential\": 1}"
  route_service_url = "http://my.route.com"
  syslog_drain_url = "http://my.syslog.com"
  tags = [ "tag1", "tag2" ]
}
  • name: (Required) Name of your service.
  • space_id: (Required) Space id created from resource or data source cloudfoundry_space to register service inside.
  • user_provided: (Optional, default: false) Set to true to create an user provided service. Note: service and plan params will not be used.
  • params: (Optional, default: null) Must be json, if it's an user provided service it will be credential for your service instead it will be params sent to service broker when creating service.
  • update_params: (Optional, default: null) Must be json, Params sent to service broker when updating service.
  • tags: (Optional, default: null) list of tags for your service.
  • service: (Required when not user provided service) name of service from marketplace.
  • plan: (Required when not user provided service) name of the plan to use.
  • route_service_url: (Optional, default: null) Only works for user provided, an url to create a route service
  • syslog_drain_url: (Optional, default: null) Only works for user provided, an url to drain logs as a service on an app.

Data source

Note: every parameters from resource which are not used here are marked as computed and will be filled, except:

  • params
  • update_params
data "cloudfoundry_service" "svc_ups" {
  name = "my-ups"
  space_id = "${cloudfoundry_space.space_mysuperspace.id}"
  // or by_id = "a-guid"
}
  • name: (Required if by_id not set) Name of your service.
  • space_id: (Required if by_id not set) Space id created from resource or data source cloudfoundry_space to register service inside.
  • by_id: (Required if name not set) by_id of your service.

Domains

Resource

resource "cloudfoundry_domain" "domain_mydomain" {
  name = "my.domain.com"
  org_owner_id = "${cloudfoundry_organization.org_mysuperorg.id}"
  router_group = "default-router"
  orgs_shared_id = ["${cloudfoundry_organization.org_mysecondorg.id}"]
  shared = false
}
  • name: (Required) Your domain name.
  • org_owner_id: (Required if not shared) Organization id created from resource or data source which own the domain cloudfoundry_organization.
  • orgs_shared_id: (Optional, default: null) Set of organization id which can have access to domain. Note: Only can used when not a shared domain
  • router_group: (Optional, default: null) Routes for this domain will be configured only on the specified router group. Note: Only when when it's a shared domain
  • shared: (Optional, default: false) If True this domain will be a shared domain.

Data source

Get one domain with all details

Note: every parameters from resource which are not used here are marked as computed and will be filled.

data "cloudfoundry_domain" "domain_mydomain" {
  name = "my.domain.com"
  org_owner_id = "${cloudfoundry_organization.org_mysuperorg.id}"
  first = false
  // or by_id = "a-guid"
}
  • name: (Optional if first param set to true, default: null) Your domain name.
  • first: (Optional, default: null) If set to true parameter name or by_id become unnecessary and will give the first domain found in your Cloud Foundry (it will be the first shared domain if org_owner_id is not set).
  • org_owner_id: (Required if not shared) Organization id created from resource or data source which own the domain cloudfoundry_organization.
  • by_id: (Optional if first param set to true or name param set, default: null) by_id of your domain.
Get all domains
data "cloudfoundry_domains" "available" {
  org_owner_id = "${cloudfoundry_organization.org_mysuperorg.id}"
}

data "cloudfoundry_domain" "space_mysuperspace" {
    name = "${data.cloudfoundry_domains.available.names[0]}"
    org_owner_id = "${cloudfoundry_organization.org_mysuperorg.id}"
}
  • org_owner_id: (Optional, Default: Empty) Organization id created from resource or data source which own the domain cloudfoundry_organization. If not set all spaces will be retrieve.
  • names: (Computed) List of the domains name found.
  • ids: (Computed) List of the domains id found. (same order as names)

Routes

Resource

resource "cloudfoundry_route" "route_superroute" {
  hostname = "superroute"
  space_id = "${cloudfoundry_space.space_mysuperspace.id}"
  domain_id = "${cloudfoundry_domain.domain_mydomain.id}"
  port = -1
  path = ""
  service_id = "${cloudfoundry_service.svc_ups.id}"
  service_params = "{ \"my-param\": 1}"
}
  • hostname: (Required) Your hostname.
  • domain_id: (Required) Domain id created from resource or data source domains.
  • space_id: (Required) Space id created from resource or data source cloudfoundry_space to register route inside.
  • port: (Optional, default: -1) Set a port for your route (only works with a tcp domain). Note: If 0 a random port will be chose
  • path: (Optional, default: null) Set a path for your route (only works with a http(s) domain).
  • service_id: (Optional, default: null) Set a service id created from resource or data source services this will bind a route service on your route. Note: It obviously needs a service which is a route service.
  • service_params: (Optional, default: null) Must be in json, set params to send to service when binding on it.
  • protocol: (Optional, default: null) This parameter is only for uri computed parameter it permits to override the protocol when generating uri (generated uri will use always https protocol when it's an http route, you can found useful to force in http).
  • uri: (Computed) This is an uri generated by the resource, you can use this for service brokers resource for example. Note: It autodetects when it's an http route or a tcp route.

Data source

Note: every parameters from resource which are not used here are marked as computed and will be filled, except:

  • service_params
resource "cloudfoundry_route" "route_superroute" {
  hostname = "superroute"
  domain_id = "${cloudfoundry_domain.domain_mydomain.id}"
  port = -1
  path = ""
  // or by_id = "a-guid"
}
  • name: (Required if by_id not set) Your hostname.
  • domain_id: (Required if by_id not set) Domain id created from resource or data source domains.
  • port: (Optional, default: -1) Set a port for your route (only works with a tcp domain). Note: If 0 a random port will be chose
  • path: (Optional, default: null) Set a path for your route (only works with a http(s) domain).
  • protocol: (Optional, default: null) This parameter is only for uri computed parameter it permits to override the protocol when generating uri (generated uri will use always https protocol when it's an http route, you can found useful to force in http).
  • by_id: (Required if name not set) by_id of your route.

Isolation segments

Resource

resource "cloudfoundry_isolation_segment" "my_isolation_segment" {
  name = "isolation_segment_name_set_in_cf_deployment"
}
  • name: (Required if by_id not set) Isolation segment that you have set on your cloud foundry deployment.
  • orgs_id: DEPRACTED USE entitlement instead (Required) (Optional, default: null) You can pass a list of organization created from resource or data source cloudfoundry_organization, this will put those organizations in the isolation segment.
  • by_id: (Required if name not set) by_id of your isolation segment.

Data source

Note: every parameters from resource which are not used here are marked as computed and will be filled.

data "cloudfoundry_isolation_segment" "my_isolation_segment" {
  name = "isolation_segment_name_set_in_cf_deployment"
}
  • name: (Required if first not set) Isolation segment that you have set on your cloud foundry deployment.
  • first: Get the first non shared isolation segment.

Isolation segments entitlement

Resource

resource "cloudfoundry_isolation_segment_entitlement" "private_mysuperorg" {
  segment_id = "${cloudfoundry_isolation_segment.my_isolation_segment.id}"
  org_id = "${cloudfoundry_organization.org_mysuperorg.id}"
  default = false
}
  • segment_id: (Required) Isolation segment id to use.
  • org_id: (Required) Organization id to be entitled by this segment.
  • default: (Optional, default: false) Set this isolation segment as default segment for this organization.

Isolation segments space

Resource

resource "cloudfoundry_isolation_segment_space" "private_mysuperspace" {
  segment_id = "${cloudfoundry_isolation_segment.my_isolation_segment.id}"
  space_id = "${cloudfoundry_organization.space_mysuperspace.id}"
}
  • segment_id: (Required) Isolation segment id to use.
  • space_id: (Required) Space id where assign segment.\

Stacks

Resource

Stacks cannot be used as a resource

Data source

Note: every parameters from resource which are not used here are marked as computed and will be filled.

data "cloudfoundry_stack" "my_stack" {
  name = "cflinuxfs2"
  first = false
  // or by_id = "a-guid"
}
  • name: (Optional if first param set to true, default: null) Name of the stack.
  • first: (Optional, default: null) If set to true parameter name become unnecessary and will give the first stack found in your Cloud Foundry.
  • by_id: (Optional if first param set to true or name param set, default: null) by_id of your stack.

Environment Variable Group

Resource

resource "cloudfoundry_env_var_group" "env_var_group" {
  env_var {
    key = "myvar1"
    value = "myvalue1"
    running = true
    staging = true
  }
  env_var {
    key = "myvar2"
    value = "myvalue1"
    running = true
    staging = true
  }
}
  • env_var: (Required) Add any variable you want to environment variable group:
    • key: (Required) Env var key.
    • value: (Required) Env var value.
    • running: (Required) if set to true this env var will be use on all running app.
    • staging: (Required) if set to true this env var will be use during staging step when creating an app.

Data source

Environment Variable Group cannot be used as a data source


Service brokers

Resource

resource "cloudfoundry_service_broker" "service_broker_mysuperbroker" {
  name = "mysuperbroker"
  url = "http://url.of.my.service.broker.com"
  username = "user"
  password = "mypassword"
  service_access {
    service = "service_name_from_service_broker_catalog"
    plan = "plan_from_service_broker_catalog"
    org_id = "${cloudfoundry_organization.org_mysuperorg.id}"
  }
  service_access {
    service = "service_name_from_service_broker_catalog"
    plan = "plan2_from_service_broker_catalog"
    org_id = "${cloudfoundry_organization.org_mysuperorg.id}"
  }
  #...
}
  • name: (Required) Name of your service broker.
  • url: (Required) URL to access to your service broker.
  • username: (Optional, default: null) Username to authenticate to your service broker.
  • password: (Optional, default: null) Password to authenticate to your service broker. Note: you can pass a base 64 encrypted gpg message if you enabled password encryption.
  • catalog_sha1: (Computed) Do not modify yourself, this permits to detect a change in the service broker catalog.
  • space_id: (Optional, default: null) If set, your service broker will be created as a space-scoped service broker on this space.
  • service_access: (Required if space_id not set) Add service access as many as you need, service access make you service broker accessible on marketplace:
    • service: (Required) Service name from your service broker catalog to activate. Note: if there is only service in your service access it will enable all plan on all orgs on your Cloud Foundry.
    • plan: (Optional, default: null) Plan from your service broker catalog attached to this service to activate. Note: if no org_id is given it will enable this plan on all orgs.
    • org_id: (Optional, default: null) Org id created from resource or data source cloudfoundry_organization to activate this service. Note: if no plan is given it will all plans on this org.

BUG FOUND: if you set both plan and org_id in your service_access Cloud Foundry will enable all plans on this org. It's maybe only on the version of Cloud Foundry I am. Feedbacks are needed on other versions.

Data source

Note: every parameters from resource which are not used here are marked as computed and will be filled, except:

  • username
  • password
resource "cloudfoundry_service_broker" "service_broker_mysuperbroker" {
  name = "mysuperbroker"
  // or by_id = "a-guid"
}
  • name: (Required if by_id not set) Name of your service broker.
  • by_id: (Required if name not set) by_id of your service broker.

Applications

This resource is used in order to deploy and update an application. It can see changes between code you have locally and code you have in your cloud foundry to do the update fastly (It compares a checksum from a chunk of data between local and remotely)

By default, when updating, your app will never shutdown. It always use blue-green deployment when app bits changed, rename or scale number of instances instantly and do blue-green restage in all others modification.

As a terraform resource, creating an app give you more control but can also be more painful than using the cli. To be painless, terraform modules can be use to deploy you app like you could do with a manifest.yml file. This can be found on https://github.com/orange-cloudfoundry/terraform-cloudfoundry-modules

Resource

resource "cloudfoundry_app" "myapp" {
  name = "myapp"
  stack_id = "${data.cloudfoundry_stack.my_stack.id}"
  space_id = "${data.cloudfoundry_space.space_mysuperspace.id}"
  started = true
  instances = 2
  memory = "64M"
  disk_quota = "1G"
  command = ""
  path = "/path/to/folder"
  diego = true
  buildpack = "php_buildpack"
  health_check_type = "port"
  health_check_http_endpoint = ""
  health_check_timeout = ""
  docker_image = ""
  enable_ssh = false
  ports = [8080]
  routes = ["${cloudfoundry_route.route_superroute.id}"]
  services = ["${cloudfoundry_service.svc_db.id}"]
  env_var = {
    "MY_ENV_KEY" = "myvalue"
    "MY_ENV_KEY2" = "myvalue2"
    #...
  }
}
  • name: (Required) Name of your application.
  • space_id: (Required) Space id created from resource or data source spaces.
  • stack_id: (Required) Stack id retrieve from data source Stacks.
  • path: (Required) Path to a folder which contains application code, url to a zip/jar, url to a tgz/tar or a git url following the scheme: https://[user:password@]mygit.com/myrepo.git[#tag-or-branch-or-commit-hash]
  • started: (Optional, default: true) State of your application (should be start or not).
  • instances: (Optional, default: 1) The number of instances of the app to run.
  • memory: (Optional, default: 512M) The amount of memory each instance should have.
  • disk_quota: (Optional, default: 1G) The maximum amount of disk available to an instance of an app.
  • command: (Optional, default: NULL) The command to start an app after it is staged.
  • diego: (Optional, default: true) Use diego to stage and to run when available (Diego should be always available because DEA is not supported anymore).
  • buildpack: (Optional, default: NULL) Buildpack to build the app. 3 options: a) Blank means autodetection; b) A Git Url pointing to a buildpack; c) Name of an installed buildpack.
  • health_check_type: (Optional, default: port) Type of health check to perform. Others values are:
    • http (Diego only)
    • port
    • process
    • none
  • started: (Optional, default: true) when set to false app will not be started.
  • health_check_http_endpoint: (Optional, default: NULL) Endpoint called to determine if the app is healthy. (Can be use only when check type is http)
  • health_check_timeout: (Optional, default: NULL) Timeout in seconds for health checking of an staged app when starting up.
  • docker_image: (Optional, default: NULL) Name of the Docker image containing the app. The "diego_docker" feature flag must be enabled in order to create Docker image apps.
  • enable_ssh: (Optional, default: false) Enable SSHing into the app. Supported for Diego only.
  • ports: (Optional, default: 8080 when diego is set to true) List of ports on which application may listen. Overwrites previously configured ports. Ports must be in range 1024-65535. Supported for Diego only. (Note: This is a copy of the default behaviour of cloud foundry cli, it always create a default port to 8080 when using diego backend)
  • routes: (Optional, default: NULL) List of route guid retrieve from resource or data source routes to attach routes to your app.
  • services: (Optional, default: NULL) List of service guid retrieve from resource or data source services to bind services to your app.
  • env_var: (Optional, default: NULL) Add any variable you want to the app environment.
  • no_blue_green_restage: (Optional, default: false) If set to true no blue green restage will be performed (it will restart the app).
  • no_blue_green_deploy: (Optional, default: false) If set to true no blue green deployment will be performed.

Note:

  • Cloud controller doesn't support multipart upload in chunk (could not stream chunk of files) this actually mean that an intermediate file need to be created containing the request and data (this is actually the current behaviour from cli)
  • When retrieving source from a zip file url the stream will be passed directly
  • When retrieving source from a tgz/tar file url this will be converted as zip directly from the stream
  • When retrieving source from a git repo a folder will be created containing source before push them
  • A git repo fetch data only for the branch or tag with a depth of 1, if a commit hash is set everything from repo will be fetched before force to commit (this mean that passing a commit hash will make things slower)

Data source

Note: every parameters from resource which are not used here are marked as computed and will be filled.

resource "cloudfoundry_service_broker" "myapp" {
  name = "mysuperbroker"
  space_id = "${data.cloudfoundry_space.space_mysuperspace.id}"
  // or by_id = "a-guid"
}
  • name: (Required if by_id not set) Name of your app. If space_id set it will try to find the first matching app found in all spaces you have access to.
  • space_id: (Optional, default: null) Space id created from resource or data source spaces.
  • by_id: (Required if name not set) by_id of your service broker.

Enable password encryption

You can use gpg encryption to encrypt your service broker password.

Create a private key for the provider

Requirements: you will need to have gpg on your system.

  1. run gpg --gen-key, next steps will assume that you put cloudfoudry as real name. (Do not forget to remember your passphrase!)
  2. go on your terraform folder config in command line
  3. run gpg --export-secret-key -a cloudfoudry > private.key
  4. inside provider configuration put those two key/value pairs (you can also copy content of private.key and export CF_ENC_PRIVATE_KEY=content_of_private.key && export CF_ENC_PASSPHRASE=your_passphrase_that_you_remembered:)):
provider "cloudfoundry" {
  enc_private_key = "${file("private.key")}"
  enc_passphrase = "your_passphrase_that_you_remembered:)"
}
  1. create the public key with gpg --export -a cloudfoudry > public.key
  2. Share the public key to the rest of your team to let them encrypt password with it (see Encrypt password)
  3. you're done

Encrypt password

  1. Get the public key previously created (public.key)
  2. Import the key with gpg --import public.key
  3. generate the encrypted password with commands echo "mypassword" | gpg --encrypt --armor -r cloudfoudry > encrypted_pass.key
  4. Retrieve it from your resource, e.g.:
resource "cloudfoundry_service_broker" "service_broker_mysuperbroker" {
  name = "mysuperbroker"
  url = "http://url.of.my.service.broker.com"
  username = "user"
  password = "${file("encrypted_pass.key")}"
  service_access {
    service = "service_name_from_service_broker_catalog"
  }
}
  1. you're done

terraform-provider-cloudfoundry's People

Contributors

arthurhlt avatar dcarley avatar gberche-orange avatar o-orand avatar seb4stien avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

terraform-provider-cloudfoundry's Issues

upgrade lifecycle management for particular space on cloudfoundry_sec_group function

Hi,

Sometime , we need to use different security groups during running or staging for same Org/Space.
but this feature is not currently available with this provider.

this functionnality is already available on cloudfoundry via this api call :

PUT /v2/security_groups/:guid/staging_spaces/:space_guid

https://apidocs.cloudfoundry.org/263/security_groups/associate_space_with_the_security_group_for_staging.html

CF cli use thie method GetSecurityGroupStagingSpacesRequest for this kind of call

( Line 105 : https://github.com/cloudfoundry/cli/blob/v6.32.0/api/cloudcontroller/ccv2/internal/api_routes.go )

called by function AssociateSpaceWithStagingSecurityGroup
( line 93 : https://github.com/cloudfoundry/cli/blob/v6.32.0/api/cloudcontroller/ccv2/security_group.go )

So, idea here is to integrate/adapt this code to the terraform provider for be able to use this on a space.
Remain to define where this param need to be set : on "space" or "securityGroup" parts

thanks

Service creation calls deprecated API, which fails

We have observed that the plugin calls an endpoint, which has been deprecated by V2.46 of CF API. With a newer API it does not work. This issue happens by calling the ยดFindServicePlanByDescriptionยด method in the CF CLI, and the CF developers recommended to get in touch with you.

The full stack trace and debug information is located in this issue:

cloudfoundry/cli#1276

Would it be possible to use a newer API endpoint for service creation?

Manage dependencies with glide or similar

I tried to build this locally and ran into the following:

../../github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/cf_client/client.go:70: undefined: ccv2.NewCloudControllerClient
../../github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/cf_client/terraform_repository.go:408: cannot use TerraformRepository literal (type *TerraformRepository) as type coreconfig.Repository in return argument:
        *TerraformRepository does not implement coreconfig.Repository (missing CLIVersion method)

I'm guessing we have different versions of the cf cli source. Should be able to fix by specifying dependencies and versions with glide, godeps, etc.

Application Security Group : icmp rules are KO

Tested with terraform cloudfoundry provider 0.8 / 0.5.4
I cant apply ASG icmp rules (cf 245).
Here is the error i get

cloudfoundry_quota.tf_org_quota: Refreshing state... (ID: dcad5ab4-3dbe-4724-b602-83044b646831)                    
cloudfoundry_sec_group.sec_group_services-ping: Creating...                                                        
  name:                         "" => "services-ping"                                                              
  on_running:                   "" => "true"                                                                       
  on_staging:                   "" => "false"                                                                      
  rules.#:                      "" => "1"                                                                          
  rules.2387358670.code:        "" => "0"
  rules.2387358670.description: "" => "any ICMP to NET_CF_SERVICES"
  rules.2387358670.destination: "" => "192.168.30.0-255.255.255.0"
  rules.2387358670.log:         "" => "false"
  rules.2387358670.ports:       "" => ""
  rules.2387358670.protocol:    "" => "icmp"
  rules.2387358670.type:        "" => "0"
Error applying plan:

1 error(s) occurred:

* cloudfoundry_sec_group.sec_group_services-ping: Server error, status code: 400, error code: 300001, message: The security group is invalid: rules rule number 1 missing required field 'code', rules rule number 1 missing required field 'type'

Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.

Install script should work with hashicorp/terraform docker image

Hashicorp provides a terraform docker image. It could be nice to have install script working with this docker image out-of-the-box.
But unfortunately, this image does not include bash. So installation script does not work correctly.
There is at least an issue with OSTYPE (bash environment variable). Maybe uname can replace it.

On ubuntu

> uname -s
Linux

On windows git bash

> uname -s
MINGW64_NT-6.1

Broker resource incorrectly reports change in password

We're observing that when upgrading terraform-provider-cloudfoundry from 0.7.3 to 0.9.1, the plan output is reporting unexpected changes to all our broker passwords:

  ~ cloudfoundry_service_broker.tf-p-mysql
      password:            <sensitive> => <sensitive> (attribute changed)

Using https://github.com/wybczu/tfjson to render the plan file and display otherwise redacted values, I see that the planned new value isn't different from the current one.

I'm wondering whether this could be related to previous fix 7a02e0b

d.Set("password", d.Get("previous_password"))

and whether inspiration from similar pattern in core aws provider could help address the issue:
https://github.com/terraform-providers/terraform-provider-aws/blob/0bfaf6cd4d85a2fb2b32d71ab26341e8d95b0661/aws/resource_aws_db_instance.go#L945-L949

cloudfoundry_domain fails to report domain creation failure

Given a domain declared such as the following which is in conflict with an existing domain visible in another org

resource "cloudfoundry_domain" "tf-preprod-system-domain" {
  name = "${var.cloudfoundry["system_domain"]}"
  org_owner_id = "${cloudfoundry_organization.tf-system_domain.id}"
}

Terraform plan properly displays the need to delete and create the resource:

-/+ cloudfoundry_domain.tf-preprod-system-domain (new resource required)
      id:                                "e9ced353-bb66-4d3b-8e03-2c33f4920db3" => <computed> (forces new resource)
      name:                              "nd-int-cfapi.mydomain.org" => "nd-int-cfapi.mydomain.org"
      org_owner_id:                      "612c1b99-e8df-4d58-8412-df7fa440290e" => "87505508-4c09-499e-933c-eb89582cb9a5" (forces new resource)

however the terraform apply silently completes with success:

cloudfoundry_domain.tf-preprod-system-domain: Creating...
  name:         "" => "nd-int-cfapi.mydomain.org"
  org_owner_id: "" => "87505508-4c09-499e-933c-eb89582cb9a5"
[...]
cloudfoundry_domain.tf-preprod-system-domain: Creation complete after 1s (ID: e9ced353-bb66-4d3b-8e03-2c33f4920db3)

while the equivalent Cf CLI command fails:

cf create-domain system_domain nd-int-cfapi.mydomain.org 
Creating domain nd-int-cfapi.mydomain.org for org system_domain as gberche...
FAILED
Server error, status code: 400, error code: 130003, message: The domain name is taken: nd-int-cfapi.mydomain.org

I did not finish checking the provider info traces that require orange-cloudfoundry/cf-ops-automation#39 in our environment

Resource Importability

Support for terraform import would help TF-CF adoption when existing infrastructure are already created and need to be preserved, and start being managed by TF.

We have use cases for the following imports:

  • org
  • space
  • broker
  • domain

A workaround currently applied is to manually craft the corresponding tfstate file entries, which might be tedious and error prone.

Related tf documentation:

/CC @shoudusse

Allow authentication via uaa client credentials

It would be useful to authenticate using uaa client id and secret as well as username and password or oauth token. For compliance reasons, our user credentials expire after a few months, so it would be helpful to authenticate with creds that don't expire.

Isolation segment fails to refresh resource when missing from cloud

When the tfstate and tf specs contain an isolation segment which is not present in the cloud,

resource "cloudfoundry_isolation_segment" "internet_isolation_segment" {
  name = "internet_isolation_segment"
  orgs_id = ["${cloudfoundry_organization.org-orange-internet.id}"]
}

the terraform plan fails with the following output:

+ terraform plan -input=false ../spec-applied/
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

[...]	
cloudfoundry_isolation_segment.internet_isolation_segment: Refreshing state... (ID: 1de9160c-c572-4eb2-b9f6-7e08d98a9564)
[...]
	
Error: Error refreshing state: 1 error(s) occurred:
* cloudfoundry_isolation_segment.internet_isolation_segment: 1 error(s) occurred:
	
* cloudfoundry_isolation_segment.internet_isolation_segment: cloudfoundry_isolation_segment.internet_isolation_segment: Isolation segment not found

The attempt to refresh the tfstate also fails with the same message:

terraform refresh -input=false -target=cloudfoundry_isolation_segment.internet_isolation_segment ../spec-applied/ 
cloudfoundry_organization.org-orange-internet: Refreshing state... (ID: 6344f674-7e9e-4159-a9e9-abc5f14501ee)
cloudfoundry_isolation_segment.internet_isolation_segment: Refreshing state... (ID: 1de9160c-c572-4eb2-b9f6-7e08d98a9564)

Error: Error refreshing state: 1 error(s) occurred:

* cloudfoundry_isolation_segment.internet_isolation_segment: 1 error(s) occurred:

* cloudfoundry_isolation_segment.internet_isolation_segment: cloudfoundry_isolation_segment.internet_isolation_segment: Isolation segment not found

Workaround: manually remove the missing isolation-segment from the tfstate:

$ terraform state list | grep isolation | xargs -n 1 terraform state rm

Support for managing feature flags

I'd like to add support for managing Cloud Foundry feature flags.

They're a bit odd in that, unlike most other Terraform resources, there's nothing to create/destroy because they always exist in some state. It would also be possible for two resources to fight over the same flag if you told Terraform to do so.

I'm interested in some opinions about the implementation. There seems to be three possible options for the schema and user interface. I think I prefer the first or the last:

  1. Single resource, multiple flags, using a map. This requires the least repetition for the user. However it would require dropping support for Terraform 0.7 because non-string map items wasn't added until Terraform 0.8

    resource "cloudfoundry_feature_flags" "feature_flags" {
      flags {
        user_org_creation = false
        diego_docker = true
      }
    }
    
  2. Single resource, multiple flags, using a set. This requires a bit more typing and makes the diff harder to read because the hash of each item changes when the value does.

    resource "cloudfoundry_feature_flags" "feature_flags" {
      flag {
        name = "user_org_creation"
        value = false
      }
      flag {
        name = "diego_docker"
        value = true
      }
    }
    
  3. Separate resources, single flag each. This is the simplest to implement but requires more repetition and results in more "read" calls against the Cloud Controller API.

    resource "cloudfoundry_feature_flag" "user_org_creation" {
      name = "user_org_creation"
      value = false
    }
    resource "cloudfoundry_feature_flag" "diego_docker" {
      name = "diego_docker"
      value = true
    }
    

What do you think?

Space resource should not remove externally provisionned associated security groups

The following use-case is not supported by the space resource: it unbinds any extra security group associated with the space which was not specified in the cloudfoundry_space.sec_groups. It would be great if the security group unbinding could be restricted only to security group resources previously provisionned and bound by the terraform resource.

Use case: a space is provisionned with terraform-provider-cloudfoundry with an empty set of security groups. Then security groups are dynamically associated with this space by a 3rd party (such as https://github.com/orange-cloudfoundry/sec-group-broker-filter or anynines service guard) to enable consumption of service instances provisionned by application developers (outside of terraform)

During discussion @ArthurHlt mentionned a potential fix similar to 7a02e0b (using tfstate as persistence engine for maintaining transient state during the terraform apply)

Panic when trying to refresh non existing org quota

When trying to refresh the TF state with an org quota which is missing in the cloud, the provider panics with the following traces:

2018-05-29T15:12:45.837Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: {
2018-05-29T15:12:45.837Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1:   "description": "Space Quota Definition could not be found: 52606bcc-fe61-4398-831e-ca9d56dbbddf",
2018-05-29T15:12:45.837Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1:   "error_code": "CF-SpaceQuotaDefinitionNotFound",
2018-05-29T15:12:45.837Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1:   "code": 310007
2018-05-29T15:12:45.837Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: }
2018-05-29T15:12:45.837Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: 
2018-05-29T15:12:45.840Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: panic: interface conversion: interface {} is models.QuotaFields, not models.SpaceQuota
2018-05-29T15:12:45.840Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: 
2018-05-29T15:12:45.840Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: goroutine 1209 [running]:
2018-05-29T15:12:45.841Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/resources.CfQuotaResource.Exists(0x0, 0x0, 0xc42018bf80
, 0xfacc20, 0xc420098a00, 0x7f32da03d000, 0x0, 0x30)
2018-05-29T15:12:45.842Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1:         /home/travis/gopath/src/github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/resources/quotas.go:197
 +0x791
2018-05-29T15:12:45.842Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/resources.(*CfQuotaResource).Exists(0xc420476690, 0xc42
018bf80, 0xfacc20, 0xc420098a00, 0xf99cc0, 0x100050100000001, 0xc42018bf80)
2018-05-29T15:12:45.843Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1:         <autogenerated>:1 +0x67
2018-05-29T15:12:45.843Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/resources.(CfResource).Exists-fm(0xc42018bf80, 0xfacc20
, 0xc420098a00, 0x24, 0x1714940, 0x0)
2018-05-29T15:12:45.844Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1:         /home/travis/gopath/src/github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/resources/cf_resource.g
o:24 +0x4d
2018-05-29T15:12:45.844Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: github.com/hashicorp/terraform/helper/schema.(*Resource).Refresh(0xc4203440c0, 0xc42035ca50, 0xfacc20, 0xc420098a00, 0
xc4201539e0, 0xc420810b01, 0x80000000018)
2018-05-29T15:12:45.845Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1:         /home/travis/gopath/src/github.com/hashicorp/terraform/helper/schema/resource.go:298 +0x3bf
2018-05-29T15:12:45.845Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: github.com/hashicorp/terraform/helper/schema.(*Provider).Refresh(0xc4200f67e0, 0xc42035ca00, 0xc42035ca50, 0x7f32da03d
000, 0x0, 0x0)
2018-05-29T15:12:45.846Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1:         /home/travis/gopath/src/github.com/hashicorp/terraform/helper/schema/provider.go:284 +0x9a
2018-05-29T15:12:45.846Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: github.com/hashicorp/terraform/plugin.(*ResourceProviderServer).Refresh(0xc42026dfc0, 0xc420250bb0, 0xc420250cc0, 0x0,
 0x0)
2018-05-29T15:12:45.846Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1:         /home/travis/gopath/src/github.com/hashicorp/terraform/plugin/resource_provider.go:510 +0x4e
2018-05-29T15:12:45.847Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: reflect.Value.call(0xc4202632c0, 0xc42000c9a0, 0x13, 0xfc103c, 0x4, 0xc420964f20, 0x3, 0x3, 0x403a23, 0xc420232380, ..
.)
2018-05-29T15:12:45.848Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1:         /home/travis/.gimme/versions/go1.9.linux.amd64/src/reflect/value.go:434 +0x906
2018-05-29T15:12:45.848Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: reflect.Value.Call(0xc4202632c0, 0xc42000c9a0, 0x13, 0xc4203f2720, 0x3, 0x3, 0xc4203f2720, 0xc4203f2728, 0xc420355ec0)

2018-05-29T15:12:45.849Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1:         /home/travis/.gimme/versions/go1.9.linux.amd64/src/reflect/value.go:302 +0xa4
2018-05-29T15:12:45.850Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: net/rpc.(*service).call(0xc420482d40, 0xc42005a190, 0xc420015a28, 0xc4200f1500, 0xc4208f82c0, 0xdd1f20, 0xc420250bb0, 
2018-05-29T15:12:45.850Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1:         /home/travis/.gimme/versions/go1.9.linux.amd64/src/net/rpc/server.go:381 +0x142
2018-05-29T15:12:45.850Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1: created by net/rpc.(*Server).ServeCodec
2018-05-29T15:12:45.850Z [DEBUG] plugin.terraform-provider-cloudfoundry_v0.9.1:         /home/travis/.gimme/versions/go1.9.linux.amd64/src/net/rpc/server.go:475 +0x36b
2018/05/29 15:12:45 [ERROR] root: eval: *terraform.EvalRefresh, err: cloudfoundry_space.cassandra-smoke-tests-space: unexpected EOF

Discussion: testing resources

I've noticed in the unit tests that do:

resource = LoadCfResource(CfBuildpackResource{})
resourceData = resource.Data(&terraform.InstanceState{})

It's not possible to test an resource.Update() method which uses resourceData.HasChange() because resourceData doesn't have any record of the before and after diff.

Do you have any thoughts about how it might be possible to implement a more realistic test? I was wondering..

  • do we need to poke schema.Resource.Diff() and schema.Resource.Apply() ourselves?
  • would it be better to use the resource.Test acceptance test framework along with the fake client?
  • is this going too much against the grain of Terraform, who typically only use acceptance tests against real APIs, and should we do that instead of unit testing?

cloudfoundry_domain unexpectedly recreates private shared domains, deleting existing routes as a side effect

We observe the following traces without apparent related TF spec changes

cloudfoundry_domain.tf-internet-paas-apps-domain: Modifying... (ID: fa6aabce-2819-4328-abe2-738456aeae07)
  orgs_shared_id.#:          "5" => "0"
  orgs_shared_id.1707224278: "3042fe9b-2e05-4293-a977-50e39eda9d3a" => ""
  orgs_shared_id.2851328613: "1a0b3943-1a11-4804-aeff-9de1d543b930" => ""
  orgs_shared_id.3544041737: "2f9da367-07f5-4745-bb6e-09df876812b3" => ""
  orgs_shared_id.3732900449: "be730559-33c1-4714-ac6f-69f722d27007" => ""
  orgs_shared_id.590687062:  "e14c9737-0ebb-4ec5-8e7f-06ea63ea96d2" => ""

Suspecting that when refreshing the list, the order of orgs (with whom the domain is shared) changes unpredicbily and triggers the equivalent of cf unshare-private-domain org domain and cf share-private-domain org domain

As a result, the corresponding existing routes gets deleted silently without warning.

Hopefully, the split between domain and private_domain_access in mevansam/terraform-provider-cf won't allow the same issue to reproduce there.

cloudfoundry_quota creates org quotas even when org_id is omitted

The cloudfoundry_quota documentation mentions

org_id: (Optional, default: null) If set to an organization id created from resource or data source cloudfoundry_organization, it will be considered as organization quota, else it will be a space quota.

Using the following terraform config

resource "cloudfoundry_quota" "tf_coab_smoketests_quota" {
  name = "tf_coab_smoketests_quota"
  total_memory = "2G"
  instance_memory = "2G"
  routes = 5
  service_instances = 15 #Restrict to 15
  app_instances = 5
  allow_paid_service_plans = true
  reserved_route_ports = 0
}

resource "cloudfoundry_space" "coa-cassandra-smoke-tests-space" {
  name = "coa-cassandra-smoke-tests"
  org_id = "${data.cloudfoundry_organization.org-service-sandbox.id}"
[...]  
  quota_id = "${cloudfoundry_quota.tf_coab_smoketests_quota.id}"
}

fails with the following message

cloudfoundry_quota.tf_coab_smoketests_quota: Creating...
  allow_paid_service_plans: "" => "true"
  app_instances:            "" => "5"
  instance_memory:          "" => "2G"
  name:                     "" => "tf_coab_smoketests_quota"
  reserved_route_ports:     "" => "0"
  routes:                   "" => "5"
  service_instances:        "" => "15"
  total_memory:             "" => "2G"
	
cloudfoundry_space.coa-cassandra-smoke-tests-space: Creating...
  allow_ssh:             "" => "true"
  name:                  "" => "coa-cassandra-smoke-tests"
  org_id:                "" => "a95b339c-c52f-4b7d-bc70-d0c57af38f73"
  sec_groups.#:          "0" => "2"
  sec_groups.1097534615: "" => "8df01522-a1c4-4c65-a213-1c7657a6fd6e"
  sec_groups.142526119:  "" => "ec556d93-acd8-49e2-a0e6-4f57bebde4c8"
	
cloudfoundry_quota.tf_coab_smoketests_quota: Creation complete after 0s (ID: 38d39477-eb72-4421-8f52-c155392de53c)
	
cloudfoundry_space.coa-cassandra-broker-space: Modifying... (ID: 43eaa3ef-50d1-45ef-8647-cb3a3c7af49c)
  quota_id: "" => "38d39477-eb72-4421-8f52-c155392de53c"
	
cloudfoundry_space.coa-cassandra-smoke-tests-space: Creation complete after 2s (ID: 0981269a-47d9-45a4-b1de-5bede572e86c)

Error: Error applying plan:

1 error(s) occurred:
	
* cloudfoundry_space.coa-cassandra-broker-space: 1 error(s) occurred:
* cloudfoundry_space.coa-cassandra-broker-space: Server error, status code: 404, error code: 310007, message: Space Quota Definition could not be found: 38d39477-eb72-4421-8f52-c155392de53c

leads to the generation of an org quota as not a space quota

$ cf space-quotas
Getting space quotas as xx..
OK

$ cf quotas 
Getting quotas as xx...
OK

name                                        total memory   instance memory   routes   service instances   paid plans   app instances   route ports
[...]
tf_coab_smoketests_quota                    2G             2G                5        15                  allowed      5               0

cloudfoundry_quota creates space quotas even when org_id is defined, and quota unassigned

This is variation of #34

The cloudfoundry_quota documentation mentions

org_id: (Optional, default: null) If set to an organization id created from resource or data source cloudfoundry_organization, it will be considered as organization quota, else it will be a space quota.

Given the following specs (note the org is NOT referencing the quota as instructed in the organization documentation):

resource "cloudfoundry_organization" "org-orange-private-sandboxes" {
  name = "orange-private-sandboxes"
}

resource "cloudfoundry_quota" "quota_org-orange-private-sandboxes" {
  name                     = "tf_orange-private-sandboxes"
  org_id                   = "${cloudfoundry_organization.org-orange-private-sandboxes.id}"
  total_memory             = "30G"
  instance_memory          = "30G"
  routes                   = 2000
  service_instances        = 400
  app_instances            = 400
  allow_paid_service_plans = true
  reserved_route_ports     = 0
}

then the tf apply succeeds

cloudfoundry_quota.quota_org-orange-private-sandboxes: Creating...
  allow_paid_service_plans: "" => "true"
  app_instances:            "" => "400"
  instance_memory:          "" => "30G"
  name:                     "" => "tf_orange-private-sandboxes"
  org_id:                   "" => "6c5ea025-074d-4b41-8c0d-fc7924782f57"
  reserved_route_ports:     "" => "0"
  routes:                   "" => "2000"
  service_instances:        "" => "400"
  total_memory:             "" => "30G"

but actually creates a space quota, and not an org quota:

cf t
api endpoint:   https://api.redacted
api version:    2.102.0
user:           redacted
org:            orange-private-sandboxes

$ cf space-quotas
Getting space quotas as redacted...
OK

name                          total memory   instance memory   routes   service instances   paid plans   app instances   route ports
tf_orange-private-sandboxes   30G           30G              2000     400                 allowed      400             0

$ cf quotas | grep private

Feature request: Disable service access

It would be useful to include an equivalent of the cf disable-service-access command in the service broker resource--for example, to enable a service for all organizations but one. Syntax might look like:

resource "cloudfoundry_service_broker" "service_broker_mysuperbroker" {
  name = "mysuperbroker"
  url = "http://url.of.my.service.broker.com"
  username = "user"
  password = "mypassword"
  service_access {
    service = "service_name_from_service_broker_catalog"
    plan = "plan_from_service_broker_catalog"
    org_id = "${cloudfoundry_organization.org_mysuperorg.id}"
    enable = false
  }
}

WDYT?

Provider crash: concurrent map read and map write during translation

Terraform run each resource in parallel and an error occurred sometimes during getting the list of organization:

/Users/arthurhalet/.gobrew/versions/1.7/src/runtime/panic.go:566 +0x95 fp=0xc4207ec340 sp=0xc4207ec320
runtime.mapaccess1_faststr(0x6c5580, 0xc4203a1c50, 0x799668, 0x15, 0xc4203a2ff8)
/Users/arthurhalet/.gobrew/versions/1.7/src/runtime/hashmap_fast.go:201 +0x4f3 fp=0xc4207ec3a0 sp=0xc4207ec340
code.cloudfoundry.org/cli/vendor/github.com/nicksnyder/go-i18n/i18n/bundle.(*Bundle).translate(0xc42000c700, 0xc4204bc440, 0x799668, 0x15, 0x0, 0x0, 0x0, 0xd4, 0xc4200c30e0)
/Users/arthurhalet/go/src/code.cloudfoundry.org/cli/vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go:238 +0xb1 fp=0xc4207ec468 sp=0xc4207ec3a0
code.cloudfoundry.org/cli/vendor/github.com/nicksnyder/go-i18n/i18n/bundle.(*Bundle).TfuncAndLanguage.func1(0x799668, 0x15, 0x0, 0x0, 0x0, 0x0, 0x0)
/Users/arthurhalet/go/src/code.cloudfoundry.org/cli/vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle.go:195 +0x65 fp=0xc4207ec4c0 sp=0xc4207ec468

[...]

code.cloudfoundry.org/cli/cf/api/organizations.CloudControllerOrganizationRepository.GetManyOrgsByGUID(0x21480e0, 0xc4201d6d80, 0x0, 0x0, 0x7f7628, 0x1, 0x12a05f200, 0x0, 0x0, 0x0, ...)
/Users/arthurhalet/go/src/code.cloudfoundry.org/cli/cf/api/organizations/organizations.go:60 +0x29a fp=0xc4207ed0f0 sp=0xc4207ecda8
github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/resources.CfOrganizationResource.getOrgFromCf(0x0, 0x0, 0xb15740, 0xc420294000, 0xc4206845a0, 0x24, 0x0, 0x0, 0x0, 0x0, ...)
/Users/arthurhalet/go/src/github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/resources/organizations.go:93 +0x129 fp=0xc4207ed4c8 sp=0xc4207ed0f0
github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/resources.CfOrganizationResource.Read(0x0, 0x0, 0xc4207a1740, 0x76f420, 0xc420294000, 0x0, 0xb0b4c0)

The error come from https://github.com/nicksnyder/go-i18n which is writing and reading in same time on a map (still cause terraform run resource in parallel)

This the cloud foundry CLI which use go-i18n to do translation.
Like we use some part of the cli to use it as a client for Cloud Foundry we are really tied to this translation functionality (cause the cli is tied to it).

Fortunately pull request and issue are already addressed to this repo:

fail to update service broker

Service broker resource update does not seem to be applied in cloudfoundry.

Given existing service broker resource
When I update service broker password
Then service broker should be updated on CF with new password -> Failed

Terraform credhub support

The cloudfoundry community is moving to global shared secrets and certificate, with the credhub project.

Credhub API is a simple REST API.
A terraform integration would be very useful.

Example use case:

  • provision a cf service broker. Requires the broker http basic auth password. We should be able to get it from credhub in the key (/my_bosh_directot/my_service_deployment/broker_password).

cc @gberche-orange @ArthurHlt

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.