Substitution are in a beta state and may not be available on your Apollo Hub. Contact your Palantir representative to learn more.
Services can read in generated and user-defined secrets from configuration using the substitution language’s secret
method:
Copied!1 2 3 4 5 6 7 8
conf: oauth-client: id: my-oauth-client-id secret: '{{secret("my-oauth-secret")}}' generated_secrets: my-oauth-secret: type: random_string length: 32
The secret
function used above additionally supports the following named arguments:
name
: The name of the secret. If no named arguments are provided, the provided string is considered the secret name; in the example above, this is my-oauth-secret
.part
: The part of the secret to render. Different types of secrets support different parts:
secret_value
: The value of the secret. The default part rendered when no part is defined.secret_value
: The value of the secret. The default part rendered when no part is defined.rsa_pkcs8
:
private_key
: The base64-encoded RSA private key in PKCS8 format.public_key
: The base64-encoded RSA public key in PKCS8 format.ec_pkcs8
:
private_key
: The base64-encoded elliptic-curve private key in PKCS8 format.public_key
: The base64-encoded elliptic-curve public key in PKCS8 format.Named argument usage appears as:
Copied!1 2 3 4 5 6 7 8 9
generated_secrets: my-oauth-secret: type: random_string length: 24 conf: oauth-client: id: my-oauth-client-id secret: '{{secret(name: "my-oauth-secret")}}' bcrypted-secret: '{{secret(name: "my-oauth-secret", part: "bcrypt_hash")}}'
The Service Management Plane’s substitution language exposes information for accessing Certificates and CAs through configuration. Referencing these security material file paths can be done using the ssl
method:
Copied!1 2 3 4 5 6
conf: cert-file: '{{ssl.cert_path}}' key-file: '{{ssl.pem_path}}' ca-file: '{{ssl.ca_path}}' truststore: '{{ssl.truststore_path}}' keystore: '{{ssl.keystore_path}}'
Substitution language provides paths on disk to volume mounts requested in product configuration (see Requesting Storage for Your Service for how to request volumes). Reading in the path to a volume can be done using the volumes
substitution method:
Copied!1 2 3 4 5 6
volumes: app-data: durable-storage-configuration: desired-size: 10G conf: my-app-data-dir: '{{volumes.app-data.PathOnDisk}}'
The substitution language includes a method for referencing a product's declared endpoints:
Copied!1 2 3 4 5 6 7 8 9
endpoints: definitions: my-endpoint: desired-port: 8443 path: /my-endpoint-path conf: server: my-endpoint-port: '{{ endpoints.definitions.port }}' my-endpoint-path: '{{ endpoints.definitions.path }}'
To help developers to avoid repeating themselves when writing configurations, substitution supports referencing other fields under a configuration.yml
file’s conf
block:
Copied!1 2 3
conf: a: b also-a: '{{conf.a}}' # renders to 'b'
Substitution additionally offers a set of built-ins for convenience. These include:
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
conf: a: 5 b: 2 add: '{{conf.a + conf.b}}' subtract: '{{conf.a - conf.b}}' multiply: '{{conf.a * conf.b}}' divide: '{{conf.a / conf.b}}' int_divide: '{{conf.a // conf.b}}' mod: '{{conf.a % conf.b}}' eq: '{{conf.a == conf.b}}' neq: '{{conf.a != conf.b}}' gt: '{{conf.a > conf.b}}' lt: '{{conf.a < conf.b}}' geq: '{{conf.a >= conf.b}}' leq: '{{conf.a <= conf.b}}' and: '{{conf.a != null && conf.a > 4}}' or: '{{conf.b == null || conf.b < 4}}' c: ['a'] d: ['b'] concat: '{{c + d}}'
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
conf: list-of-list: [[1,2,3], [4,5,6], [7,8,9]] # `len` gives the length of an array num-name-nodes: "{{len(discovered.hadoop-name-node))}}" # `join` concatenates strings with a separator comma-separated-uris: "{{join(discovered.hadoop-name-node, ',')}}" # `distinct` removes duplicate entries from a list and returns only the unique elements, # it uses deep equality to compare elements and will work for both simple and complex types distinct-values: "{{distinct(discovered.hadoop-name-node)}}" # a Gatekeeper initial node is a json object: e.g. "{ "resource": { "id": "ri.gatekeeper.resource.root", "policy": ... } }" distinct-gk-nodes: "{{distinct(discovered.gatekeeper-nodes)}}" # `flatten` combines a list of lists by extracting the inner values into a single list # it only expands 1 level and will not recursively flatten inner lists flattened-list: "{{flatten(conf.list-of-list)}}" # `cross_join` takes the cross product of 2 string arrays by concatenting each element with its counter-part in the other array # when cross joining an array of size `n` with an array of size `m`, the result will be an array of size `n x m` # the example below will return [ "a1", "a2", "b1", "b2", "c1", "c2" ] cross-joined-list: "{{cross_join(['a', 'b', 'c'], ['1', '2'])}}" # `cross_join` automatically encapsulates string arguments as arrays of size 1. The example below returns: # [ "https://localhost", "wss://localhost" ] cross-joined-hosts: "{{cross_join(['https://', 'wss://'], "localhost")}}" # `cross_join` prioritizes the first arugment in its join operations, if you join a list against an empty list, you will # receive the first list back. However, if you an empty list with a non-empty list, you will receive an empty list # the first example returns [ "foo", "bar" ], the second example returns [] cross-join-non-empty: "{{cross_join(["foo", "bar"], []}} cross-join-empty: "{{cross_join([], ["foo", "bar"]}} # `min` returns the minimum value in an array of numeric values min-value: "{{min([1.0, -1.9, 100, -22.2])}}" # `max` returns the maximum value in an array of numeric values max-value: "{{max([1.0, -1.9, 100, -22.2])}}" # `sum` returns the sum of an array of numeric values sum-value: "{{sum([1.0, -1.9, 100, -22.2])}}" # `contains` returns `true` if an array contains a value that matches the string argument, returns `false` # if the value is not contained in the array node.master: {{ contains(conf.tags, 'master') }} # `merge` returns the result of merging the key/value pairs of a second map argument into the first. If a key exists # in both map arguments then the value for the key in the first argument is used. merged-map: "{{merge(map1, map2)}}" # As of deployd 1.168.0, `merge` supports a variable number of maps. `merge` must be called with at least one # argument. If a key exists in more than one of the provided maps, then the value for the key in the first # argument that contains the key is used. merged-map-of-many-maps: "{{merge(map1, map2, map3, map4)}}" # `base64` accepts a string argument and returns the base 64 encoded representation, it will use padding by default # if you require the un-padded version of the base 64 encoding, use the `nopadding: true` option base64-padding: "{{base64('my-string-value'}}" base64-no-padding: "{{base64('my-string-value', nopadding: true)}}" # decodes a base64-encoded string from-base64: "{{decode_base64(conf.foo-base64)}}" # converts a string to its hexadecimal value; convert a hexadecimal text to its string value to-hex: "{{hex('my-string-value')}}" from-hex: "{{decode_hex(conf.foo-hex)}}" # hash functions `md5`, `sha1`, and `sha256` compute the hash for a string argument using the named algorithm md5-hash: "{{md5('my-string-value')}}" sha1-hash: "{{sha1('my-string-value')}}" sha256-hash: "{{sha256('my-string-value')}}"