2017년 12월 17일 일요일

[Ansible] 귀중품 보관실 서비스 (vault/볼트)

- 0 개의 댓글


볼트(vault)는 에니메이션 볼트(Bolt)랑은 다른 단어입니다. ;;;;

사전을 좀 찾아보니 vault라는건...

   - 둥근 지붕, 둥근 천장(모양의 것), 둥근 천장이 있는 장소(복도), 푸른 하늘(the vault of        heaven), 지하(저장)실, (은행 등의)귀중품 보관실, 지하 납골소

그 중에서 귀중품 보관실? 이게 가장 적절한 쓰임의 말이겠네요 :)

그러면 어떤 것들을 귀중품 보관실에 보관하게 될까요


주로 이런 보석이나, 소중한 것들이겠죠?

운영쪽으로 본다면...제일 중요한 것들은 접속 정보 / 아이디 / 암호 같은 것들이겠네요 :)

잘못 해서 이런 정보들이 유출되거나 잘못되면....

이런 곳에 전화하거나..사실 그러기 전에 직장을 잃어버리게 되겠죠 -_-

그렇다고 매번 접속 정보들이나, 필요한 내용들을 다 하나하나 기입하면서 구성 관리하자니....왠지 자동화 툴을 제대로 못 쓰는거 같고...-_-

그래서 절충안으로 쓸수 있는게 ansible-vault 입니다.
그나마 금고에 넣어두면 누군가가 손댈수 없겠죠.



이 금고의 철판의 종류는 AES-256 입니다. 튼튼한 놈이죠 -_-

자 그러면 어떻게 쓸까요? 한번 예시를 볼까요?

[ nginx_remove.yml ]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
---
- name: Remove nginx on the nodes
  hosts: nodes
  become: yes

  tasks:
  - name: nginx for Ubuntu
    include_tasks: Ubuntu_nginx_remove.yml
    when: ansible_distribution == 'Ubuntu'

  - name: nginx for CentOS
    include_tasks: CentOS_nginx_remove.yml
    when: ansible_distribution == 'CentOS'

  - debug: var=Step_grpVars

nginx_remove.yml을 사용하면, 이미 기존에 사용한 것처럼 노드들에 nginx를 삭제할 수 있습니다. 계속 삭제해도 큰 문제가 없으니...이걸 사용하기로 하고요.

여기서 ~!!
일반적으로 'anp nginx_remove.yml -k' 를 사용해서 ssh password를 입력하게 되는데요

이 귀찮음~~ 귀찮음 ssh password (vagrant)를 매번 매번 매번 입력해야 하는 귀찮음을 벗어나게 위해서 해당 값을 파일로 입력해 둡니다.

해당 값은 여러 곳에 아주 많이 자유롭게 넣을수 있지만요
ssh password를 암호화 할 예정이니까, 독립적으로 만들어 둡니다.

따라서 sudo vi '/etc/ansible/group_vars/' 밑에 all이라는 파일을 만들어 아래와 같이 기록해 둡니다.

[ group_vars/all ]
1
2
3
4
---
# file: group_vars/all
ansible_ssh_pass: vagrant
Step_grpVars: "group_vars_passed"


그리고 나서 해당 파일을 암호화 시킵니다.

잠깐~!!!

암호화 시키기 전에 해야 할게 있습니다. ansible-vault는 작업마다 vault의 암호를 요청합니다. 그러니까 말이죠...ssh pass 입력하기 귀찮다고 vault pass를 입력해야하는 꼴이 되는거죠


   (오랜만에 보는 혹부리 영감이네요 ...)

그래서 vault pass도 파일로 입력을 받겠습니다.

이러기 위해서는 vault pass를 생성하고 pass 자체가 알려지면 안되니까 해당 파일도 암호화해야 하며, vault pass가 어디 있는지 알려줘야 합니다.

우선

ansible-vault create .passfile 

passfile을 만들고 편의를 위해서 환경 설정들이 있는 곳에 옮겨줍니다.
(친구들과 함께 있으라구요 )
  (함께 있을때는...아 이분들 일반인이라..차마 -_-; 뻘소리 못하겠네요..)


만들때 그리고 내부에는 모두 '1234' 라는 내용을 기입해 줍니다.
우리 모두 알수는 없지만 1234입니다 -_-













