Merge pull request #60 from tendermint/feature/jenkins

Feature/jenkins
This commit is contained in:
Anton Kaliaev
2017-10-09 17:39:05 +04:00
committed by GitHub
64 changed files with 1526 additions and 245 deletions

View File

@@ -9,5 +9,8 @@
"amount": 9007199254740992
}
]
}]
}],
"plugin_options": [
"coin/issuer", {"app": "sigs", "addr": "1B1BE55F969F54064628A63B9559E7C21C925165"}
]

View File

@@ -13,6 +13,24 @@
}
]
},
{
"name": "greg",
"address": "B01C264BFE9CBD45458256E613A6F07061A3A6B6",
"pub_key": {
"type": "ed25519",
"data": "E1FFBD187FA2A922CE1B367532CEAC1AD8E606D576AB0D2E2CAA7EC6B7DAC10F"
},
"coins": [
{
"denom": "buckyball",
"amount": 9007199254740991
},
{
"denom": "gregcoin",
"amount": 1000
}
]
},
{
"name": "anton",
"address": "40CC622438D3E42148A1FFD3A27C07C100F8FA3D",
@@ -22,30 +40,26 @@
},
"coins": [
{
"denom": "anton",
"denom": "buckyball",
"amount": 9007199254740992
},
{
"denom": "tank",
"amount": 99
"denom": "antoncoin",
"amount": 1000
}
]
},
{
"name": "adrian",
"address": "98F28277FA8C512968BBDE443F5DB27AC743F814",
"pub_key": {
"type": "ed25519",
"data": "2E7EAB9E4C93D3657A63E063D6ABB851596BA97ED9F4EB9A2FC714043DC9685D"
},
"address": "0FA1DB09E8B174E81E94280C047C158D4271457B",
"coins": [
{
"denom": "axi",
"denom": "buckyball",
"amount": 1928936473812
},
{
"denom": "bear",
"amount": 42
"denom": "adriancoin",
"amount": 1000
}
]
},
@@ -62,16 +76,8 @@
"amount": 20000000000
},
{
"denom": "bumblebee",
"amount": 100
},
{
"denom": "french",
"amount": 10
},
{
"denom": "frey",
"amount": 4838271727204
"denom": "buckycoin",
"amount": 1000
}
]
},
@@ -84,34 +90,12 @@
},
"coins": [
{
"denom": "radio",
"amount": 50
},
{
"denom": "tv",
"amount": 3478765434568
}
]
},
{
"name": "gregkey",
"address": "B01C264BFE9CBD45458256E613A6F07061A3A6B6",
"pubkey": {
"type": "ed25519",
"data": "E1FFBD187FA2A922CE1B367532CEAC1AD8E606D576AB0D2E2CAA7EC6B7DAC10F"
},
"coins": [
{
"denom": "mycoin",
"amount": 3478765434568
"denom": "rigelcoin",
"amount": 1000
},
{
"denom": "buckyball",
"amount": 8367251830291
},
{
"denom": "playmoney",
"amount": 9999999999999
"amount": 3478765434568
}
]
},
@@ -124,13 +108,87 @@
},
"coins": [
{
"denom": "shadow",
"denom": "buckyball",
"amount": 53712836452781
},
{
"denom": "unit",
"amount": 1
"denom": "shadowcoin",
"amount": 1000
}
]
},
{
"name": "peng",
"address": "7B8422A210D0F0B8734908C093ECF0E9A768BDB8",
"coins": [
{
"denom": "buckyball",
"amount": 53712836452781
},
{
"denom": "pengcoin",
"amount": 1000
}
]
},
{
"name": "matt",
"address": "C2104A8191E282AA45D210BA93282B36768EDDA1",
"coins": [
{
"denom": "buckyball",
"amount": 53712836452781
},
{
"denom": "mattcoin",
"amount": 1000
}
]
},
{
"name": "frey",
"address": "0F8FB94B5A4D04220F15058B7AA16AF1328B57A9",
"coins": [
{
"denom": "buckyball",
"amount": 53712836452781
},
{
"denom": "freycoin",
"amount": 1000
}
]
},
{
"name": "wancloud",
"address": "117FE408E1F74C453901BCB638F996964FD29CBB",
"coins": [
{
"denom": "buckyball",
"amount": 53712836452781
},
{
"denom": "wancloudcoin",
"amount": 1000
}
]
},
{
"name": "bianjie",
"address": "F63F2D34C03430A54B7F6A43C886B4A83F366B84",
"coins": [
{
"denom": "buckyball",
"amount": 53712836452781
},
{
"denom": "bianjiecoin",
"amount": 1000
}
]
}
],
"plugin_options": [
"coin/issuer", {"app": "sigs", "addr": "B01C264BFE9CBD45458256E613A6F07061A3A6B6"}
]

View File

@@ -13,4 +13,8 @@
}
]
}
],
"plugin_options": [
"coin/issuer", {"app": "sigs", "addr": "1B1BE55F969F54064628A63B9559E7C21C925165"}
]

View File

