Merge lp:~akuzminsky/twindb-agent/bug-1410509 into lp:twindb-agent
- bug-1410509
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Ovais Tariq |
Approved revision: | 19 |
Merged at revision: | 3 |
Proposed branch: | lp:~akuzminsky/twindb-agent/bug-1410509 |
Merge into: | lp:twindb-agent |
Diff against target: |
747 lines (+250/-123) 10 files modified
Makefile (+94/-6) support/deb/debian/changelog (+0/-15) support/deb/debian/control (+13/-6) support/deb/debian/twindb.init (+31/-5) support/deb/debian/twindb.manpages (+1/-1) support/deb/debian/twindb.postinst (+9/-11) support/rpm/rpmmacros (+0/-2) support/rpm/twindb.spec.template (+3/-2) support/twindb (+3/-3) twindb.py (+96/-72) |
To merge this branch: | bzr merge lp:~akuzminsky/twindb-agent/bug-1410509 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ovais Tariq | Approve | ||
Review via email: mp+246837@code.launchpad.net |
Commit message
Fixes Bug #1410509
Description of the change
- 5. By root <root@ubuntu-lucid>
-
Make the packager's full name and email match to ones from the packager GPG key
- 6. By root <root@ubuntu-lucid>
-
fix arithmetic expansion error in shell
- 7. By root <root@ubuntu-lucid>
-
Use a template @@CODENAME@@ in changelog. It is replaced by a build script
- 8. By root <root@ubuntu-lucid>
-
sh-compatible increment is fixed again
- 9. By root <root@ubuntu-lucid>
-
show registration hint only if the agent isn't registred
- 10. By root <root@ubuntu-lucid>
-
On lucid sys.path doen't include path where mysql-connector
-python installs its modules - 11. By root <root@ubuntu-lucid>
-
Include OS codename into debian package version
- 12. By root <root@ubuntu-lucid>
-
package version ++
- 13. By root <root@ubuntu-lucid>
-
Use UNRELEASED as target name, otherwise dch throws and error
- 14. By root <root@ubuntu-lucid>
-
Version ++
- 15. By root <root@ubuntu-lucid>
-
updated changelog
Ovais Tariq (ovais-tariq) wrote : | # |
- 16. By Aleksandr Kuzminsky
-
Build rpm packages in local .build directory instead of /root/rpmbuild
Ovais Tariq (ovais-tariq) wrote : | # |
Have the dependencies for the deb package not been specified?
I am able to install the package using:
dpkg -i /tmp/twindb_
Although the dependencies are not installed on the system. It should have failed.
root@server55-
ii twindb 0.1.32-1.wheezy all This is a TwinDB agent - a tool that takes backups from MySQL server
When I try to start twindb agent it fails which is expected:
root@server55-
Traceback (most recent call last):
File "/usr/bin/twindb", line 27, in <module>
import mysql.connector
ImportError: No module named mysql.connector
And then uninstalling and purging fails because pre-removal script is failing:
root@server55-
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
mysql-server percona-xtrabackup
Use 'apt-get autoremove' to remove them.
The following packages will be REMOVED:
twindb
0 upgraded, 0 newly installed, 1 to remove and 68 not upgraded.
After this operation, 129 kB disk space will be freed.
Do you want to continue [Y/n]? y
(Reading database ... 72372 files and directories currently installed.)
Removing twindb ...
Pid file(/var/
invoke-rc.d: initscript twindb, action "stop" failed.
dpkg: error processing twindb (--remove):
subprocess installed pre-removal script returned error exit status 1
Traceback (most recent call last):
File "/usr/bin/twindb", line 27, in <module>
import mysql.connector
ImportError: No module named mysql.connector
=======
TwinDB client is installed.
Now you need to register this server. To do so run:
twindb --register <registration code>
To obtain the registration code follow link https:/
=======
Starting TwinDB agent ... OK
Errors were encountered while processing:
twindb
E: Sub-process /usr/bin/dpkg returned an error code (1)
root@server55-
(Reading database ... 72372 files and directories currently installed.)
Removing twindb ...
Pid file(/var/
invoke-rc.d: initscript twindb, action "stop" failed.
dpkg: error processing twindb (--remove):
subprocess installed pre-removal script returned error exit status 1
Traceback (most recent call last):
File "/usr/bin/twindb", line 27, in <module>
import mysql.connector
ImportError: No module named mysql.connector
=======
TwinDB client is installed.
Now you need to register this server. To do so run:
twindb --register <registration code>
To obtain the registration code follow link https:/
=======
Starting TwinDB agent ... OK
Errors were encountered while processing:
twindb
...
- 17. By root <root@ubuntu-lucid>
-
* add mysql-connector
-python as dependency in Debian packages
* Number of small fixes in twindb init script for Debian
Ovais Tariq (ovais-tariq) wrote : | # |
The deb package gets installed but following errors are reported:
Setting up twindb (0.1.32-1.wheezy) ...
2015-01-21 04:05:02,893: twindb: ERROR: is_registered(
The complete installation log is as follows:
* bash[install-
Reading package lists... Done
Building dependency tree... 0%
Building dependency tree
Reading state information... 0%
Reading state information... Done
lding data structures... 0%
Building data structures... Done
lding data structures... 0%
Building data structures... Done
0% [Working]
Get:1 http://
Fetched 111 kB in 0s (0 B/s)
Selecting previously unselected package mysql-server.
(Reading database ... 72352 files and directories currently installed.)
Unpacking mysql-server (from .../mysql-
Selecting previously unselected package mysql-connector
Unpacking mysql-connector
Selecting previously unselected package percona-xtrabackup.
Unpacking percona-xtrabackup (from .../percona-
Setting up mysql-server (5.5.40-0+wheezy1) ...
Setting up mysql-connector
Setting up percona-xtrabackup (2.2.8-
Selecting previously unselected package twindb.
(Reading database ... 72492 files and directories currently installed.)
Unpacking twindb (from .../twindb_
Setting up twindb (0.1.32-1.wheezy) ...
2015-01-21 04:05:02,893: twindb: ERROR: is_registered(
TwinDB client is installed.
Now you need to register this server. To do so run:
twindb --register <registration code>
To obtain the registration code follow link https:/
Starting TwinDB agent ... OK
Processing triggers for man-db ...
Fetched 111 kB in 0s (0 B/s)
Ovais Tariq (ovais-tariq) wrote : | # |
The twindb agent fails to register though. Following is the complete log of the test run:
1) twindb agent is able to register Command "/usr/bin/twindb --register 0f6714f735a06a4
Failure/Error: its(:exit_status) { should eq 0 }
expected: 0
got: 1
2015-01-21 04:06:54,341: twindb: INFO: install_
2015-01-21 04:06:54,537: twindb: INFO: install_
gpg: key A8AD9889: public key "TwinDB (TwinDB API Portal) <email address hidden>" imported
gpg: Total number processed: 1
gpg: imported: 1 (RSA: 1)
2015-01-21 04:06:54,743: twindb: INFO: gen_gpg_
2015-01-21 04:06:54,949: twindb: INFO: gen_gpg_
gpg: Generating a standard key
...+++++
....+++++
.+++++
gpg: key 3C43C384 marked as ultimately trusted
gpg: done
2015-01-21 04:06:56,481: twindb: INFO: action_
2015-01-21 04:06:56,801: twindb: INFO: action_
2015-01-21 04:06:57,119: twindb: INFO: action_
2015-01-21 04:06:57,431: twindb: INFO: action_
2015-01-21 04:06:57,746: twindb: INFO: action_
Generating public/private rsa key pair.
Created directory '/root/.ssh'.
Your identification has been saved in /root/.
Your public key has been saved in /root/.
The key fingerprint is:
The key's randomart image is:
+--[ RSA 2048]----+
| |
| |
| |
| + |
| ..S . |
| .o. o o |
| o.o. o + |
| o.oE.+.o .|
| .o..=+=oo |
2015-01-21 04:06:58,170: twindb: INFO: action_
Traceback (most recent call last):
File "/usr/bin/twindb", line 2283, in <module>
main()
File "/usr/bin/twindb", line 2257, in main
File "/usr/bin/twindb", line 104...
Ovais Tariq (ovais-tariq) wrote : | # |
twindb --is-registered also appears to be broken:
2) twindb agent is able to register Command "/usr/bin/twindb --is-registered" stdout should match /YES/
Ovais Tariq (ovais-tariq) : | # |
- 18. By root <email address hidden>
-
Don't send debug logs to dispatcher, otherwise it's impossible to read debug output
- 19. By root <root@ubuntu-lucid>
-
pretty debug messages in get_response()
- 20. By Aleksandr Kuzminsky
-
* Debian standard bump
* Removed mysql-server and mysql-client dependencies. I'm not sure all MySQL vendors provide mysql-server. Besides, if mysql-server-5.5 is installed it will try to install mysql-server.
* Use get_mysql_connection( ) to manage connection to MySQL
* Pretty print JSON response from the dispatcher and ignore empty responses
* Make debug output nicer and more readable
Ovais Tariq (ovais-tariq) wrote : | # |
It fails when agent interacts with the production dispatcher as well.
/usr/bin/twindb -g --dispatcher dispatcher.
2015-01-23 18:07:07,432: twindb: DEBUG: get_response():485: Enter get_response(
2015-01-23 18:07:07,514: twindb: DEBUG: get_response():495: Sending to dispatcher.
},
"type": "is_registered"
}
2015-01-23 18:07:07,521: twindb: DEBUG: encrypt():386: Public key of <email address hidden> is not installed.
2015-01-23 18:07:07,522: twindb: DEBUG: encrypt():387: Will not encrypt message
2015-01-23 18:07:07,616: twindb: DEBUG: get_response():521: Response from http://
"msg": "Ignoring request without type",
},
}
2015-01-23 18:07:07,616: twindb: ERROR: is_registered(
2015-01-23 18:07:07,618: twindb: DEBUG: exit_on_
File "/usr/bin/twindb", line 750, in is_registered
msg_enc = response_
KeyError: u'response'
/usr/bin/twindb -g --dispatcher dispatcher.
2015-01-23 18:07:07,775: twindb: INFO: check_gpg():243: Looks like GPG never ran. Initializing GPG configuration
2015-01-23 18:07:07,776: twindb: INFO: install_
2015-01-23 18:07:07,789: twindb: INFO: install_
gpg: keyring `/root/
gpg: keyring `/root/
gpg: /root/.
gpg: key A8AD9889: public key "TwinDB (TwinDB API Portal) <email address hidden>" imported
2015-01-23 18:07:07,797: twindb: INFO: gen_gpg_
2015-01-23 18:07:07,798: twindb: INFO: gen_gpg_
gpg: Total number processed: 1
gpg: imported: 1 (RSA: 1)
gpg: Generating a standard key
gpg: key 94B30215 marked as ultimately trusted
gpg: done
2015-01-23 18:07:08,334: twindb: DEBUG: check_env():271: Enviroment is OK
2015-01-23 18:07:08,335: twindb: INFO: action_
2015-01-23 18:07:08,335: twindb: INFO: action_
2015-01-23 18:07:08,336: twindb: INFO: action_
2015-01-23 18:07:08,336: twindb: INFO: action_
Ovais Tariq (ovais-tariq) wrote : | # |
Above test was done on CentOS 6.5
- 21. By Aleksandr Kuzminsky
-
add lsof as dependency
- 22. By Aleksandr Kuzminsky
-
add lsof as dependency in rpm spec file too
- 23. By Aleksandr Kuzminsky
-
Connect to MySQL with option_files only if at least one options file was found
- 24. By Aleksandr Kuzminsky
-
Specify socket for innobackupex
- 25. By Aleksandr Kuzminsky
-
Select only processes that fully match mysqld
- 26. By Aleksandr Kuzminsky
-
Parse all command line arguments before calling is_registered()
Ovais Tariq (ovais-tariq) wrote : | # |
All tests pass.
Preview Diff
1 | === modified file 'Makefile' |
2 | --- Makefile 2015-01-16 07:41:06 +0000 |
3 | +++ Makefile 2015-01-24 21:00:42 +0000 |
4 | @@ -1,12 +1,16 @@ |
5 | # TwinDB agent Makefile |
6 | |
7 | spec = support/rpm/twindb.spec |
8 | -client_version = "`grep Version: ${spec} | awk '{ print $$2}' | head -1`" |
9 | -client_release = "`grep Release: ${spec} | awk '{ print $$2}' | head -1`" |
10 | +client_version = 0.1.32 |
11 | +client_release = 1 |
12 | rh_release = "$$(r=`lsb_release -sr | cut -d . -f1`; if [ \"$$r\" = \"n/a\" ] ; then echo latest; else echo $$r; fi)" |
13 | +rpmmacros = /usr/lib/rpm/macros:/usr/lib/rpm/redhat/macros:/etc/rpm/macros:support/rpm/rpmmacros |
14 | +deb_release = "$$(lsb_release -sc)" |
15 | build_dir = .build |
16 | src_dir = twindb-${client_version} |
17 | -top_dir = /root/rpmbuild |
18 | +pwd := $(shell pwd) |
19 | +top_dir = ${pwd}/${build_dir}/rpmbuild |
20 | +deb_packages = build-essential devscripts debhelper |
21 | |
22 | .PHONY: help rpm sign rpmmacros |
23 | |
24 | @@ -40,13 +44,21 @@ |
25 | |
26 | clean: |
27 | rm -f twindb twindb.8.gz |
28 | + rm -f support/rpm/twindb.spec |
29 | + rm -rf .build |
30 | |
31 | -build-rpm: rpmmacros |
32 | +archive: |
33 | rm -rf "${build_dir}" |
34 | mkdir -p "${build_dir}/${src_dir}" |
35 | cp -R * "${build_dir}/${src_dir}" |
36 | - tar zcf "${top_dir}/SOURCES/${src_dir}.tar.gz" -C "${build_dir}" "${src_dir}" |
37 | - rpmbuild -ba ${spec} |
38 | + tar zcf "${build_dir}/${src_dir}.tar.gz" -C "${build_dir}" "${src_dir}" |
39 | + |
40 | +# RPM stuff |
41 | +build-rpm: rpmmacros spec archive |
42 | + mkdir -p "${top_dir}/SOURCES/" |
43 | + mkdir -p "${top_dir}/BUILD/" |
44 | + mv "${build_dir}/${src_dir}.tar.gz" "${top_dir}/SOURCES/${src_dir}.tar.gz" |
45 | + rpmbuild --macros=${rpmmacros} -D '%_topdir ${top_dir}' -ba ${spec} |
46 | |
47 | sign-rpm: |
48 | rpm --addsign ${top_dir}/RPMS/noarch/twindb-${client_version}-${client_release}.noarch.rpm |
49 | @@ -59,3 +71,79 @@ |
50 | |
51 | rpmmacros: |
52 | if ! test -f ~/.rpmmacros ; then cp support/rpm/rpmmacros ~/.rpmmacros; fi |
53 | + |
54 | +spec: |
55 | + sed -e 's/@@VERSION@@/${client_version}/' -e 's/@@RELEASE@@/${client_release}/' \ |
56 | + support/rpm/twindb.spec.template > support/rpm/twindb.spec |
57 | + |
58 | +# Debian stuff |
59 | +deb-dependencies: |
60 | + @echo "Checking dependencies" |
61 | + @for p in ${deb_packages}; \ |
62 | + do echo -n "$$p ... " ; \ |
63 | + if test -z "`dpkg -l | grep $$p`"; \ |
64 | + then \ |
65 | + echo "$$p ... NOT installed"; \ |
66 | + apt-get -y install $$p; \ |
67 | + else \ |
68 | + echo "installed"; \ |
69 | + fi ; \ |
70 | + done |
71 | + |
72 | +build-deb: deb-dependencies archive |
73 | + mv "${build_dir}/${src_dir}.tar.gz" "${build_dir}/twindb_${client_version}.orig.tar.gz" |
74 | + cp -R support/deb/debian/ "${build_dir}/${src_dir}" |
75 | + rm -f "${build_dir}/${src_dir}/debian/changelog" |
76 | + @echo "Generating changelog" |
77 | + @export DEBEMAIL="TwinDB Packager (TwinDB packager key) <packager@twindb.com>" ; \ |
78 | + export version=${client_version}-${client_release} ; \ |
79 | + export tags="`bzr tags | sort -nk2 | cut -d" " -f1`" ; \ |
80 | + export last_tag=`bzr tags | sort -nrk2 | head -1 | cut -d" " -f1` ; \ |
81 | + export prev_tag="" ; \ |
82 | + if [ "$$last_tag" != "$$version" ] ; \ |
83 | + then \ |
84 | + echo "Error: Last tag $$last_tag doesn't match current version $$version in Makefile" ; \ |
85 | + echo "Please create tag $$version:" ; \ |
86 | + echo "bzr tag $$version" ; \ |
87 | + exit 1 ; \ |
88 | + fi ; \ |
89 | + cd support/deb/ ; \ |
90 | + for tag in $$tags ; \ |
91 | + do \ |
92 | + echo -n "Version: $$tag. Revisions " ; \ |
93 | + if test -z "$$prev_tag" ; \ |
94 | + then \ |
95 | + start_revno=1 ; \ |
96 | + else \ |
97 | + export start_revno=`bzr tags | grep $$prev_tag | awk '{ print $$2 }'` ; \ |
98 | + export start_revno=$$(( $$start_revno + 1 )); \ |
99 | + fi; \ |
100 | + echo -n "$$start_revno .. " ; \ |
101 | + export end_revno=`bzr tags | grep $$tag | awk '{ print $$2 }'` ; \ |
102 | + echo "$$end_revno" ; \ |
103 | + if ! test -f debian/changelog || test -z "`grep "twindb .*$$tag.*UNRELEASED; urgency=" debian/changelog`"; \ |
104 | + then \ |
105 | + echo "Adding new version $$tag.UNRELEASED to the changelog" ; \ |
106 | + if ! test -f debian/changelog; then export opt_create='--create' ; else export opt_create='' ; fi ; \ |
107 | + echo "dch $$opt_create -v $$tag.UNRELEASED --package twindb --distribution UNRELEASED "New version $$tag"" ; \ |
108 | + dch $$opt_create -v $$tag.UNRELEASED --package twindb --distribution UNRELEASED "New version $$tag" ; \ |
109 | + for revno in `seq $$end_revno -1 $$start_revno`; \ |
110 | + do \ |
111 | + export log_msg="`bzr log -r $$revno --line`" ; \ |
112 | + echo "Adding log entry to version $$tag: $$log_msg" ; \ |
113 | + dch --append "$$log_msg" ; \ |
114 | + done ; \ |
115 | + fi ; \ |
116 | + export prev_tag=$$tag ; \ |
117 | + done ; \ |
118 | + cd - > /dev/null; |
119 | + export distr=`lsb_release -sc` ; \ |
120 | + sed s/UNRELEASED/$$distr/g support/deb/debian/changelog > "${build_dir}/${src_dir}/debian/changelog" |
121 | + cd "${build_dir}/${src_dir}" && debuild -us -uc |
122 | + |
123 | +sign-deb: |
124 | + cd "${build_dir}"; debsign -kpackager@twindb.com *.changes |
125 | + |
126 | +upload-deb: |
127 | + ssh ubuntu@deb.twindb.com "mkdir -p ~/deb/`lsb_release -sc`" |
128 | + scp ${build_dir}/*.changes ${build_dir}/*.dsc ${build_dir}/*.tar.gz ${build_dir}/*.deb ubuntu@deb.twindb.com:~/deb/`lsb_release -sc` |
129 | |
130 | === added file 'support/deb/debian/changelog' |
131 | --- support/deb/debian/changelog 1970-01-01 00:00:00 +0000 |
132 | +++ support/deb/debian/changelog 2015-01-24 21:00:42 +0000 |
133 | @@ -0,0 +1,36 @@ |
134 | +twindb (0.1.32-1.UNRELEASED) UNRELEASED; urgency=low |
135 | + |
136 | + * New version 0.1.32-1 |
137 | + * 14: root 2015-01-19 {0.1.32-1} Version ++ |
138 | + * 13: root 2015-01-19 Use UNRELEASED as target name, otherwise dch |
139 | + throws and error |
140 | + |
141 | + -- TwinDB Packager (TwinDB packager key) <packager@twindb.com> Mon, 19 Jan 2015 05:08:48 -0800 |
142 | + |
143 | +twindb (0.1.31-2.UNRELEASED) UNRELEASED; urgency=low |
144 | + |
145 | + * New version 0.1.31-2 |
146 | + * 12: root 2015-01-19 {0.1.31-2} package version ++ |
147 | + * 11: root 2015-01-19 Include OS codename into debian package version |
148 | + * 10: root 2015-01-18 On lucid sys.path doen't include path where |
149 | + mysql-connector-python installs its modules |
150 | + * 9: root 2015-01-18 show registration hint only if the agent isn't |
151 | + registred |
152 | + * 8: root 2015-01-18 sh-compatible increment is fixed again |
153 | + * 7: root 2015-01-18 Use a template @@CODENAME@@ in changelog. It is |
154 | + replaced by a build script |
155 | + * 6: root 2015-01-18 fix arithmetic expansion error in shell |
156 | + * 5: root 2015-01-18 Make the packager's full name and email match to |
157 | + ones from the packager GPG key |
158 | + * 4: root 2015-01-17 Makefile can build Debian packages |
159 | + * 3: root 2015-01-15 Moved Makefile from twindb project |
160 | + * 2: root 2015-01-15 Fixed Bug #1403183 |
161 | + |
162 | + -- TwinDB Packager (TwinDB packager key) <packager@twindb.com> Mon, 19 Jan 2015 04:47:04 -0800 |
163 | + |
164 | +twindb (0.1.31-1.UNRELEASED) UNRELEASED; urgency=low |
165 | + |
166 | + * New version 0.1.31-1 |
167 | + * 1: Aleksandr Kuzminsky 2015-01-15 {0.1.31-1} Initial import |
168 | + |
169 | + -- TwinDB Packager (TwinDB packager key) <packager@twindb.com> Thu, 15 Jan 2015 20:25:52 -0800 |
170 | |
171 | === removed file 'support/deb/debian/changelog' |
172 | --- support/deb/debian/changelog 2015-01-16 07:41:06 +0000 |
173 | +++ support/deb/debian/changelog 1970-01-01 00:00:00 +0000 |
174 | @@ -1,15 +0,0 @@ |
175 | -twindb (0.0.80-1) testing; urgency=low |
176 | - |
177 | - * Fixes https://bugs.launchpad.net/twindb-client/+bug/1273461 |
178 | - * Package numbering is synced with RPM |
179 | - |
180 | - -- Aleksandr Kuzminsky <packager@twindb.com> Mon, 27 Jan 2014 17:14:01 -0500 |
181 | - |
182 | - |
183 | -twindb (0.0-0.1) testing; urgency=low |
184 | - |
185 | - * Non-maintainer upload. |
186 | - * Initial release. (Closes: #1234) |
187 | - |
188 | - -- Aleksandr Kuzminsky <aleksandr.kuzminsky@twindb.com> Fri, 15 Nov 2013 17:26:15 +0000 |
189 | - |
190 | |
191 | === modified file 'support/deb/debian/control' |
192 | --- support/deb/debian/control 2015-01-16 07:41:06 +0000 |
193 | +++ support/deb/debian/control 2015-01-24 21:00:42 +0000 |
194 | @@ -1,13 +1,20 @@ |
195 | Source: twindb |
196 | -Maintainer: Aleksandr Kuzminsky <packager@twindb.com> |
197 | +Homepage: https://twindb.com |
198 | +Maintainer: TwinDB Packager (TwinDB packager key) <packager@twindb.com> |
199 | Section: database |
200 | Priority: optional |
201 | -Standards-Version: 3.8.4 |
202 | +Standards-Version: 3.9.3 |
203 | Build-Depends: debhelper (>= 7) |
204 | +Vcs-Browser: https://code.launchpad.net/twindb-agent |
205 | +Vcs-Bzr: bzr+ssh://bazaar.launchpad.net/%2Bbranch/twindb-agent/ |
206 | |
207 | Package: twindb |
208 | Architecture: all |
209 | -Depends: ${misc:Depends}, percona-xtrabackup, php5-json | php5-common, php5-cli, gnupg, php5-mcrypt, mysql-server, mysql-client, php5-mysql |
210 | -Description: tool to manage backups of MySQL server |
211 | - This is a TwinDB agent - a tool that takes backups from MySQL server |
212 | - |
213 | +Section: database |
214 | +Priority: optional |
215 | +Depends: ${misc:Depends}, lsof, percona-xtrabackup, gnupg, python (>= 2.6.0), mysql-connector-python (>= 2.0.0) |
216 | +Description: backup and recovery tool for MySQL |
217 | + TwinDB is online backup service for MySQL. |
218 | + It includes scheduler, retention policy manager, storage. |
219 | + Visit us on https://twindb.com to get more details |
220 | +Homepage: https://twindb.com |
221 | |
222 | === modified file 'support/deb/debian/twindb.init' |
223 | --- support/deb/debian/twindb.init 2015-01-16 07:41:06 +0000 |
224 | +++ support/deb/debian/twindb.init 2015-01-24 21:00:42 +0000 |
225 | @@ -23,19 +23,45 @@ |
226 | 'start') |
227 | if test -f $pid_file |
228 | then |
229 | - $0 stop |
230 | + #$0 stop |
231 | + echo "Pid file $pid_file exists." |
232 | + echo "Either another instance of twindb is running or $pid_file is abandoned file." |
233 | + echo "Please stop twindb agent first." |
234 | + echo "$0 stop" |
235 | + exit 1 |
236 | fi |
237 | + echo -n "Starting TwinDB agent ... " |
238 | /usr/bin/twindb --start > /dev/null 2>&1 & |
239 | + echo "OK" |
240 | ;; |
241 | 'stop') |
242 | if test -f $pid_file |
243 | then |
244 | + echo -n "Stopping TwinDB agent ... " |
245 | + pid=`cat "$pid_file"` |
246 | + wait_timeout=300 |
247 | /usr/bin/twindb --stop |
248 | + # Wait till agent exits |
249 | + while kill -0 $pid 2>/dev/null |
250 | + do |
251 | + if [ $wait_timeout -lt 1 ]; then break; fi |
252 | + sleep 1 |
253 | + wait_timeout=$(( $wait_timeout - 1 )) |
254 | + done |
255 | + echo "OK" |
256 | + else |
257 | + echo "Pid file($pid_file) doesn't exist." |
258 | fi |
259 | - ;; |
260 | - 'restart'|'reload'|'force-reload') |
261 | - $0 stop |
262 | - $0 start |
263 | + # Kill all abandoned and hung agents |
264 | + pkill -9 -f /usr/bin/twindb || true |
265 | + ;; |
266 | + 'restart') |
267 | + $0 stop |
268 | + $0 start |
269 | + ;; |
270 | + 'force-reload') |
271 | + $0 stop |
272 | + $0 start |
273 | ;; |
274 | 'status') |
275 | if test -f $pid_file && ! test -z "$(ps -p `cat $pid_file` -o pid=)" |
276 | |
277 | === modified file 'support/deb/debian/twindb.manpages' |
278 | --- support/deb/debian/twindb.manpages 2015-01-16 07:41:06 +0000 |
279 | +++ support/deb/debian/twindb.manpages 2015-01-24 21:00:42 +0000 |
280 | @@ -1,1 +1,1 @@ |
281 | -twindb.man |
282 | +support/twindb.man |
283 | |
284 | === modified file 'support/deb/debian/twindb.postinst' |
285 | --- support/deb/debian/twindb.postinst 2015-01-16 07:41:06 +0000 |
286 | +++ support/deb/debian/twindb.postinst 2015-01-24 21:00:42 +0000 |
287 | @@ -2,18 +2,16 @@ |
288 | |
289 | chmod 755 /usr/bin/twindb |
290 | |
291 | -echo "Please run " |
292 | -echo "" |
293 | -echo "twindb --register <registration code>" |
294 | -echo "" |
295 | -echo "to register the server" |
296 | -echo "The registration code you can find on https://twindb.com" |
297 | - |
298 | -# on saucy mcrypt is not loaded in cli php |
299 | -if test -z "`php -m | grep mcrypt`" |
300 | +if [ "`twindb --is-registered`" != "YES" ] |
301 | then |
302 | - ln -s /etc/php5/conf.d/mcrypt.ini /etc/php5/cli/conf.d/30-mcrypt.ini |
303 | + echo "================================================================================" |
304 | + echo "TwinDB client is installed." |
305 | + echo "Now you need to register this server. To do so run:" |
306 | + echo "" |
307 | + echo "twindb --register <registration code>" |
308 | + echo "" |
309 | + echo "To obtain the registration code follow link https://console.twindb.com/?get_code" |
310 | + echo "================================================================================" |
311 | fi |
312 | - |
313 | #DEBHELPER# |
314 | |
315 | |
316 | === modified file 'support/rpm/rpmmacros' |
317 | --- support/rpm/rpmmacros 2015-01-16 07:41:06 +0000 |
318 | +++ support/rpm/rpmmacros 2015-01-24 21:00:42 +0000 |
319 | @@ -2,5 +2,3 @@ |
320 | %_gpg_name packager@twindb.com |
321 | %vendor TwinDB LLC |
322 | %packager packager@twindb.com |
323 | -%_topdir /root/rpmbuild/ |
324 | -%_tmppath /root/rpmbuild/tmp |
325 | |
326 | === renamed file 'support/rpm/twindb.spec' => 'support/rpm/twindb.spec.template' |
327 | --- support/rpm/twindb.spec 2015-01-16 07:41:06 +0000 |
328 | +++ support/rpm/twindb.spec.template 2015-01-24 21:00:42 +0000 |
329 | @@ -1,6 +1,6 @@ |
330 | Name: twindb |
331 | -Version: 0.1.31 |
332 | -Release: 1 |
333 | +Version: @@VERSION@@ |
334 | +Release: @@RELEASE@@ |
335 | Summary: TwinDB agent for online MySQL backups |
336 | |
337 | Group: Applications/Databases |
338 | @@ -25,6 +25,7 @@ |
339 | |
340 | Requires: gpg |
341 | Requires: tar |
342 | +Requires: lsof |
343 | Requires: chkconfig |
344 | Requires: procps |
345 | Requires: mysql |
346 | |
347 | === modified file 'support/twindb' |
348 | --- support/twindb 2015-01-16 07:41:06 +0000 |
349 | +++ support/twindb 2015-01-24 21:00:42 +0000 |
350 | @@ -26,7 +26,7 @@ |
351 | echo "Either another instance of twindb is running or $pid_file is abandoned file." |
352 | echo "Please stop twindb agent first." |
353 | echo "$0 stop" |
354 | - exit -1 |
355 | + exit 1 |
356 | fi |
357 | echo -n "Starting TwinDB agent ... " |
358 | /usr/bin/twindb --start > /dev/null 2>&1 & |
359 | @@ -44,14 +44,14 @@ |
360 | do |
361 | if [ $wait_timeout -lt 1 ]; then break; fi |
362 | sleep 1 |
363 | - let wait_timeout=$wait_timeout-1 |
364 | + wait_timeout=$(( $wait_timeout - 1 )) |
365 | done |
366 | echo "OK" |
367 | else |
368 | echo "Pid file($pid_file) doesn't exist." |
369 | fi |
370 | # Kill all abandoned and hung agents |
371 | - pkill -9 -f /usr/bin/twindb |
372 | + pkill -9 -f /usr/bin/twindb || true |
373 | ;; |
374 | 'restart') |
375 | $0 stop |
376 | |
377 | === modified file 'twindb.py' |
378 | --- twindb.py 2015-01-15 21:02:14 +0000 |
379 | +++ twindb.py 2015-01-24 21:00:42 +0000 |
380 | @@ -19,7 +19,11 @@ |
381 | import json |
382 | import urllib |
383 | import re |
384 | -import mysql.connector |
385 | +try: |
386 | + import mysql.connector |
387 | +except ImportError: |
388 | + sys.path.insert(0, '/usr/lib/python2.6/site-packages') |
389 | + import mysql.connector |
390 | import tempfile |
391 | import uuid |
392 | |
393 | @@ -109,13 +113,15 @@ |
394 | def emit(self, record): |
395 | global server_id |
396 | global job_id |
397 | + global debug |
398 | + |
399 | request = {} |
400 | request["type"] = "log" |
401 | request["params"] = {} |
402 | if job_id != 0: |
403 | request["params"]["job_id"] = job_id |
404 | request["params"]["msg"] = record.getMessage() |
405 | - if self.log_flag: |
406 | + if self.log_flag and not debug: |
407 | self.log_flag = False |
408 | get_response(request) |
409 | self.log_flag = True |
410 | @@ -145,6 +151,38 @@ |
411 | -p | --password password MySQL password") |
412 | return |
413 | |
414 | + |
415 | +def get_mysql_connection(user = None, passwd = None): |
416 | + global mysql_user |
417 | + global mysql_password |
418 | + |
419 | + try: |
420 | + if user == None: |
421 | + user = mysql_user |
422 | + if passwd == None: |
423 | + passwd = mysql_password |
424 | + mysql_option_files = [] |
425 | + unix_socket = get_unix_socket() |
426 | + conn = mysql.connector.connect() |
427 | + if user != None: |
428 | + for f in ['/etc/mysql/my.cnf', '/etc/my.cnf', '/root/.my.cnf']: |
429 | + if os.path.exists(f): |
430 | + mysql_option_files.append(f) |
431 | + if mysql_option_files: |
432 | + conn = mysql.connector.connect(option_files = mysql_option_files, unix_socket = unix_socket) |
433 | + logger.debug("Connected to MySQL as '%s'@'localhost' with options files %r" % (conn.user, mysql_option_files) ) |
434 | + if not conn.is_connected(): |
435 | + conn = mysql.connector.connect(user = user, passwd = passwd, unix_socket = unix_socket) |
436 | + logger.debug("Connected to MySQL as %s@localhost " % conn.user) |
437 | + except mysql.connector.Error as err: |
438 | + logger.error("Can not connect to local MySQL server") |
439 | + logger.error("MySQL said: %s" % err.msg) |
440 | + return None |
441 | + except: |
442 | + logger.error("Can not connect to local MySQL server") |
443 | + logger.error("Unexpected error: %s,%s" % sys.exc_info()[:2]); |
444 | + return None |
445 | + return conn |
446 | # Checks if TwinDB API public key is installed |
447 | # Returns |
448 | # True - if the key is installed |
449 | @@ -475,8 +513,7 @@ |
450 | |
451 | uri = "api.php" |
452 | response_body = None |
453 | - logger.debug("Enter get_response(uri=" + uri + ") with request:") |
454 | - logger.debug(request) |
455 | + logger.debug("Enter get_response(uri=" + uri + ")") |
456 | if proto == "http": |
457 | conn = httplib.HTTPConnection(host) |
458 | elif proto == "https": |
459 | @@ -486,8 +523,7 @@ |
460 | try: |
461 | url = proto + "://" + host + "/" + api_dir + "/" + uri |
462 | conn.connect() |
463 | - logger.debug("Sending to " + host + ":") |
464 | - logger.debug(request) |
465 | + logger.debug("Sending to " + host + ": %s" % json.dumps(request, indent=4, sort_keys=True)) |
466 | data_json = json.dumps(request) |
467 | data_json_enc = encrypt(data_json) |
468 | data_json_enc_urlenc = urllib.urlencode({'data': data_json_enc}) |
469 | @@ -502,7 +538,6 @@ |
470 | http_response = conn.getresponse() |
471 | if(http_response.status == 200): |
472 | response_body = http_response.read() |
473 | - logger.debug("Response from server: %s" % response_body); |
474 | if(len(response_body) == 0): |
475 | return None |
476 | url = "%(proto)s://%(host)s/%(api_dir)s/%(uri)s" % { |
477 | @@ -511,9 +546,16 @@ |
478 | "api_dir": api_dir, |
479 | "uri": uri |
480 | } |
481 | + d = json.JSONDecoder() |
482 | + try: |
483 | + json_object = json.loads(response_body) |
484 | + except ValueError as e: |
485 | + msg = response_body |
486 | + else: |
487 | + msg = json.dumps(d.decode(response_body), indent=4, sort_keys=True) |
488 | logger.debug("Response from %(url)s : %(resp)s" % { |
489 | "url": url, |
490 | - "resp": response_body |
491 | + "resp": msg |
492 | }) |
493 | else: |
494 | logger.error("HTTP error %d %s" % (http_response.status, http_response.reason)) |
495 | @@ -575,7 +617,6 @@ |
496 | response_body_decoded = d.decode(response_body) |
497 | if response_body_decoded: |
498 | msg_enc = response_body_decoded["response"] |
499 | - logger.debug("Reply from server %s" % msg_enc) |
500 | msg_pt = d.decode(decrypt(msg_enc)) |
501 | config = msg_pt["data"] |
502 | logger.info("Got config:\n%s" % json.dumps(sanitize_config(config), indent=4, sort_keys=True)) |
503 | @@ -634,10 +675,7 @@ |
504 | logger.error("Unexpected error: %s,%s" % sys.exc_info()[:2]) |
505 | return |
506 | try: |
507 | - unix_socket = get_unix_socket() |
508 | - logger.debug("Connecting to MySQL as '%s'@'localhost' with password '%s' via socket %s" % |
509 | - (mysql_user, mysql_password, unix_socket)) |
510 | - con = mysql.connector.connect(user=mysql_user, passwd=mysql_password, unix_socket = unix_socket) |
511 | + con = get_mysql_connection(user=mysql_user, passwd=mysql_password) |
512 | cursor = con.cursor() |
513 | query = "SELECT PRIVILEGE_TYPE FROM information_schema.USER_PRIVILEGES" |
514 | logger.debug("Sending query : %s" % query) |
515 | @@ -742,15 +780,18 @@ |
516 | d = json.JSONDecoder() |
517 | response_body_decoded = d.decode(response_body) |
518 | if response_body_decoded: |
519 | - msg_enc = response_body_decoded["response"] |
520 | - logger.debug("Reply from server %s" % msg_enc) |
521 | - msg_pt = d.decode(decrypt(msg_enc)) |
522 | - registration_status = msg_pt["data"] |
523 | - logger.debug("Got registration status:\n%s" % json.dumps(registration_status, indent=4, sort_keys=True)) |
524 | - if msg_pt["error"]: |
525 | - logger.error(msg_pt["error"]) |
526 | - exit_on_error(msg_pt["error"]) |
527 | - return registration_status["registered"] |
528 | + if "response" in response_body_decoded: |
529 | + msg_enc = response_body_decoded["response"] |
530 | + msg_pt = d.decode(decrypt(msg_enc)) |
531 | + registration_status = msg_pt["data"] |
532 | + logger.debug("Got registration status:\n%s" % json.dumps(registration_status, indent=4, sort_keys=True)) |
533 | + if msg_pt["error"]: |
534 | + logger.error(msg_pt["error"]) |
535 | + exit_on_error(msg_pt["error"]) |
536 | + return registration_status["registered"] |
537 | + else: |
538 | + logger.debug("No valid response from dispatcher. Conseder agent unregistered") |
539 | + return False |
540 | except exceptions.KeyError as err: |
541 | logger.error("Failed to decode %s" % response_body); |
542 | exit_on_error(traceback.format_exc()) |
543 | @@ -939,25 +980,15 @@ |
544 | return |
545 | |
546 | def get_slave_status(): |
547 | - global mysql_user |
548 | - global mysql_password |
549 | |
550 | result = dict() |
551 | # Read master host |
552 | try: |
553 | - mysql_option_files = [] |
554 | - for f in ['/etc/mysql/my.cnf', '/etc/my.cnf', '/root/.my.cnf']: |
555 | - if os.path.exists(f): |
556 | - mysql_option_files.append(f) |
557 | - conn = mysql.connector.connect(option_files=mysql_option_files) |
558 | - if not conn.is_connected(): |
559 | - conn = mysql.connector.connect(user=mysql_user, passwd=mysql_password) |
560 | - except mysql.connector.Error as err: |
561 | - logger.error("Can not connect to local MySQL server.") |
562 | - logger.error("MySQL said: %s" % err.msg) |
563 | - exit_on_error(traceback.format_exc()) |
564 | - try: |
565 | - cursor = conn.cursor(dictionary=True) |
566 | + conn = get_mysql_connection() |
567 | + if conn: |
568 | + cursor = conn.cursor(dictionary=True) |
569 | + else: |
570 | + return None |
571 | |
572 | result["mysql_server_id"] = None |
573 | result["mysql_master_server_id"] = None |
574 | @@ -981,9 +1012,9 @@ |
575 | cursor.close() |
576 | conn.close() |
577 | except: |
578 | - logger.error("Can not read Master_host from MySQL") |
579 | + logger.error("Could not read Master_host from MySQL") |
580 | logger.error("Unexpected error: %s,%s" % sys.exc_info()[:2]); |
581 | - exit_on_error(traceback.format_exc()) |
582 | + return None |
583 | return result |
584 | |
585 | # Registers this server in TwinDB dispatcher |
586 | @@ -1042,6 +1073,9 @@ |
587 | cmd += "| awk '{ print $2}'" |
588 | cmd += "| awk -F/ '{ print $1}'" |
589 | ss = get_slave_status() |
590 | + if ss is None: |
591 | + logger.error("Could not get slave status on this server") |
592 | + exit_on_error() |
593 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) |
594 | local_ip = list() |
595 | for row in p.stdout: |
596 | @@ -1065,8 +1099,6 @@ |
597 | "local_ip": local_ip |
598 | } |
599 | } |
600 | - logger.debug("Registration request:") |
601 | - logger.debug(data) |
602 | response = get_response(data) |
603 | if response <> None: |
604 | jd = json.JSONDecoder() |
605 | @@ -1091,18 +1123,7 @@ |
606 | |
607 | config = get_config() |
608 | try: |
609 | - mysql_option_files = [] |
610 | - for f in ['/etc/mysql/my.cnf', '/etc/my.cnf', '/root/.my.cnf']: |
611 | - if os.path.exists(f): |
612 | - mysql_option_files.append(f) |
613 | - conn = mysql.connector.connect(option_files=mysql_option_files) |
614 | - if not conn.is_connected(): |
615 | - conn = mysql.connector.connect(user=mysql_user, passwd=mysql_password) |
616 | - except mysql.connector.Error as err: |
617 | - logger.error("Can not connect to local MySQL server.") |
618 | - logger.error("MySQL said: %s" % err.msg) |
619 | - exit_on_error(traceback.format_exc()) |
620 | - try: |
621 | + conn = get_mysql_connection() |
622 | q = "GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT, SUPER, CREATE TABLESPACE" |
623 | q += " ON *.* TO %s@'localhost' IDENTIFIED BY %s" |
624 | cursor = conn.cursor() |
625 | @@ -1218,16 +1239,13 @@ |
626 | # True - if all necessary privileges are granted |
627 | # False - if not all necessary privilegers are granted |
628 | |
629 | -def check_mysql_permissions(config, job): |
630 | +def check_mysql_permissions(config): |
631 | global logger |
632 | |
633 | try: |
634 | logger.info("Checking if '%s'@'localhost' has enough rights to backup MySQL" % config["mysql_user"]) |
635 | result = False |
636 | - unix_socket = get_unix_socket() |
637 | - logger.debug("Connecting to MySQL as '%s'@'localhost' with password '%s' via socket %s" % |
638 | - (config["mysql_user"], config["mysql_password"], unix_socket)) |
639 | - con = mysql.connector.connect(user=config["mysql_user"], passwd=config["mysql_password"], unix_socket = unix_socket) |
640 | + con = get_mysql_connection(user=config["mysql_user"], passwd=config["mysql_password"]) |
641 | required_priv = ["RELOAD", "LOCK TABLES", "REPLICATION CLIENT", "SUPER", "CREATE TABLESPACE"] |
642 | for priv in required_priv: |
643 | cursor = con.cursor() |
644 | @@ -1363,6 +1381,7 @@ |
645 | xtrabackup_cmd.append("--stream=xbstream") |
646 | xtrabackup_cmd.append("--user=%s" % mysql_user) |
647 | xtrabackup_cmd.append("--password=%s" % mysql_password) |
648 | + xtrabackup_cmd.append("--socket=%s" % get_unix_socket()) |
649 | xtrabackup_cmd.append("--slave-info") |
650 | xtrabackup_cmd.append("--safe-slave-backup") |
651 | xtrabackup_cmd.append("--safe-slave-backup-timeout=3600") |
652 | @@ -1457,10 +1476,9 @@ |
653 | try: |
654 | f, extra_config = tempfile.mkstemp() |
655 | os.write(f, "[mysqld]\n") |
656 | - mysql_user = config["mysql_user"] |
657 | - mysql_password = config["mysql_password"] |
658 | - unix_socket = get_unix_socket() |
659 | - con = mysql.connector.connect(user = mysql_user, passwd = mysql_password, unix_socket = unix_socket) |
660 | + con = get_mysql_connection( |
661 | + user = config["mysql_user"], |
662 | + passwd = config["mysql_password"]) |
663 | cur = con.cursor() |
664 | cur.execute("SELECT @@datadir") |
665 | row = cur.fetchone() |
666 | @@ -1880,7 +1898,7 @@ |
667 | socket = "" |
668 | try: |
669 | cmd = [ |
670 | - "lsof", "-U", "-c", "mysqld", "-a", "-F", "n" |
671 | + "lsof", "-U", "-c", "/^mysqld$/", "-a", "-F", "n" |
672 | ] |
673 | p = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.PIPE) |
674 | cout, cerr = p.communicate() |
675 | @@ -1997,8 +2015,9 @@ |
676 | |
677 | # Reports error removes pid and exits |
678 | |
679 | -def exit_on_error(tb): |
680 | - logger.debug(tb) |
681 | +def exit_on_error(tb = None): |
682 | + if tb is not None: |
683 | + logger.debug(tb) |
684 | remove_pid() |
685 | sys.exit(2) |
686 | |
687 | @@ -2020,7 +2039,7 @@ |
688 | os.kill(pid, signal.SIGTERM) |
689 | wait_pid(pid, 300) |
690 | f.close() |
691 | - except OSError: |
692 | + except OSError as err: |
693 | logger.error("Couldn't kill process %d" % pid) |
694 | logger.error(err) |
695 | exit_on_error(traceback.format_exc()) |
696 | @@ -2090,7 +2109,7 @@ |
697 | global job_id |
698 | |
699 | try: |
700 | - if not check_mysql_permissions(config, job): |
701 | + if not check_mysql_permissions(config): |
702 | return False |
703 | if job["start_scheduled"] == None: |
704 | logger.error("Job start time isn't set") |
705 | @@ -2150,6 +2169,8 @@ |
706 | global logger |
707 | global mysql_user |
708 | global mysql_password |
709 | + global debug |
710 | + |
711 | # Read or generate server id |
712 | if os.path.exists(init_config): |
713 | try: |
714 | @@ -2205,6 +2226,7 @@ |
715 | elif opt in ['-p', '--password']: |
716 | mysql_password = arg |
717 | elif opt == '-g': |
718 | + debug = True |
719 | logger.setLevel(logging.DEBUG) |
720 | elif opt == '--start': |
721 | action = "start" |
722 | @@ -2220,11 +2242,7 @@ |
723 | elif opt == '--backup': |
724 | action = "backup" |
725 | elif opt == '--is-registered': |
726 | - if is_registered(): |
727 | - print("YES") |
728 | - else: |
729 | - print("NO") |
730 | - sys.exit(0) |
731 | + action = "is-registered" |
732 | elif opt in ["-h", "--help"]: |
733 | usage() |
734 | sys.exit(0) |
735 | @@ -2265,6 +2283,12 @@ |
736 | if not action_handler_backup(): |
737 | logger.error("Failed to take backup") |
738 | sys.exit(2) |
739 | + elif action == "is-registered": |
740 | + if is_registered(): |
741 | + print("YES") |
742 | + else: |
743 | + print("NO") |
744 | + sys.exit(0) |
745 | else: |
746 | # If we got there print usage() and exit |
747 | logger.error("Neither --start nor --stop nor --register is specified") |
The Makefile target "build-deb" builds the package in the .build directory. But the "build-rpm" package builds the rpm in the directory /root/rpmbuild/ Should we use identical directories for both targets?