그리고, valut pass의 위치 변경은 /etc/ansible/ansible.cfg 에서

  # If set, configures the path to the Vault password file as an alternative to
  # specifying --vault-password-file on the command line.
  #vault_password_file = /path/to/vault_password_file
  vault_password_file = /etc/ansible/.passfile

마지막에 있는 것처럼 .passfile이 valut 암호 파일이라고 알려줍니다.


자 이제 vault pass에 대한 설정이 다 되었으니...
해당 설정 값으로 group_vars에 있는 all을 암호화할 차례입니다.




암호화가 끝나고 나면, vagrant로 바로 실행하게 하기 위해서 유저와 그룹 권한을 변경해 줍니다.

이거 전에 변경하면 다 처음부터 해야 합니다. -_-; 한마디로 망합니다.

왜냐하면 순수하게 '1234'는 같다고 해도 AES256에 방식에 따라 다르게 기입하기 때문입니다.

자세하게 알고 싶다면 이걸 클릭..

암호화 된 것은 보고 실행할까요?



이제 실행~!!






[ 참고사항 ]
.passfile은 순환구조로 읽어서 암호화를 했기 때문에 ansible-vault로는 볼수가 없습니다. 정확하게는 ansible.cfg를 수정하고 나서 봐야 하고요


그리고 all 파일의 경우에는 ansible-vault edit 또는 view 등으로 볼수가 있으므로, 추가적으로 암호화 하거나, 유저 권한으로 제한하는게 옳다고 보여지네요.


이렇게 되면 일반 유저는 어쨌든 전혀 볼수가 없을테니까요 :)
그리고 핵심은 유출시에 plain_text가 아니기 때문에 해당 파일을 볼수가 없다는 장점이 있는것이죠. 

또한 윈도우와 같이 다른 환경 설정이 필요한 것이라든가...또는 네트워크 장치등에 대한 정보들을 모두 한번에 group_vars 또는 host_vars 외에 role의 vars로 관리하는 것도 생각해 볼만 하네요. :) 
[Continue reading...]

2017년 12월 12일 화요일

[Ansible] 은하계(galaxy)와 앤서블의 관계는?

- 0 개의 댓글
은하계라고 하니까 거창한데요
지금까지 배운 것들이 모여 있는 공간 그것을 앤서블에서는 은하계 즉, 갤럭시라고 부릅니다.

원래 은하계도 이와 같이 엄청 많은 별들과 암흑물질 , 그 사이에 성간 물질이라고 불리는 애들 등 여러가지들이 모여 있죠

Image result for 은하계 구성

그런 것처럼, 앤서블에서는 이런 애들이 모아 놓은 공간을 갤럭시라고 부르고, 실제적으로 바로 쓸수 있는 것들을 공유 할수 있도록 해줍니다. 그게 어떤 거냐구요?

롤롤롤 이죠 .

이제 알겠죠 왜 템플릿을 하고 롤을 배우고 했는지...다 미래를 내다 보는....ㅎㅎㅎㅎ -_-;

Related image
(이러진 마세요오;;;;)

여튼 각설하고 이걸 어떻게 사용할까요?
이미 앤서블을 설치했다면 이미 모든 것은 아니...정확하게는 거의 다 준비되어 있습니다.

무슨 말이냐면 말이죠
명령어는 ansible-galaxy라는 명령어고 해당 명령어를 치면 아래와 같이 사용법이 주루룩 나오게 되는거죠




하지만 그런데, 여기서 바로 명령어를 친다면 아래와 같은 에러를 만나게 됩니다.


왜냐...앤서블 갤럭시는 아직까지는 read-only라는 개념보다는 계정 자체를 (단독 계정 또는 github계정 , 그 외에도 다른 계정 가능) 권한을 주고 다운로드도 하고 올리고 하는 것을 추구하기 때문입니다. 이건 제 생각에는 수정이 필요하지 않을까? 싶기도 하네요 
다운만 하고 싶은 사람도 로그인을 해야 한다니~ 이건 좀.....틀리면 얘기해주세용 :)

추가(2017-12-13) : 직접 git에서 다운 받는 옵션이 있는데, 테스트가 필요하지만 이건 될 겁니다 정말 그냥 다운로드 하는거라서요 :) 