@@ -0,0 +1,8 @@
---
#variable "service" is required
- hosts: "{{ lookup('env','TF_VAR_TESTNET_NAME') }}:tag_Environment_{{ lookup('env','TF_VAR_TESTNET_NAME') | regex_replace('-','_') }}"
roles:
- getconfigtoml

8
ansible/getfile.yml Normal file
View File

@@ -0,0 +1,8 @@
---
#variable "source" is required
- hosts: "{{ lookup('env','TF_VAR_TESTNET_NAME') }}:tag_Environment_{{ lookup('env','TF_VAR_TESTNET_NAME') | regex_replace('-','_') }}"
roles:
- getfile

View File

@@ -7,6 +7,6 @@
roles:
- install
- {role: generic-service, when: service == 'tendermint'}
- {role: config, testnet_name: "{{lookup('env','TF_VAR_TESTNET_NAME')}}"}
- {role: config, testnet_name: "{{lookup('env','TF_VAR_TESTNET_NAME')}}", tags: reconfig }
- start

8
ansible/jsonconfig.yml Normal file
View File

@@ -0,0 +1,8 @@
---
#variable "service" is required
- hosts: "{{ lookup('env','TF_VAR_TESTNET_NAME') }}:tag_Environment_{{ lookup('env','TF_VAR_TESTNET_NAME') | regex_replace('-','_') }}"
roles:
- jsonconfig

View File

@@ -1,7 +1,6 @@
---
#tendermint_genesis_file: "<undefined>"
#service_genesis_file: "<undefined>"
app_options_file: "app_options_files/dev_money"
#genesis_file: "<undefined>"
app_options_file: "app_options_files/public_testnet"
seeds: ""
testnet_name: testnet1
validators: true

View File

@@ -2,64 +2,56 @@
- name: gather tendermint public keys
when: (validators == true or validators == 'true') and tendermint_genesis_file is not defined
command: "/usr/bin/tendermint show_validator --home /etc/{{service}}/tendermint --log_level error"
tags: reconfig-toml,reconfig-genesis
command: "/usr/bin/tendermint show_validator --home /etc/{{service}} --log_level error"
register: pubkeys
changed_when: false
- name: resetting permissions from root after gathering public keys
file: "path=/etc/{{service}}/tendermint owner={{service}} group={{service}} recurse=yes"
tags: reconfig-toml,reconfig-genesis
file: "path=/etc/{{service}} owner={{service}} group={{service}} recurse=yes"
- name: register tendermint public keys as host facts
when: (validators == true or validators == 'true') and tendermint_genesis_file is not defined
tags: reconfig-toml,reconfig-genesis
set_fact: "pubkey='{{pubkeys.stdout}}'"
connection: local
- name: copy generated tendermint genesis.json - genesis_time will be updated
when: (validators == true or validators == 'true') and tendermint_genesis_file is not defined
- name: copy generated genesis.json - genesis_time will be updated
when: (validators == true or validators == 'true') and (genesis_file is not defined)
tags: reconfig-genesis
template:
src: genesis-server.json.j2
dest: "/etc/{{service}}/tendermint/genesis.json"
owner: "{{service}}"
group: "{{service}}"
- name: copy generated service genesis.json - genesis_time will be updated
when: (validators == true or validators == 'true') and (service_genesis_file is not defined) and (service != 'ethermint')
template:
src: genesis-service.json.j2
src: genesis.json.j2
dest: "/etc/{{service}}/genesis.json"
owner: "{{service}}"
group: "{{service}}"
- name: copy pre-created tendermint genesis.json
when: tendermint_genesis_file is defined
copy: "src={{tendermint_genesis_file}} dest=/etc/{{service}}/tendermint/genesis.json owner={{service}} group={{service}}"
- name: copy pre-created service genesis.json
when: service_genesis_file is defined
copy: "src={{service_genesis_file}} dest=/etc/{{service}}/genesis.json owner={{service}} group={{service}}"
- name: copy pre-created genesis.json
when: genesis_file is defined
copy: "src={{genesis_file}} dest=/etc/{{service}}/genesis.json owner={{service}} group={{service}}"
- name: copy tendermint config.toml
tags: reconfig
tags: reconfig-toml
when: validators == true or validators == 'true'
template:
src: config.toml.j2
dest: "/etc/{{service}}/tendermint/config.toml"
dest: "/etc/{{service}}/config.toml"
owner: "{{service}}"
group: "{{service}}"
- name: Copy validator network files for non-validators
when: validators == false or validators == 'false'
tags: reconfig-toml,reconfig-genesis
get_url: "url={{item['src']}} dest={{item['dst']}} force=yes"
with_items:
- { src: "https://raw.githubusercontent.com/tendermint/testnets/master/{{validator_network}}/{{service}}/genesis.json" , dst: "/etc/{{service}}/genesis.json" }
- { src: "https://raw.githubusercontent.com/tendermint/testnets/master/{{validator_network}}/tendermint/genesis.json" , dst: "/etc/{{service}}/tendermint/genesis.json" }
- { src: "https://raw.githubusercontent.com/tendermint/testnets/master/{{validator_network}}/tendermint/config.toml" , dst: "/etc/{{service}}/tendermint/config.toml" }
- { src: "https://raw.githubusercontent.com/tendermint/testnets/master/{{validator_network}}/config.toml" , dst: "/etc/{{service}}/config.toml" }
- name: Set validator network files permissions for non-validators
when: validators == false or validators == 'false'
tags: reconfig-toml,reconfig-genesis
file: "path={{item}} owner={{service}} group={{service}}"
with_items:
- "/etc/{{service}}/genesis.json"
- "/etc/{{service}}/tendermint/genesis.json"
- "/etc/{{service}}/tendermint/config.toml"
- "/etc/{{service}}/config.toml"

