def provision_storage_class(schema, prop, app_name, namespace, provisioner):
  if not provisioner:
    provisioner = _DEFAULT_STORAGE_CLASS_PROVISIONER
  volume_binding_mode = 'Immediate'
  if provisioner == 'kubernetes.io/vsphere-volume':
    parameters = {'diskformat': 'thin'}
  elif provisioner == 'kubernetes.io/gce-pd':
    # WaitForFirstConsumer is only available for gce-pd. See:
    # https://kubernetes.io/docs/concepts/storage/storage-classes/#volume-binding-mode
    volume_binding_mode = 'WaitForFirstConsumer'
    if prop.storage_class.ssd:
      parameters = {
          'type': 'pd-ssd',
      }
    else:
      raise Exception('Do not know how to provision for property {}'.format(
          prop.name))
  elif provisioner == 'kubernetes.io/no-provisioner':
    # local-shared storage class is already pre-provisioned
    return 'local-shared', []

  sc_name = dns1123_name('{}-{}-{}'.format(namespace, app_name, prop.name))
  manifests = [{
      'apiVersion': 'storage.k8s.io/v1',
      'kind': 'StorageClass',
      'metadata': {
          'name': sc_name,
      },
      'provisioner': provisioner,
      'parameters': parameters,
      'volumeBindingMode': volume_binding_mode
  }]
  return sc_name, add_preprovisioned_labels(manifests, prop.name)
def provision_from_storage(key, value, app_name, namespace):
  """Provisions a resource for a property specified from storage."""
  raw_manifest = storage.load(value)

  manifest = yaml.safe_load(raw_manifest)
  if 'metadata' not in manifest:
    manifest['metadata'] = {}
  resource_name = dns1123_name("{}-{}".format(app_name, key))
  manifest['metadata']['name'] = resource_name
  manifest['metadata']['namespace'] = namespace

  return resource_name, add_preprovisioned_labels([manifest], key)
def provision_storage_class(schema, prop, app_name, namespace):
  if prop.storage_class.ssd:
    sc_name = dns1123_name('{}-{}-{}'.format(namespace, app_name, prop.name))
    manifests = [{
        'apiVersion': 'storage.k8s.io/v1',
        'kind': 'StorageClass',
        'metadata': {
            'name': sc_name,
        },
        # Some intelligence might go here to determine what
        # provisioner and configuration to use here and below.
        'provisioner': 'kubernetes.io/gce-pd',
        'parameters': {
            'type': 'pd-ssd',
        }
    }]
    return sc_name, add_preprovisioned_labels(manifests, prop.name)
  else:
    raise Exception('Do not know how to provision for property {}'.format(
        prop.name))
def provision_service_account(schema, prop, app_name, namespace,
                              image_pull_secret):
  sa_name = dns1123_name('{}-{}'.format(app_name, prop.name))
  subjects = [{
      'kind': 'ServiceAccount',
      'name': sa_name,
      'namespace': namespace,
  }]
  service_account = {
      'apiVersion': 'v1',
      'kind': 'ServiceAccount',
      'metadata': {
          'name': sa_name,
          'namespace': namespace,
      },
  }
  if image_pull_secret:
    service_account['imagePullSecrets'] = [{
        'name': image_pull_secret,
    }]

  manifests = [service_account]
  for i, rules in enumerate(prop.service_account.custom_role_rules()):
    role_name = '{}:{}-r{}'.format(app_name, prop.name, i)
    manifests.append({
        'apiVersion': 'rbac.authorization.k8s.io/v1',
        'kind': 'Role',
        'metadata': {
            'name': role_name,
            'namespace': namespace,
        },
        'rules': rules,
    })
    manifests.append({
        'apiVersion': 'rbac.authorization.k8s.io/v1',
        'kind': 'RoleBinding',
        'metadata': {
            'name': '{}:{}-rb{}'.format(app_name, prop.name, i),
            'namespace': namespace,
        },
        'roleRef': {
            'apiGroup': 'rbac.authorization.k8s.io',
            'kind': 'Role',
            'name': role_name,
        },
        'subjects': subjects,
    })
  for i, rules in enumerate(prop.service_account.custom_cluster_role_rules()):
    role_name = '{}:{}:{}-r{}'.format(namespace, app_name, prop.name, i)
    manifests.append({
        'apiVersion': 'rbac.authorization.k8s.io/v1',
        'kind': 'ClusterRole',
        'metadata': {
            'name': role_name,
        },
        'rules': rules,
    })
    manifests.append({
        'apiVersion': 'rbac.authorization.k8s.io/v1',
        'kind': 'ClusterRoleBinding',
        'metadata': {
            'name': '{}:{}:{}-rb{}'.format(namespace, app_name, prop.name, i),
            'namespace': namespace,
        },
        'roleRef': {
            'apiGroup': 'rbac.authorization.k8s.io',
            'kind': 'ClusterRole',
            'name': role_name,
        },
        'subjects': subjects,
    })
  for role in prop.service_account.predefined_roles():
    manifests.append({
        'apiVersion': 'rbac.authorization.k8s.io/v1',
        'kind': 'RoleBinding',
        'metadata': {
            'name':
                limit_name('{}:{}:{}-rb'.format(app_name, prop.name, role), 64),
            'namespace':
                namespace,
        },
        'roleRef': {
            'apiGroup': 'rbac.authorization.k8s.io',
            # Note: predefined ones are actually cluster roles.
            'kind': 'ClusterRole',
            'name': role,
        },
        'subjects': subjects,
    })
  for role in prop.service_account.predefined_cluster_roles():
    manifests.append({
        'apiVersion': 'rbac.authorization.k8s.io/v1',
        'kind': 'ClusterRoleBinding',
        'metadata': {
            'name':
                limit_name(
                    '{}:{}:{}:{}-crb'.format(namespace, app_name, prop.name,
                                             role), 64),
            'namespace':
                namespace,
        },
        'roleRef': {
            'apiGroup': 'rbac.authorization.k8s.io',
            'kind': 'ClusterRole',
            'name': role,
        },
        'subjects': subjects,
    })
  return sa_name, add_preprovisioned_labels(manifests, prop.name)