여튼 그래서 로그인을 하고 나면 이제 사용할 준비가 된겁니다. 



아래와 같이 최소한 에러는 안 나오게 되는 거죠~!



이런 다음에 nginx에 대한 패키지인 (구글에 검색하면 제일 상단에 나오는) geerlingguy.nginx 를 설치할 겁니다.



이거 이름이 이상해 보일수가 있는데 왜 이런식으로 구조화 되어 있냐면...
생각해 봅시다. sysnet4admin 이라는 사람도 nginx 롤을 만들어서 공유하고 master라는 사람도 nginx를 올려서 공유한다면 이 두 사람을 구분해야 겠죠?

왜냐면 여긴 자유롭게 롤을 공유하는 공간이니까요 그래서 사용자 이름이 꼭 앞에 붙습니다 :)

geerlingguy가 사용자 이름이 되는 거죠.

사용법은 놀랄만큼 간단합니다.

Image result for 놀람 짤
(이러지 마시구요;;;)

그냥 실행하면 그동안 실행했던거와 달리 에러가 납니다.
왜 일까요오?



힌트만 드리겠습니다~~(아마 다 아실 -_-;;)
/etc/ansible/roles는 permission이 제한이 있습니다 ~!

여튼 그래서 sudo를 붙이고 다시 실행합니다. 아니면 루트 계정으로? 해도 되고요


쓰는 사이에 벌써~ 끝났습니다. 아주 쉽게 성공했네요.

그럼 이게 끝일까요?
아니죠..이건 그냥 롤만 다운로드 및 압축 해제된거고...(엄밀히 따지자면..)



이제 이걸로 노드들에 설치를 하는 단계가 필요합니다.
어려울까요~~?
아니죠 기존에 썼던거에 롤 이름만 바꿔주면 됩니다. 아주아주 간단하게요

[ geerlingguy.nginx.yml ]

1
2
3
4
5
6
7
---
- name: Install nginx on the nodes by geer
  hosts: nodes
  become: yes

  roles:
    - role: geerlingguy.nginx


결과를 볼까요?



엄청 쉽지 않나요? 한번 실습해 보시면 정말 깜놀 하실거니다.
그렇다면, 그간 고생한게 아까우신가요? 아닙니다 그동안 고생을 했으니 이게 쉬운겁니다 :)
그러니 좀더 재미난 것을 더 같이 해봅시다~!
이번엔 여기까지 빠잉 :)


[Continue reading...]

2017년 12월 6일 수요일

[Ansible] 그럼 롤(Role)은 어떻게 쓰나요?

- 0 개의 댓글
지난번 글에서는 롤의 구성을 알아봤다면~!
실제로 어떻게 쓸수 있는지 알아봐야 겠죠?

모든 디렉터리를 다 사용할 건 아니지만
디렉터리를 우선 생성해야 합니다 :)
sudo mkdir -p /etc/ansible/roles/nginx
cd /etc/ansible/roles/nginx/
sudo mkdir tasks handlers defaults vars files templates meta



해당 내용을 다 만들었으면, 이제 각각의 디렉터리에 들어갈 yml파일을 만들어 보죠
룰 #1
main.yml입니다.
음...이상하게 들리시겠지만?

각각의 디렉터리 밑에 main.yml이라고 되어 있어야 읽어들입니다 :)
하하하;; (저는 범인이 아니에요~~)

잘못 없음 짤에 대한 이미지 검색결과

어쨌거나~~! 최근에 작업했던 코드를 사용해 어떻게 롤로 변형되는지 알아보겠습니당.

[ nginx_if_main.yml ]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
---
- name: Install nginx on the nodes
  hosts: nodes
  become: yes
  vars:
    lnx_name: "{{ 'Ubuntu' if ansible_distribution == 'Ubuntu' else 'CentOS' if ansible_distribution == 'CentOS' else 'Just Linux' }}"

  tasks:
  - name: nginx for Any Linux
    include_tasks: "{{ lnx_name }}.yml"


[ CentOS.yml ] 
1
2
3
4
5
6
7
8
- name: install epel-release
  action : "{{ ansible_pkg_mgr }} name=epel-release state=latest"
- name: install nginx web server
  action : "{{ ansible_pkg_mgr }} name=nginx state=present"
