728x90
반응형
SMALL
SMALL

 

Loop

Ansible Playbook을 작성할 때도 물론 Loop를 사용할 수 있다. 그리고 Ansible에서 기존 방식과 새롭게 생겨난 방식이 있는데 둘 다 알아보겠지만 앞으로 Deprecated되고 더 이상 사용하지 않게 될 가능성도 있으니 앞으로는 새롭게 생겨난 방식으로 코드를 작성해보자.

 

with_<lookup>

아직은 Deprecated 되지 않았지만 추천하지 않는 구 방식인 with_<lookup>을 살펴보자.

- name: Playbook
  hosts: ubuntu
  become: true
  tasks:
    - name: "Create groups"
      group:
        name: "{{ item }}"
        state: "present"
      with_items:
        - backend
        - frontend
        - devops

 

위 코드를 보면 group을 만들어내는 모듈을 사용한다. 여기서 총 세번의 그룹이 만들어진다. with_items라는 키워드로 만들어 낼 그룹 3가지를 위 코드처럼 작성하면 name: "{{ item }}"에서 저 하나하나를 item이 가리키게 된다. 그래서 총 3개의 그룹이 만들어진다. 

 

실행해보자. 

ansible-playbook -i inventory playbook.yaml

 

정상적으로 실행됐으면 Ubuntu 호스트에 들어가서 다음 명령어를 입력해보자.

cat /etc/group

이렇게 총 세개의 그룹이 만들어졌음을 확인할 수 있다. 이렇게 사용하는 방법을 with_<lookup> 이라고 한다.

 

loop

이제 Ansible 공식 문서에서도 이 방법을 추천한다. 그래서 앞으로는 이것만 사용하도록 한다. 

간단하게 loop 키워드에 반복할만큼 데이터를 채워넣으면 된다.

- name: Playbook
  hosts: ubuntu
  become: true
  tasks:
    - name: "Create users"
      user:
        name: "{{ item }}"
        comment: "ansible study"
        state: "present"
      loop:
        - john
        - alice
        - cloud
        - henry
        - jeremy
        - may

데이터를 채워넣고 유저를 생성하는 모듈을 사용해서 name: "{{ item }}"을 사용하면 loop에 채워넣은 데이터를 쭉 돌게 된다.

실행해보자. 다음과 같은 결과를 확인할 수 있다.

 

근데 저렇게 loop에 직접적으로 데이터를 채워넣는 방법도 있지만, 데이터를 변수로 받을 수도 있다. 다음이 그 예시이다.

- name: Playbook
  hosts: ubuntu
  become: true
  vars:
    users:
      - jan
      - ali
      - cow
      - hazard
      - june
  tasks:
    - name: "Create a users"
      user:
        name: "{{ item }}"
        comment: "loop vars"
        state: "present"
      loop: "{{ users }}"

이렇게 작성하고 실행해보자. 다음과 같은 결과를 확인할 수 있다.

 

이제 그냥 단순 문자열 말고 Key/Value 쌍으로 이루어진 값에 대해 반복문도 가능한데, 그럴 때 많이 사용되는 builtIn Function이 'dict2items'이다. 이건 Ansible에서 공식적으로 내장하고 있는 함수인데 다음과 같이 사용할 수 있다.

- name: Playbook
  hosts: ubuntu
  become: true
  vars:
    tags:
      Name: "Debug"
      Environment: "Test"
      Owner: "cwchoiit"
  tasks:
    - name: "Debug data"
      debug:
        msg: "{{ item.key }}: {{ item.value }}"
      loop: "{{ tags | dict2items }}"

 

변수에 tags라는 값으로 Key/Value 쌍의 데이터가 이렇게 있고 Task에 사용되는 loop로 "{{ tags | dict2items }}"라고 작성한 것을 볼 수 있다. 이 구조는 {{ exp | func }}인데, exp의 값을 func 인자로 넘겨주는 표현식이다. 그래서 인자로 넘겨받으면 item이라는 객체에 key와 value에 데이터로 들어가게 된다. 그래서 위 Playbook을 실행해보면 다음과 같은 결과를 얻는다.

Ubuntu 그룹에 호스트가 2개가 있으니까 그리고 alias로 ubuntu1, ubuntu2로 선언했기 때문에 Key/Value 한 쌍이 각각의 호스트에서 한번씩 실행되는것을 알 수 있고 msg값으로 tags에 정의한 "Key: Value"로 표현됨을 알 수 있다. 

 

그리고 이렇게 사용하는 방법을 살짝만 응용하면 다음과 같이도 작성할 수 있다. 

- name: Playbook
  hosts: ubuntu
  become: true
  vars:
    users:
      - name: jan
        shell: /bin/bash
      - name: ali
        shell: /bin/sh
      - name: cow
        shell: /bin/bash
      - name: hazard
        shell: /bin/sh
      - name: june
        shell: /bin/bash
  tasks:
    - name: "Create a user"
      user:
        name: "{{ item.name }}"
        shell: "{{ item.shell }}"
        comment: "cwchoiit-ansible"
        state: "present"
      loop: "{{ users }}"

