Usar módulos de modelos

Os módulos de modelos são ficheiros auxiliares que executam funções específicas que podem tornar os seus modelos mais eficientes. Por exemplo, pode ter um módulo que gera nomes únicos para os seus recursos. O Deployment Manager pode executar qualquer módulo escrito em Python ou Jinja.

Antes de começar

Criar um módulo de modelo

Um módulo de modelo é tratado como um ficheiro de modelo normal e pode ser escrito em Jinja ou Python.

Por exemplo, o seguinte é um modelo auxiliar que gera um nome dado um prefixo e um sufixo.

Jinja


Em Jinja, este modelo auxiliar (neste exemplo, denominado helpers/common.jinja) teria o seguinte aspeto:



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

Em seguida, pode importar este modelo e usá-lo como um módulo. No modelo Jinja, pode usar o módulo da seguinte forma:

# 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

Em seguida, a configuração tem de importar ambos os ficheiros (incluindo o ficheiro 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

O serviço Deployment Manager expande a configuração e a configuração final tem o seguinte aspeto:

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


Em Python, o modelo auxiliar (neste exemplo, denominado helpers/common.py) teria o seguinte aspeto:

# 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 o usar no seu modelo 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}

Em seguida, a configuração tem de importar ambos os ficheiros (incluindo o ficheiro 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

Segue-se um módulo auxiliar mais 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)

O que se segue?