View File

@@ -4,13 +4,23 @@
proxy_app = "tcp://127.0.0.1:46658"
moniker = "{{inventory_hostname}}"
fast_sync = true
{% if service == 'tendermint' %}
db_backend = "memdb"
#log_level = "mempool:error,*:debug"
log_level = "mempool:error,*:debug"
{% else %}
db_backend = "leveldb"
log_level = "state:info,*:error"
{% endif %}
[rpc]
laddr = "tcp://0.0.0.0:46657"
{% if service == 'tendermint' %}
[mempool]
recheck = false
broadcast = false
@@ -24,11 +34,21 @@ skip_timeout_commit = true
timeout_commit = 1
wal_light = true
block_part_size = 262144
create_empty_blocks_interval = 1
{% else %}
[consensus]
create_empty_blocks_interval = 1
{% endif %}
[p2p]
{% if service == 'tendermint' %}
max_msg_packet_payload_size=65536
send_rate=51200000 # 50 MB/s
recv_rate=51200000 # 50 MB/s
{% endif %}
laddr = "tcp://0.0.0.0:46656"
{% if validators == true or validators == 'true' %}
{% set comma = joiner(",") %}seeds = "{% for host in ((groups[testnet_name]|default([]))+(groups['tag_Environment_'~(testnet_name|regex_replace('-','_'))]|default([])))|difference(inventory_hostname) %}{{ comma() }}{{hostvars[host]["inventory_hostname"]}}:46656{% endfor %}"

View File

@@ -12,7 +12,7 @@
"data": "{{hostvars[host]["pubkey"]["data"]}}",
"type": "{{hostvars[host]["pubkey"]["type"]}}"
},
"amount":10,
"power":10,
"name":"{{hostvars[host]["inventory_hostname"]}}"
}
{% endfor %}

View File

