0002-python3-celery-now-handle-text-40288.patch
hobo/agent/common/management/commands/hobo_deploy.py | ||
---|---|---|
5 | 5 |
import requests |
6 | 6 |
import subprocess |
7 | 7 |
import sys |
8 | 8 |
import tempfile |
9 | 9 | |
10 | 10 |
from django.conf import settings |
11 | 11 |
from django.core.management.base import BaseCommand, CommandError |
12 | 12 |
from django.core.management import call_command, get_commands |
13 |
from django.utils.encoding import force_text |
|
13 | 14 |
from django.utils.six.moves.urllib import parse as urlparse |
14 | 15 | |
15 | 16 |
from tenant_schemas.utils import tenant_context |
16 | 17 |
from hobo.multitenant.middleware import TenantMiddleware, TenantNotFound |
17 | 18 |
from hobo.theme.utils import get_theme |
18 | 19 | |
19 | 20 |
# TODO: move this to settings |
20 | 21 |
KEY_SIZE = 1024 |
21 | 22 |
DAYS = 3652 |
22 | 23 | |
23 | 24 | |
24 | 25 |
def replace_file(path, content): |
25 | 26 |
dirname = os.path.dirname(path) |
26 | 27 |
fd, temp = tempfile.mkstemp(dir=dirname, |
27 | 28 |
prefix='.tmp-'+os.path.basename(path)+'-') |
28 | 29 |
f = os.fdopen(fd, 'w') |
29 |
f.write(content)
|
|
30 |
f.write(force_text(content))
|
|
30 | 31 |
f.flush() |
31 | 32 |
os.fsync(f.fileno()) |
32 | 33 |
f.close() |
33 | 34 |
os.rename(temp, path) |
34 | 35 | |
35 | 36 | |
36 | 37 |
class Command(BaseCommand): |
37 | 38 |
early_secondary_exit = True |
hobo/agent/worker/services.py | ||
---|---|---|
18 | 18 |
import fnmatch |
19 | 19 |
import json |
20 | 20 |
import multiprocessing |
21 | 21 |
import multiprocessing.pool |
22 | 22 |
import os |
23 | 23 |
import subprocess |
24 | 24 |
import sys |
25 | 25 | |
26 |
from django.utils.encoding import force_bytes |
|
26 | 27 |
from django.utils.six.moves.urllib import parse as urlparse |
27 | 28 | |
28 | 29 |
from . import settings |
29 | 30 | |
30 | 31 | |
31 | 32 |
class BaseService(object): |
32 | 33 |
tenants_dir = None |
33 | 34 | |
... | ... | |
75 | 76 |
return False |
76 | 77 | |
77 | 78 |
def execute(self, environment): |
78 | 79 |
if not os.path.exists(self.service_manage_try_cmd): |
79 | 80 |
return |
80 | 81 |
cmd = self.service_manage_cmd + ' hobo_deploy ' + self.base_url + ' -' |
81 | 82 |
cmd_process = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, |
82 | 83 |
stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
83 |
stdout, stderr = cmd_process.communicate(input=json.dumps(environment))
|
|
84 |
stdout, stderr = cmd_process.communicate(input=force_bytes(json.dumps(environment)))
|
|
84 | 85 |
if cmd_process.returncode != 0: |
85 | 86 |
raise RuntimeError('command "%s" failed: %r %r' % (cmd, stdout, stderr)) |
86 | 87 | |
87 | 88 |
@classmethod |
88 | 89 |
def notify(cls, data): |
89 | 90 |
if not os.path.exists(cls.service_manage_try_cmd): |
90 | 91 |
return |
91 | 92 |
tenants = cls.get_actual_tenants() |
... | ... | |
98 | 99 |
else: |
99 | 100 |
return |
100 | 101 |
cmd = cls.service_manage_cmd + ' hobo_notify -' |
101 | 102 |
try: |
102 | 103 |
cmd_process = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, |
103 | 104 |
stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
104 | 105 |
except OSError: |
105 | 106 |
return |
106 |
stdout, stderr = cmd_process.communicate(input=json.dumps(data))
|
|
107 |
stdout, stderr = cmd_process.communicate(input=force_bytes(json.dumps(data)))
|
|
107 | 108 |
if cmd_process.returncode != 0: |
108 | 109 |
raise RuntimeError('command "%s" failed: %r %r' % (cmd, stdout, stderr)) |
109 | 110 | |
110 | 111 | |
111 | 112 |
class Passerelle(BaseService): |
112 | 113 |
service_id = 'passerelle' |
113 | 114 |
service_manage_cmd = settings.PASSERELLE_MANAGE_COMMAND |
114 | 115 |
service_manage_try_cmd = settings.PASSERELLE_MANAGE_TRY_COMMAND |
tests_multitenant/test_agent_worker.py | ||
---|---|---|
1 | 1 |
# -*- coding: utf-8 -*- |
2 | 2 |
import importlib |
3 | 3 |
import json |
4 | 4 |
import mock |
5 | 5 |
import os |
6 | 6 |
import pytest |
7 | 7 |
import six |
8 | 8 | |
9 |
from django.utils.encoding import force_text |
|
10 | ||
9 | 11 |
from hobo.agent.worker.services import deploy, notify |
10 | 12 |
from hobo.agent.worker import settings |
11 | 13 | |
12 | 14 | |
13 | 15 |
ENVIRONMENT = { |
14 | 16 |
u'timestamp': '2022-02-22', |
15 | 17 |
u'services': [ |
16 | 18 |
{ |
... | ... | |
97 | 99 |
assert '/usr/bin/wcsctl hobo_deploy https://wcs.dev.publik.love/ -' in mock_calls |
98 | 100 |
assert '/usr/lib/combo/manage.py hobo_deploy https://combo.dev.publik.love/ -' in mock_calls |
99 | 101 |
assert '/usr/bin/hobo-manage hobo_deploy https://hobo2.dev.publik.love/ -' in mock_calls |
100 | 102 | |
101 | 103 |
# environment sent |
102 | 104 |
mock_calls = mocked_communicate.mock_calls |
103 | 105 |
assert len(mock_calls) == 4 |
104 | 106 |
for i in range(0, len(mock_calls)): |
105 |
assert json.loads(mock_calls[0][2]['input']) == ENVIRONMENT
|
|
107 |
assert json.loads(force_text(mock_calls[0][2]['input'])) == ENVIRONMENT
|
|
106 | 108 | |
107 | 109 |
mocked_opened.returncode = 1 |
108 | 110 |
with pytest.raises(RuntimeError, match='failed: '): |
109 | 111 |
deploy(ENVIRONMENT) |
110 | 112 | |
111 | 113 |
@mock.patch('hobo.agent.worker.services.os.path.exists', return_value=True) |
112 | 114 |
@mock.patch('hobo.agent.worker.services.subprocess') |
113 | 115 |
def test_deploy_host_with_agent_patterns(mocked_subprocess, mocked_exists, local_settings): |
... | ... | |
142 | 144 | |
143 | 145 |
# process called |
144 | 146 |
mock_calls = set(x[1][0] for x in mocked_subprocess.Popen.mock_calls) |
145 | 147 |
assert mock_calls == {'/usr/lib/combo/manage.py hobo_notify -'} |
146 | 148 | |
147 | 149 |
# notification sent |
148 | 150 |
mock_calls = mocked_communicate.mock_calls |
149 | 151 |
assert len(mock_calls) == 1 |
150 |
assert json.loads(mock_calls[0][2]['input'])['objects']['data'][0]['uuid'] == '12345'
|
|
152 |
assert json.loads(force_text(mock_calls[0][2]['input']))['objects']['data'][0]['uuid'] == '12345'
|
|
151 | 153 | |
152 | 154 |
mocked_opened.returncode = 1 |
153 | 155 |
with pytest.raises(RuntimeError, match='failed: '): |
154 | 156 |
notify(NOTIFICATION) |
155 | 157 | |
156 | 158 |
# ignore subprocess error |
157 | 159 |
mocked_communicate.reset_mock() |
158 | 160 |
mocked_subprocess.Popen.side_effect = OSError |
159 |
- |