Usa módulos de plantilla

Los módulos de plantilla son archivos de ayuda que ejecutan funciones específicas para que tus plantillas sean más eficientes. Por ejemplo, puedes tener un módulo que genere nombres únicos para tus recursos. Deployment Manager puede ejecutar cualquier módulo escrito en Python o en Jinja.

Antes de comenzar

Crear un módulo de plantilla

Un módulo de plantilla se trata de igual manera que un archivo de plantilla normal y se puede escribir en Jinja o en Python.

Por ejemplo, la que sigue es una plantilla de ayuda que genera un nombre si se le da un prefijo o un sufijo.

Jinja


En Jinja, esta plantilla de ayuda (en el ejemplo, helpers/common.jinja) se vería de la siguiente manera:



{%- macro GenerateMachineName(prefix='', suffix='') -%}
    {{ prefix + "-" + suffix }}
{%- endmacro %}

Luego, puedes importar esta plantilla y usarla como módulo. En tu plantilla en Jinja, podrías usar un módulo como el que sigue:

# Copyright 2016 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


{% import 'helpers/common.jinja' as common %}

resources:
- name: {{ common.GenerateMachineName("myfrontend", "prod") }}
  type: compute.v1.instance
  properties:
    zone: us-central1-f
    machineType: https://www.googleapis.com/compute/v1/projects/{{ env['project'] }}/zones/us-central1-f/machineTypes/f1-micro
    disks:
    - deviceName: boot
      type: PERSISTENT
      boot: true
      autoDelete: true
      initializeParams:
        sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/family/debian-11
    networkInterfaces:
    - network: https://www.googleapis.com/compute/v1/projects/{{ env['project'] }}/global/networks/default
      accessConfigs:
      - name: External NAT
        type: ONE_TO_ONE_NAT

Luego, la configuración debe importar ambos archivos (incluido el archivo helpers/common.jinja):

# Copyright 2015 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

imports:
- path: helpers/common.jinja
- path: vm-instance-example.jinja

resources:
- name: my-vm
  type: vm-instance-example.jinja

El servicio Deployment Manager expandirá la configuración y la configuración final presenta el siguiente aspecto:

resources:
- name: myfrontend-prod
  type: compute.v1.instance
  properties:
    zone: us-central1-f
    machineType: https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-f/machineTypes/f1-micro
    disks:
    - deviceName: boot
      type: PERSISTENT
      boot: true
      autoDelete: true
      initializeParams:
        sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/family/debian-9
    networkInterfaces:
    - network: https://www.googleapis.com/compute/v1/projects/myproject/global/networks/default
      accessConfigs:
      - name: External NAT
        type: ONE_TO_ONE_NAT

Python


En Python, la plantilla de ayuda (en el ejemplo, helpers/common.py) se vería de la siguiente manera:

# Copyright 2016 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Generates name of a VM."""


def GenerateMachineName(prefix, suffix):
  return prefix + "-" + suffix

Para usarlo en tu plantilla en Python:

# Copyright 2016 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Constructs a VM with imported module."""
from helpers import common

COMPUTE_URL_BASE = 'https://www.googleapis.com/compute/v1/'


def GenerateConfig(context):
  """Generates configuration of a VM."""
  resources = [{
      'name': common.GenerateMachineName('myfrontend', 'prod'),
      'type': 'compute.v1.instance',
      'properties': {
          'zone': 'us-central1-f',
          'machineType': COMPUTE_URL_BASE + 'projects/' + context.env['project']
                         + '/zones/us-central1-f/machineTypes/f1-micro',
          'disks': [{
              'deviceName': 'boot',
              'type': 'PERSISTENT',
              'boot': True,
              'autoDelete': True,
              'initializeParams': {
                  'sourceImage': COMPUTE_URL_BASE + 'projects/'
                                 'debian-cloud/global/images/family/debian-11'}
          }],
          'networkInterfaces': [{
              'network': COMPUTE_URL_BASE + 'projects/' + context.env['project']
                         + '/global/networks/default',
              'accessConfigs': [{
                  'name': 'External NAT',
                  'type': 'ONE_TO_ONE_NAT'
              }]
          }]
      }
  }]
  return {'resources': resources}

Luego, la configuración debe importar ambos archivos (incluido el archivo helpers/common.py):

# Copyright 2015 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

imports:
- path: helpers/common.py
- path: vm-instance-example.py

resources:
- name: my-vm
  type: vm-instance-example.py

A continuación, verás un módulo de ayuda más complicado:

# Copyright 2015 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Helper methods for working with containers in config."""
import common
import default
import yaml

# Specific properties for this component, also see container_instance
DCKRENV = default.DCKRENV
DCKRIMAGE = default.DCKRIMAGE

MANIFEST = """
version: v1beta2
containers:
  - name: %(name)s
    image: %(dockerImage)s
    ports:
      - name: %(name)s-port
        hostPort: %(port)i
        containerPort: %(port)i
    %(env)s
"""


def GenerateManifest(context):
  """Generates a Container Manifest given a Template context.

  Args:
    context: Template context, which must contain dockerImage and port
        properties, and an optional dockerEnv property.

  Returns:
    A Container Manifest as a YAML string.
  """
  env = ""
  env_list = []
  if DCKRENV in context.properties:
    for key, value in context.properties[DCKRENV].iteritems():
      env_list.append({"name": key, "value": value})
  if env_list:
    env = "env: " + yaml.dump(env_list, default_flow_style=True)

  manifest_yaml_string = MANIFEST % {
      "name": context.env["name"],
      "dockerImage": context.properties[DCKRIMAGE],
      "port": context.properties[default.PORT],
      "env": env
  }
  return common.GenerateEmbeddableYaml(manifest_yaml_string)

¿Qué sigue?