@@ -0,0 +1,46 @@
{
"genesis_time":"{{ansible_date_time.iso8601}}",
"chain_id":"{{testnet_name}}",
"validators":
[
{% if (validators == true) or (validators == 'true') %}
{% set comma = joiner(",") %}
{% for host in (groups[testnet_name]|default([]))+(groups['tag_Environment_'~(testnet_name|regex_replace('-','_'))]|default([])) %}
{{ comma() }}
{
"pub_key": {
"data": "{{hostvars[host]["pubkey"]["data"]}}",
"type": "{{hostvars[host]["pubkey"]["type"]}}"
},
"power":10,
"name":"{{hostvars[host]["inventory_hostname"]}}"
}
{% endfor %}
{% endif %}
],
"app_hash":"",
"app_options": {
{% if app_options_file is defined %}
{% include app_options_file %}
{% endif %}
}
{% if service == 'ethermint' %}
,
"config": {
"chainId": 15,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"nonce": "0xdeadbeefdeadbeef",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x40",
"gasLimit": "0x8000000",
"alloc": {
"0x7eff122b94897ea5b0e2a9abf47b86337fafebdc": { "balance": "10000000000000000000000000000000000" },
"0xc6713982649D9284ff56c32655a9ECcCDA78422A": { "balance": "10000000000000000000000000000000000" }
}
{% endif %}
}

View File

@@ -15,11 +15,8 @@
- name: Reload systemd services
systemd: "name={{service}} daemon_reload=yes enabled=no"
- name: Create tendermint directory
file: "path=/etc/{{service}}/tendermint state=directory mode=0755 owner={{service}} group={{service}}"
- name: Initialize tendermint
command: "/usr/bin/tendermint init --home /etc/{{service}}/tendermint"
command: "/usr/bin/tendermint init --home /etc/{{service}}"
become: yes
become_user: "{{service}}"

View File

@@ -0,0 +1,6 @@
---
- name: Get config.toml from node
fetch: "dest={{ destination | default('.') }}/config.toml flat=yes src=/etc/{{service}}/config.toml"
run_once: yes

View File

@@ -0,0 +1,6 @@
---
- name: Get file from node
fetch: "dest={{ destination | default('.') }}/{{ source | basename }} flat=yes src='{{source}}'"
run_once: yes

View File

@@ -1,4 +1,5 @@
---
release_install: true
binary: "{{ lookup('env','GOPATH') | default('') }}/bin/{{service}}"
devops_path: false

View File

@@ -13,7 +13,7 @@
#Workaround
- name: Download repository key for CentOS/RedHat
when: ansible_os_family == "RedHat"
get_url: "url=https://tendermint-packages.interblock.io/centos/7/os/x86_64/RPM-GPG-KEY-Tendermint dest=/root/RPM-GPG-KEY-Tendermint force=yes checksum=sha256:a8c61d4061697d2595562c703dbafbdfdcfa7f0c75a523ac84d5609d1b444abe"
get_url: "url=https://tendermint-packages.interblock.io/{{ (devops_path | default(false) | bool) | ternary('devops/','') }}centos/7/os/x86_64/RPM-GPG-KEY-Tendermint dest=/root/RPM-GPG-KEY-Tendermint force=yes checksum=sha256:a8c61d4061697d2595562c703dbafbdfdcfa7f0c75a523ac84d5609d1b444abe"
- name: Import repository key for CentOS/RedHat
when: ansible_os_family == "RedHat"
command: "rpm --import /root/RPM-GPG-KEY-Tendermint"
@@ -22,13 +22,32 @@
when: ansible_os_family == "RedHat"
yum_repository:
name: tendermint
baseurl: https://tendermint-packages.interblock.io/centos/7/os/x86_64
baseurl: https://tendermint-packages.interblock.io/{{ (devops_path | default(false) | bool) | ternary('devops/','') }}centos/7/os/x86_64
description: "Tendermint repo"
gpgcheck: yes
gpgkey: https://tendermint-packages.interblock.io/centos/7/os/x86_64/RPM-GPG-KEY-Tendermint
gpgkey: https://tendermint-packages.interblock.io/{{ (devops_path | default(false) | bool) | ternary('devops/','') }}centos/7/os/x86_64/RPM-GPG-KEY-Tendermint
# repo_gpgcheck: yes
- name: Install package on CentOS/RedHat
when: ansible_os_family == "RedHat"
yum: "pkg={{service}} update_cache=yes state=latest"
# The below commands are required so that the tomlconfig playbook can run.
- name: Install epel-release on CentOS/RedHat
when: ansible_os_family == "RedHat"
yum: "pkg=epel-release update_cache=yes state=latest"
- name: Install pip on CentOS/RedHat
when: ansible_os_family == "RedHat"
yum: "pkg={{item}} state=latest"
with_items:
- python2-pip
- python-virtualenv
- unzip
- tar
- name: Install toml
when: ansible_os_family == "RedHat"
pip: name=toml

View File

@@ -8,15 +8,24 @@
- name: Add repository key on Debian/Ubuntu
when: ansible_os_family == "Debian"
apt_key:
url: https://tendermint-packages.interblock.io/centos/7/os/x86_64/RPM-GPG-KEY-Tendermint
url: https://tendermint-packages.interblock.io/{{ (devops_path | default(false) | bool) | ternary('devops/','') }}centos/7/os/x86_64/RPM-GPG-KEY-Tendermint
id: 2122CBE9
- name: Install tendermint repository on Debian/Ubuntu
when: ansible_os_family == "Debian"
apt_repository:
repo: deb https://tendermint-packages.interblock.io/debian stable main
repo: deb https://tendermint-packages.interblock.io/{{ (devops_path | default(false) | bool) | ternary('devops/','') }}debian stable main
- name: Install package on Debian/Ubuntu
when: ansible_os_family == "Debian"
apt: "pkg={{service}} update_cache=yes state=latest"
# The below command is required to use the tomlconfig playbook.
- name: Install package on Debian/Ubuntu
when: ansible_os_family == "Debian"
apt: "pkg={{item}} state=latest"
with_items:
- python-toml
- unzip
- tar

View File

@@ -13,6 +13,9 @@
- name: Restart journald
service: name=systemd-journald state=restarted
#TODO include is deprecated in Ansible 2.4.0 and will be removed in 2.8.0
#Replace it with include_tasks
- include: debian.yml
when: ansible_os_family == "Debian"

View File

@@ -0,0 +1,360 @@
#!/usr/bin/python
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: jsonconfig
short_description: Ensure a particular configuration is added to a json-formatted configuration file
version_added: "2.4"
description:
- This module will add configuration to a json-formatted configuration file.
options:
dest:
description:
- The file to modify.
required: true
aliases: [ name, destfile ]
json:
description:
- The configuration in json format to apply.
required: false
default: '{}'
merge:
description:
- Used with C(state=present). If specified, it will merge the configuration. Othwerwise
the configuration will be overwritten.
required: false
choices: [ "yes", "no" ]
default: "yes"
state:
description:
- Whether the configuration should be there or not.
required: false
choices: [ present, absent ]
default: "present"
create:
description:
- Used with C(state=present). If specified, the file will be created
if it does not already exist. By default it will fail if the file
is missing.
required: false
choices: [ "yes", "no" ]
default: "no"
backup:
description:
- Create a backup file including the timestamp information so you can
get the original file back if you somehow clobbered it incorrectly.
required: false
choices: [ "yes", "no" ]
default: "no"
others:
description:
- All arguments accepted by the M(file) module also work here.
required: false
extends_documentation_fragment:
- files
- validate
author:
- "Greg Szabo (@greg-szabo)"
'''
EXAMPLES = '''
# Add a new section to a json file
- name: Add comment section
jsonconfig:
dest: /etc/something.json
json: '{ "comment": { "comment1": "mycomment" } }'
# Rewrite a json file with the configuration
- name: Create or overwrite config.json
jsonconfig:
dest: /etc/config.json
json: '{ "regedit": { "freshfile": true } }'
merge: no
create: yes
'''
RETURN = '''
changed:
description: True if the configuration changed.
type: bool
msg:
description: Description of the change
type: str
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import b
from ansible.module_utils._text import to_bytes, to_native
import tempfile
import json
import copy
import os
def write_changes(module, b_lines, dest):
tmpfd, tmpfile = tempfile.mkstemp()
f = os.fdopen(tmpfd, 'wb')
f.writelines(b_lines)
f.close()
validate = module.params.get('validate', None)
valid = not validate
if validate:
if "%s" not in validate:
module.fail_json(msg="validate must contain %%s: %s" % (validate))
(rc, out, err) = module.run_command(to_bytes(validate % tmpfile, errors='surrogate_or_strict'))
valid = rc == 0
if rc != 0:
module.fail_json(msg='failed to validate: '
'rc:%s error:%s' % (rc, err))
if valid:
module.atomic_move(tmpfile,
to_native(os.path.realpath(to_bytes(dest, errors='surrogate_or_strict')), errors='surrogate_or_strict'),
unsafe_writes=module.params['unsafe_writes'])
def check_file_attrs(module, changed, message, diff):
file_args = module.load_file_common_arguments(module.params)
if module.set_fs_attributes_if_different(file_args, False, diff=diff):
if changed:
message += " and "
changed = True
message += "ownership, perms or SE linux context changed"
return message, changed
#Merge dict d2 into dict d1 and return a new object
def deepmerge(d1, d2):
if d1 is None:
return copy.deepcopy(d2)
if d2 is None:
return copy.deepcopy(d1)
if d1 == d2:
return copy.deepcopy(d1)
if isinstance(d1, dict) and isinstance(d2, dict):
result={}
for key in set(d1.keys()+d2.keys()):
da = db = None
if key in d1:
da = d1[key]
if key in d2:
db = d2[key]
result[key] = deepmerge(da, db)
return result
else:
return copy.deepcopy(d2)
#Remove dict d2 from dict d1 and return a new object
def deepdiff(d1, d2):
if d1 is None or d2 is None:
return None
if d1 == d2:
return None
if isinstance(d1, dict) and isinstance(d2, dict):
result = {}
for key in d1.keys():
if key in d2:
dd = deepdiff(d1[key],d2[key])
if dd is not None:
result[key] = dd
else:
result[key] = d1[key]
return result
else:
return None
def present(module, dest, conf, merge, create, backup):
diff = {'before': '',
'after': '',
'before_header': '%s (content)' % dest,
'after_header': '%s (content)' % dest}
b_dest = to_bytes(dest, errors='surrogate_or_strict')
if not os.path.exists(b_dest):
if not create:
module.fail_json(rc=257, msg='Destination %s does not exist !' % dest)
b_destpath = os.path.dirname(b_dest)
if not os.path.exists(b_destpath) and not module.check_mode:
os.makedirs(b_destpath)
b_lines = []
else:
f = open(b_dest, 'rb')
b_lines = f.readlines()
f.close()
lines = to_native(b('').join(b_lines))
if module._diff:
diff['before'] = lines
b_conf = to_bytes(conf, errors='surrogate_or_strict')
jsonconfig = json.loads(lines)
config = eval(b_conf)
if not isinstance(config, dict):
module.fail_json(msg="Invalid value in json parameter: {0}".format(config))
b_lines_new = b_lines
msg = ''
changed = False
if not merge:
if jsonconfig != config:
b_lines_new = to_bytes(json.dumps(config, sort_keys=True, indent=4, separators=(',', ': ')))
msg = 'config overwritten'
changed = True
else:
mergedconfig = deepmerge(jsonconfig,config)
if jsonconfig != mergedconfig:
b_lines_new = to_bytes(json.dumps(mergedconfig, sort_keys=True, indent=4, separators=(',', ': ')))
msg = 'config merged'
changed = True
if module._diff:
diff['after'] = to_native(b('').join(b_lines_new))
backupdest = ""
if changed and not module.check_mode:
if backup and os.path.exists(b_dest):
backupdest = module.backup_local(dest)
write_changes(module, b_lines_new, dest)
if module.check_mode and not os.path.exists(b_dest):
module.exit_json(changed=changed, msg=msg, backup=backupdest, diff=diff)
attr_diff = {}
msg, changed = check_file_attrs(module, changed, msg, attr_diff)
attr_diff['before_header'] = '%s (file attributes)' % dest
attr_diff['after_header'] = '%s (file attributes)' % dest
difflist = [diff, attr_diff]
module.exit_json(changed=changed, msg=msg, backup=backupdest, diff=difflist)
def absent(module, dest, conf, backup):
b_dest = to_bytes(dest, errors='surrogate_or_strict')
if not os.path.exists(b_dest):
module.exit_json(changed=False, msg="file not present")
msg = ''
diff = {'before': '',
'after': '',
'before_header': '%s (content)' % dest,
'after_header': '%s (content)' % dest}
f = open(b_dest, 'rb')
b_lines = f.readlines()
f.close()
lines = to_native(b('').join(b_lines))
b_conf = to_bytes(conf, errors='surrogate_or_strict')
lines = to_native(b('').join(b_lines))
jsonconfig = json.loads(lines)
config = eval(b_conf)
if not isinstance(config, dict):
module.fail_json(msg="Invalid value in json parameter: {0}".format(config))
if module._diff:
diff['before'] = to_native(b('').join(b_lines))
b_lines_new = b_lines
msg = ''
changed = False
diffconfig = deepdiff(jsonconfig,config)
if diffconfig is None:
diffconfig = {}
if jsonconfig != diffconfig:
b_lines_new = to_bytes(json.dumps(diffconfig, sort_keys=True, indent=4, separators=(',', ': ')))
msg = 'config removed'
changed = True
if module._diff:
diff['after'] = to_native(b('').join(b_lines_new))
backupdest = ""
if changed and not module.check_mode:
if backup:
backupdest = module.backup_local(dest)
write_changes(module, b_lines_new, dest)
attr_diff = {}
msg, changed = check_file_attrs(module, changed, msg, attr_diff)
attr_diff['before_header'] = '%s (file attributes)' % dest
attr_diff['after_header'] = '%s (file attributes)' % dest
difflist = [diff, attr_diff]
module.exit_json(changed=changed, msg=msg, backup=backupdest, diff=difflist)
def main():
# define the available arguments/parameters that a user can pass to
# the module
module_args = dict(
dest=dict(type='str', required=True),
json=dict(default=None, required=True),
merge=dict(type='bool', default=True),
state=dict(default='present', choices=['absent', 'present']),
create=dict(type='bool', default=False),
backup=dict(type='bool', default=False),
validate=dict(default=None, type='str')
)
# the AnsibleModule object will be our abstraction working with Ansible
# this includes instantiation, a couple of common attr would be the
# args/params passed to the execution, as well as if the module
# supports check mode
module = AnsibleModule(
argument_spec=module_args,
add_file_common_args=True,
supports_check_mode=True
)
params = module.params
create = params['create']
merge = params['merge']
backup = params['backup']
dest = params['dest']
b_dest = to_bytes(dest, errors='surrogate_or_strict')
if os.path.isdir(b_dest):
module.fail_json(rc=256, msg='Destination %s is a directory !' % dest)
conf = params['json']
if params['state'] == 'present':
present(module, dest, conf, merge, create, backup)
else:
absent(module, dest, conf, backup)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,5 @@
---
- name: Update
jsonconfig: "dest='{{destination}}' json='{{jsonconfig}}' state={{(remove | default(false) | bool) | ternary('absent','present')}}"

View File

@@ -0,0 +1,27 @@
---
- name: Download file if necessary
when: source | regex_search('^https?://')
get_url: "url={{source}} dest={{localdir}}/{{source | basename | regex_replace('\\?.*$','')}}"
register: downloaded
connection: local
run_once: yes
become: no
- name: Figure out file source
set_fact:
compiledsource: "{{ (downloaded.skipped is defined) | ternary(source, downloaded.dest) }}"
connection: local
become: no
- name: Extract file to destination
when: compiledsource | regex_search('\\.(zip|tar|tar\\.gz|tgz|tb2|tbz|tbz2|tar\\.bz2|txz|tar\\.xz)$')
register: extractcopy
unarchive:
src: "{{compiledsource}}"
dest: "{{destination}}"
- name: Copy non-zipped file to destination
when: extractcopy.skipped is defined
copy: "src='{{compiledsource}}' dest='{{destination}}'"

View File

@@ -0,0 +1,3 @@
---
destination: /etc/{{service}}/config.toml

View File

@@ -0,0 +1,386 @@
#!/usr/bin/python
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: tomlconfig
short_description: Ensure a particular configuration is added to a toml-formatted configuration file
version_added: "2.4"
description:
- This module will add configuration to a toml-formatted configuration file.
options:
dest:
description:
- The file to modify.
required: true
aliases: [ name, destfile ]
json:
description:
- The configuration in json format to apply. Either C(json) or C(toml) has to be present.
required: false
default: '{}'
toml:
description:
- The configuration in toml format to apply. Either C(json) or C(toml) has to be present.
default: ''
merge:
description:
- Used with C(state=present). If specified, it will merge the configuration. Othwerwise
the configuration will be overwritten.
required: false
choices: [ "yes", "no" ]
default: "yes"
state:
description:
- Whether the configuration should be there or not.
required: false
choices: [ present, absent ]
default: "present"
create:
description:
- Used with C(state=present). If specified, the file will be created
if it does not already exist. By default it will fail if the file
is missing.
required: false
choices: [ "yes", "no" ]
default: "no"
backup:
description:
- Create a backup file including the timestamp information so you can
get the original file back if you somehow clobbered it incorrectly.
required: false
choices: [ "yes", "no" ]
default: "no"
others:
description:
- All arguments accepted by the M(file) module also work here.
required: false
extends_documentation_fragment:
- files
- validate
author:
- "Greg Szabo (@greg-szabo)"
'''
EXAMPLES = '''
# Add a new section to a toml file
- name: Add comment section
tomlconfig:
dest: /etc/config.toml
json: '{ "comment": { "comment1": "mycomment" } }'
# Rewrite a toml file with the configuration
- name: Create or overwrite config.toml
tomlconfig:
dest: /etc/config.toml
json: '{ "regedit": { "freshfile": true } }'
merge: no
create: yes
'''
RETURN = '''
changed:
description: True if the configuration changed.
type: bool
msg:
description: Description of the change
type: str
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import b
from ansible.module_utils._text import to_bytes, to_native
import tempfile
import toml as pytoml
import json
import copy
import os
def write_changes(module, b_lines, dest):
tmpfd, tmpfile = tempfile.mkstemp()
f = os.fdopen(tmpfd, 'wb')
f.writelines(b_lines)
f.close()
validate = module.params.get('validate', None)
valid = not validate
if validate:
if "%s" not in validate:
module.fail_json(msg="validate must contain %%s: %s" % (validate))
(rc, out, err) = module.run_command(to_bytes(validate % tmpfile, errors='surrogate_or_strict'))
valid = rc == 0
if rc != 0:
module.fail_json(msg='failed to validate: '
'rc:%s error:%s' % (rc, err))
if valid:
module.atomic_move(tmpfile,
to_native(os.path.realpath(to_bytes(dest, errors='surrogate_or_strict')), errors='surrogate_or_strict'),
unsafe_writes=module.params['unsafe_writes'])
def check_file_attrs(module, changed, message, diff):
file_args = module.load_file_common_arguments(module.params)
if module.set_fs_attributes_if_different(file_args, False, diff=diff):
if changed:
message += " and "
changed = True
message += "ownership, perms or SE linux context changed"
return message, changed
#Merge dict d2 into dict d1 and return a new object
def deepmerge(d1, d2):
if d1 is None:
return copy.deepcopy(d2)
if d2 is None:
return copy.deepcopy(d1)
if d1 == d2:
return copy.deepcopy(d1)
if isinstance(d1, dict) and isinstance(d2, dict):
result={}
for key in set(d1.keys()+d2.keys()):
da = db = None
if key in d1:
da = d1[key]
if key in d2:
db = d2[key]
result[key] = deepmerge(da, db)
return result
else:
return copy.deepcopy(d2)
#Remove dict d2 from dict d1 and return a new object
def deepdiff(d1, d2):
if d1 is None or d2 is None:
return None
if d1 == d2:
return None
if isinstance(d1, dict) and isinstance(d2, dict):
result = {}
for key in d1.keys():
if key in d2:
dd = deepdiff(d1[key],d2[key])
if dd is not None:
result[key] = dd
else:
result[key] = d1[key]
return result
else:
return None
def present(module, dest, conf, jsonbool, merge, create, backup):
diff = {'before': '',
'after': '',
'before_header': '%s (content)' % dest,
'after_header': '%s (content)' % dest}
b_dest = to_bytes(dest, errors='surrogate_or_strict')
if not os.path.exists(b_dest):
if not create:
module.fail_json(rc=257, msg='Destination %s does not exist !' % dest)
b_destpath = os.path.dirname(b_dest)
if not os.path.exists(b_destpath) and not module.check_mode:
os.makedirs(b_destpath)
b_lines = []
else:
f = open(b_dest, 'rb')
b_lines = f.readlines()
f.close()
lines = to_native(b('').join(b_lines))
if module._diff:
diff['before'] = lines
b_conf = to_bytes(conf, errors='surrogate_or_strict')
tomlconfig = pytoml.loads(lines)
config = {}
if jsonbool:
config = eval(b_conf)
else:
config = pytoml.loads(b_conf)
if not isinstance(config, dict):
if jsonbool:
module.fail_json(msg="Invalid value in json parameter: {0}".format(config))
else:
module.fail_json(msg="Invalid value in toml parameter: {0}".format(config))
b_lines_new = b_lines
msg = ''
changed = False
if not merge:
if tomlconfig != config:
b_lines_new = to_bytes(pytoml.dumps(config))
msg = 'config overwritten'
changed = True
else:
mergedconfig = deepmerge(tomlconfig,config)
if tomlconfig != mergedconfig:
b_lines_new = to_bytes(pytoml.dumps(mergedconfig))
msg = 'config merged'
changed = True
if module._diff:
diff['after'] = to_native(b('').join(b_lines_new))
backupdest = ""
if changed and not module.check_mode:
if backup and os.path.exists(b_dest):
backupdest = module.backup_local(dest)
write_changes(module, b_lines_new, dest)
if module.check_mode and not os.path.exists(b_dest):
module.exit_json(changed=changed, msg=msg, backup=backupdest, diff=diff)
attr_diff = {}
msg, changed = check_file_attrs(module, changed, msg, attr_diff)
attr_diff['before_header'] = '%s (file attributes)' % dest
attr_diff['after_header'] = '%s (file attributes)' % dest
difflist = [diff, attr_diff]
module.exit_json(changed=changed, msg=msg, backup=backupdest, diff=difflist)
def absent(module, dest, conf, jsonbool, backup):
b_dest = to_bytes(dest, errors='surrogate_or_strict')
if not os.path.exists(b_dest):
module.exit_json(changed=False, msg="file not present")
msg = ''
diff = {'before': '',
'after': '',
'before_header': '%s (content)' % dest,
'after_header': '%s (content)' % dest}
f = open(b_dest, 'rb')
b_lines = f.readlines()
f.close()
lines = to_native(b('').join(b_lines))
b_conf = to_bytes(conf, errors='surrogate_or_strict')
lines = to_native(b('').join(b_lines))
tomlconfig = pytoml.loads(lines)
config = {}
if jsonbool:
config = eval(b_conf)
else:
config = pytoml.loads(b_conf)
if not isinstance(config, dict):
if jsonbool:
module.fail_json(msg="Invalid value in json parameter: {0}".format(config))
else:
module.fail_json(msg="Invalid value in toml parameter: {0}".format(config))
if module._diff:
diff['before'] = to_native(b('').join(b_lines))
b_lines_new = b_lines
msg = ''
changed = False
diffconfig = deepdiff(tomlconfig,config)
if diffconfig is None:
diffconfig = {}
if tomlconfig != diffconfig:
b_lines_new = to_bytes(pytoml.dumps(diffconfig))
msg = 'config removed'
changed = True
if module._diff:
diff['after'] = to_native(b('').join(b_lines_new))
backupdest = ""
if changed and not module.check_mode:
if backup:
backupdest = module.backup_local(dest)
write_changes(module, b_lines_new, dest)
attr_diff = {}
msg, changed = check_file_attrs(module, changed, msg, attr_diff)
attr_diff['before_header'] = '%s (file attributes)' % dest
attr_diff['after_header'] = '%s (file attributes)' % dest
difflist = [diff, attr_diff]
module.exit_json(changed=changed, msg=msg, backup=backupdest, diff=difflist)
def main():
# define the available arguments/parameters that a user can pass to
# the module
module_args = dict(
dest=dict(type='str', required=True),
json=dict(default=None),
toml=dict(default=None),
merge=dict(type='bool', default=True),
state=dict(default='present', choices=['absent', 'present']),
create=dict(type='bool', default=False),
backup=dict(type='bool', default=False),
validate=dict(default=None, type='str')
)
# the AnsibleModule object will be our abstraction working with Ansible
# this includes instantiation, a couple of common attr would be the
# args/params passed to the execution, as well as if the module
# supports check mode
module = AnsibleModule(
argument_spec=module_args,
mutually_exclusive=[['json', 'toml']],
add_file_common_args=True,
supports_check_mode=True
)
params = module.params
create = params['create']
merge = params['merge']
backup = params['backup']
dest = params['dest']
b_dest = to_bytes(dest, errors='surrogate_or_strict')
if os.path.isdir(b_dest):
module.fail_json(rc=256, msg='Destination %s is a directory !' % dest)
par_json, par_toml, jsonbool = params['json'], params['toml'], False
if par_json is None:
conf = par_toml
else:
conf = par_json
jsonbool = True
if params['state'] == 'present':
present(module, dest, conf, jsonbool, merge, create, backup)
else:
absent(module, dest, conf, jsonbool, backup)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,10 @@
---
- name: Update config.toml with json
when: jsonconfig is defined
tomlconfig: "dest='{{destination}}' json='{{jsonconfig}}' state={{(remove | default(false) | bool) | ternary('absent','present')}}"
- name: Update config.toml with toml
when: tomlconfig is defined
tomlconfig: "dest='{{destination}}' toml='{{tomlconfig}}' state={{(remove | default(false) | bool) | ternary('absent','present')}}"

View File

@@ -6,6 +6,8 @@
when: "service == 'basecoin'"
become_user: basecoin
- shell: "export TMHOME=/etc/{{service}}/tendermint ; tendermint unsafe_reset_all"
- shell: "export TMHOME=/etc/{{service}} ; tendermint unsafe_reset_all"
become_user: "{{service}}"
- file: "path=/etc/{{service}}/data state=absent"

10
ansible/setfile.yml Normal file
View File

@@ -0,0 +1,10 @@
---
#variable "source" is required
#variable "destination" is required
- hosts: "{{ lookup('env','TF_VAR_TESTNET_NAME') }}:tag_Environment_{{ lookup('env','TF_VAR_TESTNET_NAME') | regex_replace('-','_') }}"
gather_facts: no
roles:
- setfile

8
ansible/tomlconfig.yml Normal file
View File

@@ -0,0 +1,8 @@
---
#variable "service" is required
- hosts: "{{ lookup('env','TF_VAR_TESTNET_NAME') }}:tag_Environment_{{ lookup('env','TF_VAR_TESTNET_NAME') | regex_replace('-','_') }}"
roles:
- tomlconfig