- name: Upload default index.html for web server
  get_url: url=https://www.nginx.com dest=/usr/share/nginx/html/ mode=0644
- name: Start nginx web server
  service: name=nginx state=started
[ Ubuntu.yml ] 
1
2
3
4
- name: install nginx web server
  action : "{{ ansible_pkg_mgr }} name=nginx state=present"
- name: Upload default index.html for web server
  get_url: url=https://www.nginx.com dest=/usr/share/nginx/html/ mode=0644 validate_certs=no
======
최종 결과 구조는 이렇게 됩니다. 
{ tasks }
우선 가장 먼저 tasks 부분을 만들어 보겠습니다.
[ main.yml ]
1
2
3
---
- name: nginx for Any Linux
  include: "/etc/ansible/roles/nginx/tasks/{{ lnx_name }}.yml"

[ CentOS.yml ]
1
2
3
4
5
6
7
8
- name: install epel-release
  action : "{{ ansible_pkg_mgr }} name=epel-release state=latest"
- name: install nginx web server
  action : "{{ ansible_pkg_mgr }} name=nginx state=present"
- name: Upload default index.html for web server
  get_url: url=https://www.nginx.com dest=/usr/share/nginx/html/ mode=0644
  notify:
    - Start nginx web server

[ Ubuntu.yml ] 
1
2
3
4
- name: install nginx web server
  action : "{{ ansible_pkg_mgr }} name=nginx state=present"
- name: Upload default index.html for web server
  get_url: url=https://www.nginx.com dest=/usr/share/nginx/html/ mode=0644 validate_certs=no
여기서 중요한 건 include_tasks가 role에서는 인지가 안됩니다 -_-
그래서 include로 바꾸어주고, role의 경우는 실행위치를(현재는 = /home/vagrant)
기본으로 인지하니...절대 경로로 바꿔 줬습니다.
그리고 서비스 재 시작 같은거는 핸들러로 빼줬습니다. :) 멋있으라구 
{ handlers }
'Start nginx web server' 라는 notify를 받아서 동작하는 핸들러를 만들 차례입니다. 

[ main.yml ]
1
2
3
---
- name: Start nginx web server
  service: name=nginx state=started


{ defaults }
이번에는 패스~ 합니다. 
{ vars }
우리가 플레이북을 짤때 넣었던 그 vars이 이 vars입니다.
똑같아요 다만 이건 우선 순위가 defaults에서도 등록한 변수보다 높습니다. 즉 덮어쓰기가 된다는거죠 :)
근데 한가지 문제가....jinja2 문법에 따라 조건이 들어가면 해석이 늦습니다.
그래서 해당 vars는 쓰지 못하고...role을 호출할때 조건으로 뺐습니다 ㅠㅠ 흑...
눈물 짤에 대한 이미지 검색결과
{ files }
역시 특별히 할일이 없네요 :) 패스 
{ templates }
이번 예제는 템플릿이 없어서 패스~
{ meta }
의존성이 없어서 역시 패스~!
꼴랑 4개 만들고 ~~ 롤이라고 하기에는 부족함이 있지만...
어쨌든 호출해 볼까요~?
{ role을 부르는 코드 }

1
2
3
4
5
6
7
---
- name: Install nginx on the nodes
  hosts: nodes
  become: yes

  roles:
    - { role: nginx, lnx_name: "{{ 'Ubuntu' if ansible_distribution == 'Ubuntu' else 'CentOS' if ansible_distribution == 'CentOS' else 'Just Linux' }}" }
lnx_name을 vars로 빼고 싶었지만...빼지 못함 아쉬움이 있네요
role을 하나 더 만들고 child로 뺄까도 고민했지만...그건 다음 기회가 있다면 -_-
role을 호출하고 변수만 정할수 있도록 옆에 도우미 줄이 있는게 확인이 되네요 그럼 결과는~?
잘 돌아가는게 확인이 되네요~ :)
role을 잘만 이용하면, 메인 코드가 아주 많이 간결해 질수 있답니다.

[Continue reading...]

[Ansible] 롤롤롤 (LoL 아님 / Role임) 그대는 누구시길래~!

- 0 개의 댓글
오랜만에 글을 씁니다~!
1주일에 2개씩 올려야 하는건데...그동안 콜록콜록 아파서....

