
# IaC代码结构介绍
#### 单文件描述结构
单文件描述结构样例如下：
```
├── package.json                    # 包描述文件（必须）
└── specs                           # 规格总目录（必须）
      ├── cn_dev_default            # cn_dev_default规格目录，可用于描述一个开发用途的服务环境所使用的基础设施
      └── cn_product_default        # cn_product_default规格目录，可用于描述一个生产用途的服务环境所使用的基础设施
            └── meta.yaml           # IaC主体描述文件
```
IaC主体描述文件meta.yaml
```
type: WiseCloud::Environment                # 描述环境类型，当前仅支持 WiseCloud::Environment 
components:                                 # 定义服务环境所包含的组件列表，每个组件包含一个资源列表
- name: environment                         # 组件名称
  resources:                                # 资源列表
  - name: fgc_cloudmap                      # 资源名称，同类型的资源的名称在整个服务环境中唯一
    type: WiseCloud::Endpoint::CloudMap     # 资源类型
    properties:                             # 资源属性：具体包含哪些属性，由资源类型决定
      ...
- name: FGCActionInvokerService
  resources:
    ... 
- name: FGCAbilityCenterService
  resources:
    ...
applyPipeline: default                      # 默认选用名为default的组件编排流水线
pipelines:                                  # 定义可用的组件编排流水线
- name: default                             # 流水线的名称，作为流水线被引用的唯一标识
  action: Serial                            # 串行编排
  tasks:                                    # 串行编排的任务列表
  - name: apply-environment                 # 任务名称 
    action: Apply                           # 应用变更
    component:                              # 变更组件的相关约束
      name: environment                     # 变更的组件名称
  - name: parallel-others 
    action: Parallel                        # 并行编排
    tasks:                                  # 并行编排的任务列表
    - name: apply-FGCActionInvokerService   # 任务名称
      action: Apply                         # 应用变更
      component:                            # 变更组件的相关约束
        name: FGCActionInvokerService       # 变更的组件名称
    - name: apply-FGCAbilityCenterService   # 任务名称
      action: Apply                         # 应用变更
      component:                            # 变更组件的相关约束
        name: FGCAbilityCenterService       # 变更的组件名称
```
以上示例清晰地展示了IaC3.0的资源组织结构：
- Nuwa，CloudMap等资源，依照业务需要，可划分到不同的组件中。
- 一个组件可对应于一个微服务，或是服务内共享的中间件集合。
- 全体组件的集合，则汇总描述了整个服务环境的期望部署状态。
- 组件编排流水线，则是以组件为最小粒度来描述服务环境是如何做部署状态的迁移的。其可以处理组件间的升级依赖关系，以及通过多阶段方式提供灰度升级能力。
 
#### 多文件描述结构
为了避免诸多资源的描述都集中于meta.yaml，而造成文件内容过长难以管理。通过引入resources.yaml和文件引用语法，可以将单文件结构改造为多文件描述目录结构，样例如下：
```
├── package.json                    # 包描述文件（必须）
└── specs                           # 规格总目录（必须）
      ├── cn_dev_default            # cn_dev_default规格目录，可用于描述一个开发用途的服务环境所使用的基础设施
      └── cn_product_default        # cn_product_default规格目录，可用于描述一个生产用途的服务环境所使用的基础设施
            └── meta.yaml
            └── VirtualAppManangerService
                  ├── config
                  │   └── business_config.yaml
                  │   └── nginx.conf
                  ├── db
                  │   └── schema.sql
                  ├── values.yaml
                  └── resources.yaml
```
- 引入resources.yaml IaC3.0 支持当meta.yaml不编写components时，通过提取具体规格目录（如：cn_dev）的直接子目录（也称为组件目录）里的resources.yaml来自动构造出meta.yaml的components。
  引入resources.yaml后目录结构样例如下：
  ```
  ├── meta.yaml                       # IaC主体描述文件，内容不包含components
  ├── WiseEyeChaosMonkeyMgrService    # 组件一：ChaosMonkey管理服务
  │    └── resources.yaml            # 组件一的资源列表
  ├── WiseEyeChaosMonkeyPortal        # 组件二：ChaosMonkey网页服务
  │    └── resources.yaml            # 组件二的资源列表
  ├── environment                     # 组件三：环境
  │    └── resources.yaml            # 组件三的资源列表
  └── functions                       # 组件四：函数
        └── resources.yaml            # 组件四的资源列表
  ```
  