그리고 이를 실행해보면 다음과 같은 결과를 얻는다.

 

이런 여러 방법을 통해 반복문을 만들어 낼 수 있고 이 외에 문서를 참고하면 더 많은 유스케이스가 있으니 문서를 잘 참조하면 좋을 것 같다.

 

Loops — Ansible Community Documentation

Ansible Community Documentation Ansible Loops Ansible offers the loop, with_ , and until keywords to execute a task multiple times. Examples of commonly-used loops include changing ownership on several files and/or directories with the file module, creatin

docs.ansible.com

 

728x90
반응형
LIST

'IaC(Infrastructure as Code)' 카테고리의 다른 글

Ansible Part. 7 (Condition)  (0) 2024.03.18
Ansible Part. 5 (Variables)  (0) 2024.03.18
Ansible Part. 4 (Handler)  (0) 2024.03.18
Ansible Part. 3 (Playbook)  (0) 2024.03.18
Ansible Part. 2 (Adhoc)  (3) 2024.03.17
728x90
반응형
SMALL
SMALL

이번엔 루프를 이용해보자. 다음 main.tf 파일을 보자.

provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_iam_group" "developer" {
  name = "developer"
}

resource "aws_iam_group" "employee" {
  name = "employee"
}

output "groups" {
  value = [
    aws_iam_group.developer,
    aws_iam_group.employee
  ]
}

variable "users" {
    type = list(any)
}

resource "aws_iam_user" "this" {
  for_each = {
    for user in var.users : user.name => user
  }

  name = each.key

  tags = {
    level = each.value.level
    role = each.value.role
  }
}

resource "aws_iam_user_group_membership" "this" {
  for_each = {
    for user in var.users : user.name => user
  }

  user = each.key

  groups = each.value.is_developer ? [
    aws_iam_group.developer.name, aws_iam_group.employee.name
    ] : [
        aws_iam_group.employee.name
    ]
}

locals {
  developers = [
    for user in var.users : user if user.is_developer
  ]
}

resource "aws_iam_user_policy_attachment" "developer" {
  for_each = {
    for user in local.developers : user.name => user
  }

  user = each.key
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"

  depends_on = [ aws_iam_user.this ] # 이 리소스가 생성되어야만 가능하게 설정
}

output "developers" {
  value = local.developers
}

output "high_level_users" {
  value = [
    for user in var.users : user if user.level > 5
  ]
}

 

그리고 변수를 정의한 파일인 terraform.tfvars 파일은 다음과 같다.

users = [
 {
    name = "john"
    level = 7
    role = "재무"
    is_developer = false
 },
 {
    name = "alice"
    level = 1
    role = "인턴 개발자"
    is_developer = true
 },
 {
    name = "tony"
    level = 4
    role = "데브옵스"
    is_developer = true
 },
 {
    name = "cindy"
    level = 9
    role = "경영"
    is_developer = false
 },
 {
    name = "hoon"
    level = 3
    role = "마케팅"
    is_developer = false
 }   
]

 

이런식으로 for 문을 사용할 수 있다.

resource "aws_iam_user" "this" {
  for_each = {
    for user in var.users : user.name => user
  }

  name = each.key

  tags = {
    level = each.value.level
    role = each.value.role
  }
}

 

코드를 보면 이러한 구문이 있다.

for user in var.users : user.name => user

 

선언한 users 라는 변수에 담긴 각각의 유저 하나씩 루프를 돌리는데 이걸 담는 형태가 Map 형식이기 때문에 Key/Value를 다음과 같이 선언하는 것.

user.name => user

 

Map이 아닌 배열로 담는 경우 다음과 같이 사용한다.

locals {
  developers = [
    for user in var.users : user if user.is_developer
  ]
}

 

다만, 이 배열에 담을 땐 조건이 따른다. 그래서 if가 있다. 조건 없이 모두 넣으려고 한다면 이렇게 사용하면 된다.

locals {
  developers = [
    for user in var.users : user
  ]
}

 

그리고 위 main.tf 파일에서 한 가지 새로운 개념인 depends_on 이 있다.

resource "aws_iam_user_policy_attachment" "developer" {
  for_each = {
    for user in local.developers : user.name => user
  }

  user = each.key
  policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"

  depends_on = [ aws_iam_user.this ] # 이 리소스가 생성되어야만 가능하게 설정
}

 

이 depends_on이 있는 리소스는 depends_on에 걸려있는 리소스가 생성되어야만 만들어지는 리소스임을 의미한다.

728x90
반응형
LIST

'IaC(Infrastructure as Code)' 카테고리의 다른 글

Terraform Commands (taint / untaint)  (0) 2024.03.08
Terraform State  (0) 2024.03.07
AWS + Terraform (Conditions)  (0) 2024.03.07
AWS + Terraform (For-Each)  (0) 2024.03.06
AWS + Terraform (Module)  (0) 2024.03.06

+ Recent posts