환자 짤에 대한 이미지 검색결과
(빈칸에 뻥치시네 라고 보이는건 착시입니다  -_-)

여하튼....이번시간에는 롤(Role)이라는 것을 알아 볼 겁니다.
근데 롤은 어디다가 쓰는 걸까요?

사실 꼭 필요한 기능은 아닙니다.
롤이 없어도 머....사용하는데 아~~~무~~~~런 지장이 없습니다.
다만...그런거 있잖나요 include_tasks하는 마냥 코드가 멋있게 이쁘고 산뜻하게
규칙이 딱딱 맞는 느낌인거?

그리고 사용자가 이런거 하나하나 고려하지 않고 그냥 쓰고 싶은거죠
제가 가장 자주 쓰는 nginx 세팅하는걸 내가 하나하나 구성하고 싶지 않다는거죠
게으름을 창조력을 만드는 법이죠 :)

게으름 짤에 대한 이미지 검색결과


이해를 돕기 위해 한가지 예를 들어볼께요.
Linux 명령어 중에 Copy라는 명령어가 있습니다.
이게 복잡하게 시스템에서 이루어지는 작업은 아래처럼 정신 사납게 되어 있답니다.
그런데 우리가 이걸 꼭 알아야 할까요? 그냥 복사하고 싶은건데 말이죠~!

copy 호출 프로세스에 대한 이미지 검색결과

그런 것처럼, Role에서 nginx라는걸 호출만 하면 원하는 작업이~! 이루어지는 그런 방식인거죠 :)

그러기 위해서 Role은 이런 것들을 정의해 놨어요
이걸 다 정의해야만 동작하는게 아니라 필요한 것만 정의를 해 놓으면 그에 맞게 불러와서 동작한답니다

우리 친절한 공홈이 아래와 같이 설명해 놨지만...

  • tasks - contains the main list of tasks to be executed by the role.
  • handlers - contains handlers, which may be used by this role or even anywhere outside this role.
  • defaults - default variables for the role (see Variables for more information).
  • vars - other variables for the role (see Variables for more information).
  • files - contains files which can be deployed via this role.
  • templates - contains templates which can be deployed via this role.
  • meta - defines some meta data for this role. See below for more details.
이걸 보면 멀하는지 알수 없으니 우선 설명부터~!

[ tasks ]
그동안 우리가 썼던 그~그~ tasks입니다.
똑같아요
있다가 예제를 보시면 더 쉽게 아실수 있을꺼에요~!

[ handlers ]
아주 먼 옛날에 잠깐 썼었죠 handlers를~!
이건 tasks와 같은 것이 성공! 하면 변경! 등에 대한 트리거를 받아서 행동하게 짤때 씁니다.

[ defaults ]
이건 일반적으로 변수와 같은 것들을 기본!!으로 등록하는 곳인데요.
우선순위가 아~~주 낮은 변수 그러니까 정말 기본을 등록하고 다른 vars와 같은 곳에서 사용하고 업데이트 한답니다.

[ vars ]
우리가 플레이북을 짤때 넣었던 그 vars이 이 vars입니다.
똑같아요 다만 이건 우선 순위가 defaults에서도 등록한 변수보다 높습니다. 즉 덮어쓰기가 된다는거죠 :)

[ files ]
파일 즉 파일 자체를 추가할때 주로 쓰입니다~
가장 유명한 모듈은 copy 가 있겠네요.
이쯤 오면 왠지 감이 오시죠..그냥 목적에 맞게 나누어 놓은것?
안 필요하면 안 써도 됩니다~~그냥 디렉터리를 지워버리면 되요

[ templates ]
가장 최근 다룬 그 템플릿 jinja2의 양식을 따르는 그 템플릿 입니다

[ meta ]
meta라는건 약간 생소하실텐데 현재의 파일들에 대한 정보를 담고 있는 데이터를 말하며,
실제적으로는 dependencies 그러니까 이거 하기 전에 우선적으로 선행되어야 하는 작업(즉 role)을 지정합니다.
메타데이터 참고 : https://ko.wikipedia.org/wiki/메타데이터

고로 정리하자면, 이거 안해도 되는데, 왠지 구조가 멋있고, 재 사용이 잘될 것 같고.