- 使用文件引用语法 尽管meta.yaml已支持分散到诸多的组件目录中，但是每个组件仍然存在更新频率不同的配置。例如：微服务所用的镜像版本号更新频率较高。IaC3.0支持使用文件引用语法：允许YAML通过$ref键值对跨文档引用其他文本文件的内容。应用$ref语法，可以自由实现将资源、属性分散到更多文件中去。建议将更新频率较高的属性分散到被引用文件中，保持主体文件的结构稳定。
  - YAML文档整体引用 resources.yaml原始内容：
    ```
    # resources.yaml
    - name: virtualapp
      type: Wisecloud::Nuwa::Runtime::MicroService
      properties:
        configs:
          - name: common.java.http.ssl_protocols
            value: TLSv1.2
            sensitive: false
          - name: common.java.http.enabled_cipher_suites
            value: aes_128_gcm|aes_256_gcm
            sensitive: false
        globalConf: |-        
          #user  slb slb;
          worker_processes auto;
          #worker_cpu_affinity 0001 0010 0100 1000;
          pid        logs/nginx.pid;
          ......
         #  yaml 文件中多行字符串可以使用|保留换行符，如：globalConf
         # |：文中自动换行，默认仅保留一行空行
         # |+：文中自动换行，保留字符串后面所有的空行
         # |-：文中自动换行，删除字符串后面所有的空行
    ```
    将 properties \> configs下的内容，放置于business_config.yaml。
    ```
    # business_config.yaml
    - name: common.java.http.ssl_protocols
      value: TLSv1.2
      sensitive: false
    - name: common.java.http.enabled_cipher_suites
      value: aes_128_gcm|aes_256_gcm
      sensitive: false
    ```
    则resources.yaml 可修改为：
    ```
    # resources.yaml
    - name: virtualapp
      type: Wisecloud::Nuwa::Runtime::MicroService
      properties:
        configs:
          $ref: 'config/business_config.yaml#' # 运行时，会将config/business_config.yaml的整个YAML文档对象，替换掉整个$ref键值对
    ```
    将properties \> globalConf下的内容，放置于nginx.conf
    ```
    # nginx.conf
    #user  slb slb;
    worker_processes auto;
    #worker_cpu_affinity 0001 0010 0100 1000;
    pid        logs/nginx.pid;
    ......
    ```
    则 resources.yaml 可修改为：
    ```
    # resources.yaml
    - name: virtualapp
      type: Wisecloud::Nuwa::Runtime::MicroService
      properties:
        configs:
          $ref: 'config/business_config.yaml#' # 运行时，会将config/business_config.yaml的整个YAML文档对象，替换掉整个$ref键值对
        globalConf:
          $ref: 'config/nginx.conf' # 运行时，引用的是config/nginx.conf这个配置文件内容所构成的字符串
    ```
    
  
  - YAML文档片段引用 若values.yaml存在以下内容：
    ```
    values:
      example_name:
        peak_tps: 200000
    ```
    则在resources.yaml，可按照如下方式进行引用200000。
    ```
    $ref: 'values.yaml#/values/example_name/peak_tps'
    ```
    
  
  - 文本内容字符串引用
    ```
    $ref: 'db/schema.sql'    #引用的是schema.sql这个文本文件内容所构成的字符串
    ```
    
   
#### 带global的多文件描述结构
IaC Spec包通过不同规格目录来描述同一个服务在不同用途环境下所需的基础设施。但是，同一服务的不同的规格仍然存在大量相同的配置，需要一种机制来完成不同规格间配置的复用。因此，IaC支持放置一个global目录，其与specs目录同级，用于放置被所有规格目录所复用的配置文件。而各具体规格目录，只需包含与 global 目录的增量差异文件即可。
当某个规格被选用于部署时，会先将该规格目录下所有文件与global目录进行合并，得到该规格目录最终的所有配置文件，再进行部署动作。
合并策略：若文件的相对路径相同，则规格目录下的文件保留， global目录下的文件被覆盖，其他文件则共存。
带global的多文件描述结构样例如下：
```
├── package.json                           # 包描述文件（必须）
├── global                                 # global目录：放置所有规格目录所复用的配置文件
│     │
│     ├── meta.yaml                       # IaC 主体描述文件，内容不包含 components
│     ├── WiseEyeChaosMonkeyMgrService    # 组件一：ChaosMonkey 管理服务，名称需要为该服务下的微服务名称。
│     │    └── resources.yaml            # 组件一的资源列表
│     ├── WiseEyeChaosMonkeyPortal        # 组件二：ChaosMonkey 网页服务
│     │    └── resources.yaml            # 组件二的资源列表
│     ├── environment                     # 组件三：环境
│     │    └── resources.yaml            # 组件三的资源列表
│     └── functions                       # 组件四：函数
│           ├── resources.yaml            # 组件四的资源列表
│           └── values.yaml               # 组件四的values.yaml
│
└── specs                                  # 规格总目录（必须）
      ├── cn_dev_default                   # cn_dev_default 规格目录，一般可用于描述一个开发用途的服务环境所使用的基础设施  
      └── cn_product_default               # cn_product_default 规格目录，一般可用于描述一个生产用途的服务环境所使用的基础设施
            └── functions                  # 与global下functions目录的相对路径一致
                  └── values.yaml          # 用于覆盖global下functions目录的values.yaml
```