그래서 쓰이는 겁니다 :)
다음 글에서 예제를 통해서 살펴보겠습니다~!
[Continue reading...]

2017년 11월 23일 목요일

[Ansible] Template의 용도는? (2/2)

- 0 개의 댓글


아~ 아~ 저번에 Template이 아무래도 너무 부족한게 많았던거 같아요

그래서 본질적으로 돌아가서 cfg를 생성하는걸 할까? 하다가..
그건...아무래도 적절한 예시가 없어서 두개를 해 보려고 합니다.

이 예제를 통하면 Template의 사용법이 이제는 이해가 되실꺼에요

1) yml을 template으로 만들기

이상하게 들리시겠지만, template의 output은 어떤 것이라도 만들수 있어요.
물론...binary는...안된다는게 함정이지만 -_-
그래서 yml은 어떻게 보면 plain text이기 때문에 확장자를 지정해 주고 만들수 있답니다.

예시를 볼까요?

여기서 만들었던 동적으로 변수를 할당해 보아요~ 라는 yml파일을 template를 통해서 생성해 보겠습니다.

[ nginx_template.yml ]
1
2
3
4
5
6
7
8
---
- name: Create yml by template
  hosts: localhost

  tasks:
  - template:
      src: which_lnx.j2
      dest: /home/vagrant/template/which_lnx.yml

[ which_lnx.j2 ]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#Create by Template at {{ ansible_date_time.date }}
---
- name: Install nginx on the nodes
  hosts: nodes
  become: yes
  vars:
    lnx_name: "{{ "{{'Ubuntu' if ansible_distribution == 'Ubuntu' else 'CentOS' if ansible_distribution == 'CentOS' else 'Just Linux'"}} }}"

  tasks:
  - name: nginx for Any Linux
    include_tasks: "{{ '{{ lnx_name }}' }}.yml"


어떻게 결과가 나올까요~?


해당 내용을 보면 이전 작성한 내용과 동일하게 작성되는 것을 볼 수 있습니다.


template을 이렇게도 쓸수 있구나~? 정도로 보시고 다음껄 볼까요?


2) 두번째는 hosts 파일을 생성
 - template을 통해서 /etc/hosts 파일을 생성해 주는 예제~ 예제입니다~!

[ hosts_template.yml ]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
---
- name: Create hosts file by template
  hosts: localhost
  become: yes

  vars:
    Node_Number: 8

  tasks:
  - template:
      src: hosts.j2
      dest: /etc/hosts

[ hosts.j2 ]
1
2
3
4
5
6
7
#Create by Template at {{  ansible_date_time.iso8601 }}

127.0.0.1 {{ ansible_hostname }}
192.168.1.10 ansible-server
{% for ip in range(Node_Number) %}
192.168.1.{{ip+101}} ansible-node0{{ip+1}}
{% endfor %}


길지 않은 줄로 어떤 결과가 나오는지 볼까요?


짜잔~~! for loop를 사용해서 해당 내용을 자동으로 생성해 준 것입니다.
template을 사용하면 장점이 짧은 줄로...결국 프로그래밍...이라고 생각해야 겠지만...여하튼 간단하게 여러가지의 내용들을 기입할 수가 있습니다. 그리구 중요한 것은 변수들이 Pre-defined 되어 있으니 그걸 이용하기도 좋죠 :)



여기서 끝일까요~?


로컬에 /etc/hosts에만 생성하면 무슨 의미가 있겠습니까~
전체 노드 (i.e. HPC나 web server farms이나..여러가지 목적으로~?) 배포를 해야 겠죠 
한줄만 수정합니다. 

host : nodes 로요~!
그러면 nodes에 해당 내용을 배포하고 적용해 버립니다 :) 

한번 볼까요~?



확인 확인~!!! 노드 01번에 접속해서 확인하니 잘 되네요 !!!



jinja2 template을 사용하면, 재사용성도 높이고, plain text 가공도 쉬워지고, 메인 코드를 줄일수 있고. 활용하기 나름이랍니다 :)


뿌잉뿌잉 :)  빠잉 입니다~!


[Continue reading...]
 
Copyright © . 엔지니어를 위한 파이썬 및 기술 블로그 - Posts · Comments
Theme Template by BTDesigner · Powered by Blogger