├── .drone.jsonnet
├── .gitignore
├── LICENSE
├── README.md
├── bin
├── initdb.sh
├── nextcloud-config
├── nextcloud-config.php
├── nextcloud-cron
├── occ-runner
├── pg_dumpall.sh
├── php-runner
├── php.sh
├── psql.sh
├── service.nginx.sh
├── service.php-fpm.sh
├── service.postgresql.sh
└── service.redis.sh
├── build.sh
├── config
├── config.php
├── env
├── fastcgi_params
├── nginx.conf
├── php-fpm.conf
├── php.ini
├── postgresql.conf
└── redis.conf
├── download.sh
├── hooks
├── access-change
├── access-change.py
├── backup-pre-stop
├── installer.py
├── octools.py
├── postgres.py
├── restore-post-start
├── restore-pre-start
├── storage-change
└── storage-change.py
├── meta
├── hooks
│ ├── configure
│ ├── install
│ ├── post-refresh
│ └── pre-refresh
└── snap.yaml
├── nginx
├── build.sh
└── nginx.sh
├── package.sh
├── php
├── Dockerfile
├── build.sh
├── php-fpm.sh
└── php.sh
├── postgresql
├── Dockerfile
├── bin
│ ├── initdb.sh
│ ├── pg_ctl.sh
│ ├── pg_dumpall.sh
│ └── psql.sh
├── build.sh
└── pgbin
│ ├── pg_dump
│ └── postgres
├── python
├── Dockerfile
├── build.sh
├── python
└── requirements.txt
├── redis
├── bin
│ └── redis.sh
├── build.sh
└── test.sh
└── test
├── .gitignore
├── __init__.py
├── conftest.py
├── deps.sh
├── requirements.txt
├── test.odt
├── test.py
├── ui.py
└── upgrade.py
/.drone.jsonnet:
--------------------------------------------------------------------------------
1 | local name = "nextcloud";
2 | local browser = "chrome";
3 | local nextcloud = "31.0.5";
4 | local redis = "7.0.15";
5 | local nginx = "1.24.0";
6 | local platform = '25.02';
7 | local selenium = '4.21.0-20240517';
8 | local deployer = 'https://github.com/syncloud/store/releases/download/4/syncloud-release';
9 | local distro_default = "buster";
10 | local distros = ["bookworm", "buster"];
11 |
12 | local build(arch, test_ui, dind) = [{
13 | kind: "pipeline",
14 | type: "docker",
15 | name: arch,
16 | platform: {
17 | os: "linux",
18 | arch: arch
19 | },
20 | steps: [
21 | {
22 | name: "version",
23 | image: "debian:buster-slim",
24 | commands: [
25 | "echo $DRONE_BUILD_NUMBER > version"
26 | ]
27 | },
28 | {
29 | name: "download",
30 | image: "debian:buster-slim",
31 | commands: [
32 | "./download.sh " + nextcloud
33 | ]
34 | },
35 | {
36 | name: "nginx",
37 | image: "docker:" + dind,
38 | commands: [
39 | "./nginx/build.sh " + nginx
40 | ],
41 | volumes: [
42 | {
43 | name: "dockersock",
44 | path: "/var/run"
45 | }
46 | ]
47 | },
48 |
49 | {
50 | name: "redis",
51 | image: "redis:" + redis,
52 | commands: [
53 | "./redis/build.sh"
54 | ]
55 | },
56 | {
57 | name: "redis test",
58 | image: "debian:buster-slim",
59 | commands: [
60 | "./redis/test.sh"
61 | ]
62 | },
63 | {
64 | name: "postgresql",
65 | image: "docker:" + dind,
66 | commands: [
67 | "./postgresql/build.sh"
68 | ],
69 | volumes: [
70 | {
71 | name: "dockersock",
72 | path: "/var/run"
73 | }
74 | ]
75 | },
76 | {
77 | name: "python",
78 | image: "docker:" + dind,
79 | commands: [
80 | "./python/build.sh"
81 | ],
82 | volumes: [
83 | {
84 | name: "dockersock",
85 | path: "/var/run"
86 | }
87 | ]
88 | },
89 | {
90 | name: "php",
91 | image: "docker:" + dind,
92 | commands: [
93 | "./php/build.sh"
94 | ],
95 | volumes: [
96 | {
97 | name: "dockersock",
98 | path: "/var/run"
99 | }
100 | ]
101 | },
102 | {
103 | name: "build",
104 | image: "debian:buster-slim",
105 | commands: [
106 | "./build.sh"
107 | ]
108 | },
109 | {
110 | name: "package",
111 | image: "debian:buster-slim",
112 | commands: [
113 | "VERSION=$(cat version)",
114 | "./package.sh " + name + " $VERSION "
115 | ]
116 | }] + [
117 | {
118 | name: "test " + distro,
119 | image: "python:3.8-slim-buster",
120 | commands: [
121 | "APP_ARCHIVE_PATH=$(realpath $(cat package.name))",
122 | "cd test",
123 | "./deps.sh",
124 | "py.test -x -s test.py --distro=" + distro + " --domain=" + distro + ".com --app-archive-path=$APP_ARCHIVE_PATH --device-host=" + name + "." + distro + ".com --app=" + name + " --arch=" + arch
125 | ]
126 | } for distro in distros
127 | ] + ( if test_ui then [
128 | {
129 | name: "selenium",
130 | image: "selenium/standalone-" + browser + ":" + selenium,
131 | detach: true,
132 | environment: {
133 | SE_NODE_SESSION_TIMEOUT: "999999",
134 | START_XVFB: "true"
135 | },
136 | volumes: [{
137 | name: "shm",
138 | path: "/dev/shm"
139 | }],
140 | commands: [
141 | "cat /etc/hosts",
142 | "getent hosts " + name + ".buster.com | sed 's/" + name +".buster.com/auth.buster.com/g' | sudo tee -a /etc/hosts",
143 | "cat /etc/hosts",
144 | "/opt/bin/entry_point.sh"
145 | ]
146 | },
147 |
148 | {
149 | name: "selenium-video",
150 | image: "selenium/video:ffmpeg-4.3.1-20220208",
151 | detach: true,
152 | environment: {
153 | DISPLAY_CONTAINER_NAME: "selenium",
154 | FILE_NAME: "video.mkv"
155 | },
156 | volumes: [
157 | {
158 | name: "shm",
159 | path: "/dev/shm"
160 | },
161 | {
162 | name: "videos",
163 | path: "/videos"
164 | }
165 | ]
166 | },
167 | {
168 | name: "test-ui",
169 | image: "python:3.8-slim-buster",
170 | commands: [
171 | "cd test",
172 | "./deps.sh",
173 | "py.test -x -s ui.py --distro=buster --ui-mode=desktop --domain=buster.com --device-host=" + name + ".buster.com --app=" + name + " --browser=" + browser,
174 | ],
175 | volumes: [{
176 | name: "videos",
177 | path: "/videos"
178 | }]
179 | }
180 |
181 | ] else [] ) +[
182 | {
183 | name: "test-upgrade",
184 | image: "python:3.8-slim-buster",
185 | commands: [
186 | "APP_ARCHIVE_PATH=$(realpath $(cat package.name))",
187 | "cd test",
188 | "./deps.sh",
189 | "py.test -x -s upgrade.py --distro=buster --ui-mode=desktop --domain=buster.com --app-archive-path=$APP_ARCHIVE_PATH --device-host=" + name + ".buster.com --app=" + name + " --browser=" + browser,
190 | ]
191 | },
192 | {
193 | name: "upload",
194 | image: "debian:buster-slim",
195 | environment: {
196 | AWS_ACCESS_KEY_ID: {
197 | from_secret: "AWS_ACCESS_KEY_ID"
198 | },
199 | AWS_SECRET_ACCESS_KEY: {
200 | from_secret: "AWS_SECRET_ACCESS_KEY"
201 | },
202 | SYNCLOUD_TOKEN: {
203 | from_secret: "SYNCLOUD_TOKEN"
204 | }
205 | },
206 | commands: [
207 | "PACKAGE=$(cat package.name)",
208 | "apt update && apt install -y wget",
209 | "wget " + deployer + "-" + arch + " -O release --progress=dot:giga",
210 | "chmod +x release",
211 | "./release publish -f $PACKAGE -b $DRONE_BRANCH"
212 | ],
213 | when: {
214 | branch: ["stable", "master"],
215 | event: [ "push" ]
216 | }
217 | },
218 | {
219 | name: "promote",
220 | image: "debian:buster-slim",
221 | environment: {
222 | AWS_ACCESS_KEY_ID: {
223 | from_secret: "AWS_ACCESS_KEY_ID"
224 | },
225 | AWS_SECRET_ACCESS_KEY: {
226 | from_secret: "AWS_SECRET_ACCESS_KEY"
227 | },
228 | SYNCLOUD_TOKEN: {
229 | from_secret: "SYNCLOUD_TOKEN"
230 | }
231 | },
232 | commands: [
233 | "apt update && apt install -y wget",
234 | "wget " + deployer + "-" + arch + " -O release --progress=dot:giga",
235 | "chmod +x release",
236 | "./release promote -n " + name + " -a $(dpkg --print-architecture)"
237 | ],
238 | when: {
239 | branch: ["stable"],
240 | event: ["push"]
241 | }
242 | },
243 | {
244 | name: "artifact",
245 | image: "appleboy/drone-scp:1.6.4",
246 | settings: {
247 | host: {
248 | from_secret: "artifact_host"
249 | },
250 | username: "artifact",
251 | key: {
252 | from_secret: "artifact_key"
253 | },
254 | timeout: "2m",
255 | command_timeout: "2m",
256 | target: "/home/artifact/repo/" + name + "/${DRONE_BUILD_NUMBER}-" + arch,
257 | source: "artifact/*",
258 | strip_components: 1
259 | },
260 | when: {
261 | status: [ "failure", "success" ],
262 | event: [ "push" ]
263 | }
264 | }
265 | ],
266 | trigger: {
267 | event: [
268 | "push",
269 | "pull_request"
270 | ]
271 | },
272 | services: [
273 | {
274 | name: "docker",
275 | image: "docker:" + dind,
276 | privileged: true,
277 | volumes: [
278 | {
279 | name: "dockersock",
280 | path: "/var/run"
281 | }
282 | ]
283 | }] + [
284 | {
285 | name: name + "."+distro+".com",
286 | image: "syncloud/platform-"+distro+"-" + arch + ":" + platform,
287 | privileged: true,
288 | volumes: [
289 | {
290 | name: "dbus",
291 | path: "/var/run/dbus"
292 | },
293 | {
294 | name: "dev",
295 | path: "/dev"
296 | }
297 | ]
298 | } for distro in distros
299 | ],
300 | volumes: [
301 | {
302 | name: "dbus",
303 | host: {
304 | path: "/var/run/dbus"
305 | }
306 | },
307 | {
308 | name: "dev",
309 | host: {
310 | path: "/dev"
311 | }
312 | },
313 | {
314 | name: "shm",
315 | temp: {}
316 | },
317 | {
318 | name: "dockersock",
319 | temp: {}
320 | },
321 | {
322 | name: "videos",
323 | temp: {}
324 | },
325 | ]
326 | }];
327 |
328 | build("amd64", true, "20.10.21-dind") +
329 | build("arm64", false, "19.03.8-dind")
330 |
331 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | dist
3 | *.pyc
4 | *.egg-info
5 | build
6 | *.tar.gz
7 | *.tar.bz2
8 | rootfs
9 | *.log
10 | *.iml
11 | log
12 | .cache
13 | lib
14 | src/version
15 | .coin.cache
16 | geckodriver
17 | *.test.download
18 | *.test.upload
19 | test.file*
20 | venv
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | App porting guide: https://github.com/syncloud/platform/wiki/App-porting-guide
--------------------------------------------------------------------------------
/bin/initdb.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
4 |
5 | if [ -z "$SNAP_COMMON" ]; then
6 | echo "SNAP_COMMON environment variable must be set"
7 | exit 1
8 | fi
9 |
10 | # shellcheck source=config/env
11 | . "${SNAP_DATA}/config/env"
12 |
13 | if [[ "$(whoami)" == "nextcloud" ]]; then
14 | ${DIR}/postgresql/bin/initdb.sh "$@"
15 | else
16 | sudo -E -H -u nextcloud ${DIR}/postgresql/bin/initdb.sh "$@"
17 | fi
18 |
--------------------------------------------------------------------------------
/bin/nextcloud-config:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
4 | ${DIR}/bin/php-runner -f ${DIR}/bin/nextcloud-config.php "$@"
5 |
--------------------------------------------------------------------------------
/bin/nextcloud-config.php:
--------------------------------------------------------------------------------
1 | 2) {
5 | if ($argc == 3) {
6 | $value = $argv[2];
7 | if ($value === 'true')
8 | $value = true;
9 | if ($value === 'false')
10 | $value = false;
11 | } else
12 | $value = array_slice($argv, 2);
13 | echo("setting ".$argv[1]." = ".print_r($value, true)."\n");
14 | \OC::$server->getConfig()->setSystemValue($argv[1], $value);
15 | } else {
16 | echo("usage: ".$argv[0]." key value1 [value2] [value3] ...\n");
17 | exit(1);
18 | }
19 |
--------------------------------------------------------------------------------
/bin/nextcloud-cron:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
4 | ${DIR}/bin/php-runner -f ${DIR}/nextcloud/cron.php
5 |
--------------------------------------------------------------------------------
/bin/occ-runner:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
4 | ${DIR}/bin/php-runner ${DIR}/nextcloud/occ "$@"
5 |
--------------------------------------------------------------------------------
/bin/pg_dumpall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
4 |
5 | if [ -z "$SNAP_COMMON" ]; then
6 | echo "SNAP_COMMON environment variable must be set"
7 | exit 1
8 | fi
9 |
10 | # shellcheck source=config/env
11 | . "${SNAP_DATA}/config/env"
12 |
13 | if [[ "$(whoami)" == "nextcloud" ]]; then
14 | ${DIR}/postgresql/bin/pg_dumpall.sh -p ${PSQL_PORT} -h ${PSQL_DATABASE} "$@"
15 | else
16 | sudo -E -H -u nextcloud ${DIR}/postgresql/bin/pg_dumpall.sh -p ${PSQL_PORT} -h ${PSQL_DATABASE} "$@"
17 | fi
18 |
--------------------------------------------------------------------------------
/bin/php-runner:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
4 |
5 | if [[ "$(whoami)" == "nextcloud" ]]; then
6 | ${DIR}/php.sh "$@"
7 | else
8 | sudo -H -u nextcloud ${DIR}/php.sh "$@"
9 | fi
10 |
--------------------------------------------------------------------------------
/bin/php.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
3 | SNAP_DATA=/var/snap/nextcloud/current
4 | export LANG=en_US.UTF-8
5 | export LC_ALL=en_US.UTF-8
6 | export LC_ALL=en_US.UTF-8
7 | export LC_TIME=en_US.UTF-8
8 | export NEXTCLOUD_CONFIG_DIR=${SNAP_DATA}/nextcloud/config
9 | exec $DIR/php/bin/php.sh -c ${SNAP_DATA}/config/php.ini "$@"
10 |
--------------------------------------------------------------------------------
/bin/psql.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
4 |
5 | if [ -z "$SNAP_COMMON" ]; then
6 | echo "SNAP_COMMON environment variable must be set"
7 | exit 1
8 | fi
9 |
10 | # shellcheck source=config/env
11 | . "${SNAP_DATA}/config/env"
12 |
13 | if [[ "$(whoami)" == "nextcloud" ]]; then
14 | ${DIR}/postgresql/bin/psql.sh -p ${PSQL_PORT} -h ${PSQL_DATABASE} "$@"
15 | else
16 | sudo -E -H -u nextcloud ${DIR}/postgresql/bin/psql.sh -p ${PSQL_PORT} -h ${PSQL_DATABASE} "$@"
17 | fi
18 |
--------------------------------------------------------------------------------
/bin/service.nginx.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
4 |
5 | /bin/rm -f ${SNAP_COMMON}/web.socket
6 | /bin/rm -f ${SNAP_COMMON}/log/nginx*.log
7 | exec ${DIR}/nginx/bin/nginx.sh -c ${SNAP_DATA}/config/nginx.conf -p ${DIR}/nginx -e stderr
8 |
--------------------------------------------------------------------------------
/bin/service.php-fpm.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
4 |
5 | if [[ -z "$1" ]]; then
6 | echo "usage $0 [start]"
7 | exit 1
8 | fi
9 |
10 | case $1 in
11 | start)
12 | exec $DIR/php/bin/php-fpm.sh -y ${SNAP_DATA}/config/php-fpm.conf -c ${SNAP_DATA}/config/php.ini
13 | ;;
14 | post-start)
15 | timeout 5 /bin/bash -c 'until [ -S '${SNAP_COMMON}'/log/php5-fpm.sock ]; do echo "waiting for ${SNAP_COMMON}/log/php5-fpm.sock"; sleep 1; done'
16 | ;;
17 | *)
18 | echo "not valid command"
19 | exit 1
20 | ;;
21 | esac
22 |
--------------------------------------------------------------------------------
/bin/service.postgresql.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
4 |
5 | if [[ -z "$1" ]]; then
6 | echo "usage $0 [start]"
7 | exit 1
8 | fi
9 | # shellcheck source=config/env
10 | . "${SNAP_DATA}/config/env"
11 |
12 | case $1 in
13 | start)
14 | exec ${DIR}/postgresql/bin/pg_ctl.sh -w -s -D ${PSQL_DATABASE} start
15 | ;;
16 | reload)
17 | exec ${DIR}/postgresql/bin/pg_ctl.sh -s -D ${PSQL_DATABASE} reload
18 | ;;
19 | stop)
20 | exec ${DIR}/postgresql/bin/pg_ctl.sh -s -D ${PSQL_DATABASE} stop -m fast
21 | ;;
22 | *)
23 | echo "not valid command"
24 | exit 1
25 | ;;
26 | esac
27 |
--------------------------------------------------------------------------------
/bin/service.redis.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
3 | exec $DIR/redis/bin/redis.sh ${SNAP_DATA}/config/redis.conf
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 |
3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
4 | cd ${DIR}
5 |
6 | BUILD_DIR=${DIR}/build/snap
7 |
8 | cp -r bin ${BUILD_DIR}
9 | cp -r config ${BUILD_DIR}
10 | cp -r hooks ${BUILD_DIR}
11 | rm -rf ${BUILD_DIR}/nextcloud/config
12 | ls -la ${BUILD_DIR}/nextcloud/apps
13 |
14 | #disable internal updates as they break us
15 | rm -r ${BUILD_DIR}/nextcloud/apps/updatenotification
16 | cat ${BUILD_DIR}/nextcloud/.user.ini
17 | sed -i 's/upload_max_filesize=.*/upload_max_filesize=10G/g' ${BUILD_DIR}/nextcloud/.user.ini
18 | sed -i 's/post_max_size=.*/post_max_size=10G/g' ${BUILD_DIR}/nextcloud/.user.ini
19 | ln -s /var/snap/nextcloud/current/extra-apps ${BUILD_DIR}/nextcloud/extra-apps
20 |
--------------------------------------------------------------------------------
/config/config.php:
--------------------------------------------------------------------------------
1 | '{{ common_dir }}',
4 | 'check_data_directory_permissions' => false,
5 | 'log_type' => 'syslog',
6 | 'logfile' => '',
7 | 'apps_paths' => array(
8 | array(
9 | 'path'=> '{{ app_dir }}/nextcloud/apps',
10 | 'url' => '/apps',
11 | 'writable' => false,
12 | ),
13 | array(
14 | 'path'=> '{{ app_dir }}/nextcloud/extra-apps',
15 | 'url' => '/extra-apps',
16 | 'writable' => true,
17 | ),
18 | ),
19 | 'enable_previews' => true,
20 | 'enabledPreviewProviders' =>
21 | array (
22 | 'OC\Preview\Movie',
23 | 'OC\Preview\PNG',
24 | 'OC\Preview\JPEG',
25 | 'OC\Preview\GIF',
26 | 'OC\Preview\BMP',
27 | 'OC\Preview\XBitmap',
28 | 'OC\Preview\MP3',
29 | 'OC\Preview\MP4',
30 | 'OC\Preview\TXT',
31 | 'OC\Preview\MarkDown',
32 | 'OC\Preview\PDF'
33 | ),
34 | 'bulkupload.enabled' => false,
35 | 'memcache.local' => '\OC\Memcache\APCu',
36 | 'memcache.distributed' => '\OC\Memcache\Redis',
37 | 'memcache.locking' => '\OC\Memcache\Redis',
38 | 'redis' => [
39 | 'host' => '/var/snap/nextcloud/current/redis.sock',
40 | 'port' => 0,
41 | ],
42 | 'maintenance_window_start' => 1,
43 | 'allow_local_remote_servers' => true,
44 | );
45 |
--------------------------------------------------------------------------------
/config/env:
--------------------------------------------------------------------------------
1 | export PSQL_PORT={{ db_psql_port }}
2 | export PSQL_DATABASE={{ database_dir }}
3 |
--------------------------------------------------------------------------------
/config/fastcgi_params:
--------------------------------------------------------------------------------
1 |
2 | fastcgi_param QUERY_STRING $query_string;
3 | fastcgi_param REQUEST_METHOD $request_method;
4 | fastcgi_param CONTENT_TYPE $content_type;
5 | fastcgi_param CONTENT_LENGTH $content_length;
6 |
7 | fastcgi_param SCRIPT_NAME $fastcgi_script_name;
8 | fastcgi_param REQUEST_URI $request_uri;
9 | fastcgi_param DOCUMENT_URI $document_uri;
10 | fastcgi_param DOCUMENT_ROOT $document_root;
11 | fastcgi_param SERVER_PROTOCOL $server_protocol;
12 | fastcgi_param HTTPS $https if_not_empty;
13 |
14 | fastcgi_param GATEWAY_INTERFACE CGI/1.1;
15 | fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
16 |
17 | fastcgi_param REMOTE_ADDR $remote_addr;
18 | fastcgi_param REMOTE_PORT $remote_port;
19 | fastcgi_param SERVER_ADDR $server_addr;
20 | fastcgi_param SERVER_PORT $server_port;
21 | fastcgi_param SERVER_NAME $server_name;
22 |
23 | # PHP only, required if PHP was built with --enable-force-cgi-redirect
24 | fastcgi_param REDIRECT_STATUS 200;
25 |
--------------------------------------------------------------------------------
/config/nginx.conf:
--------------------------------------------------------------------------------
1 | # Version 2024-07-17
2 | # https://github.com/nextcloud/documentation/blob/master/admin_manual/installation/nginx-root.conf.sample
3 | worker_processes 4;
4 |
5 | error_log syslog:server=unix:/dev/log warn;
6 | pid /var/snap/nextcloud/common/log/nginx.pid;
7 | daemon off;
8 |
9 | events {
10 | worker_connections 1024;
11 | }
12 |
13 | http {
14 | access_log syslog:server=unix:/dev/log;
15 |
16 | upstream php-handler {
17 | server unix:/var/snap/nextcloud/common/log/php5-fpm.sock;
18 | }
19 |
20 | # Set the `immutable` cache control options only for assets with a cache busting `v` argument
21 | map $arg_v $asset_immutable {
22 | "" "";
23 | default ", immutable";
24 | }
25 |
26 | client_body_temp_path /var/snap/nextcloud/common/nginx/client_body_temp;
27 | proxy_temp_path /var/snap/nextcloud/common/nginx/proxy_temp;
28 | fastcgi_temp_path /var/snap/nextcloud/common/nginx/fastcgi_temp;
29 | uwsgi_temp_path /var/snap/nextcloud/common/nginx/puwsgi_temp;
30 | scgi_temp_path /var/snap/nextcloud/common/nginx/scgi_temp;
31 |
32 | # solves app update issue
33 | absolute_redirect off;
34 |
35 | server {
36 | listen unix:/var/snap/nextcloud/common/web.socket;
37 | set_real_ip_from unix:;
38 | server_name localhost;
39 |
40 | # Path to the root of your installation
41 | root /snap/nextcloud/current/nextcloud;
42 |
43 | # Prevent nginx HTTP Server Detection
44 | server_tokens off;
45 |
46 | # HSTS settings
47 | # WARNING: Only add the preload option once you read about
48 | # the consequences in https://hstspreload.org/. This option
49 | # will add the domain to a hardcoded list that is shipped
50 | # in all major browsers and getting removed from this list
51 | # could take several months.
52 | #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
53 |
54 | # set max upload size and increase upload timeout:
55 | client_max_body_size 10G;
56 | client_body_timeout 300s;
57 | fastcgi_buffers 64 4K;
58 | fastcgi_read_timeout 600s;
59 | fastcgi_send_timeout 600s;
60 |
61 | # Enable gzip but do not remove ETag headers
62 | gzip on;
63 | gzip_vary on;
64 | gzip_comp_level 4;
65 | gzip_min_length 256;
66 | gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
67 | gzip_types application/atom+xml text/javascript application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
68 |
69 | # Pagespeed is not supported by Nextcloud, so if your server is built
70 | # with the `ngx_pagespeed` module, uncomment this line to disable it.
71 | #pagespeed off;
72 |
73 | # The settings allows you to optimize the HTTP2 bandwidth.
74 | # See https://blog.cloudflare.com/delivering-http-2-upload-speed-improvements/
75 | # for tuning hints
76 | client_body_buffer_size 512k;
77 |
78 | # HTTP response headers borrowed from Nextcloud `.htaccess`
79 | add_header Referrer-Policy "no-referrer" always;
80 | add_header X-Content-Type-Options "nosniff" always;
81 | add_header X-Frame-Options "SAMEORIGIN" always;
82 | add_header X-Permitted-Cross-Domain-Policies "none" always;
83 | add_header X-Robots-Tag "noindex, nofollow" always;
84 | add_header X-XSS-Protection "1; mode=block" always;
85 |
86 | # Remove X-Powered-By, which is an information leak
87 | fastcgi_hide_header X-Powered-By;
88 |
89 | # Set .mjs and .wasm MIME types
90 | # Either include it in the default mime.types list
91 | # and include that list explicitly or add the file extension
92 | # only for Nextcloud like below:
93 | include /snap/nextcloud/current/nginx/etc/nginx/mime.types;
94 | types {
95 | text/javascript js mjs;
96 | application/wasm wasm;
97 | }
98 |
99 | # Specify how to handle directories -- specifying `/index.php$request_uri`
100 | # here as the fallback means that Nginx always exhibits the desired behaviour
101 | # when a client requests a path that corresponds to a directory that exists
102 | # on the server. In particular, if that directory contains an index.php file,
103 | # that file is correctly served; if it doesn't, then the request is passed to
104 | # the front-end controller. This consistent behaviour means that we don't need
105 | # to specify custom rules for certain paths (e.g. images and other assets,
106 | # `/updater`, `/ocs-provider`), and thus
107 | # `try_files $uri $uri/ /index.php$request_uri`
108 | # always provides the desired behaviour.
109 | index index.php index.html /index.php$request_uri;
110 |
111 | # Rule borrowed from `.htaccess` to handle Microsoft DAV clients
112 | location = / {
113 | if ( $http_user_agent ~ ^DavClnt ) {
114 | return 302 /remote.php/webdav/$is_args$args;
115 | }
116 | }
117 |
118 | location = /robots.txt {
119 | allow all;
120 | log_not_found off;
121 | access_log off;
122 | }
123 |
124 | # Make a regex exception for `/.well-known` so that clients can still
125 | # access it despite the existence of the regex rule
126 | # `location ~ /(\.|autotest|...)` which would otherwise handle requests
127 | # for `/.well-known`.
128 | location ^~ /.well-known {
129 | # The rules in this block are an adaptation of the rules
130 | # in `.htaccess` that concern `/.well-known`.
131 |
132 | location = /.well-known/carddav { return 301 /remote.php/dav/; }
133 | location = /.well-known/caldav { return 301 /remote.php/dav/; }
134 |
135 | location /.well-known/acme-challenge { try_files $uri $uri/ =404; }
136 | location /.well-known/pki-validation { try_files $uri $uri/ =404; }
137 |
138 | # Let Nextcloud's API for `/.well-known` URIs handle all other
139 | # requests by passing them to the front-end controller.
140 | return 301 /index.php$request_uri;
141 | }
142 |
143 | # Rules borrowed from `.htaccess` to hide certain paths from clients
144 | location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; }
145 | location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; }
146 |
147 | # Ensure this block, which passes PHP files to the PHP process, is above the blocks
148 | # which handle static assets (as seen below). If this block is not declared first,
149 | # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
150 | # to the URI, resulting in a HTTP 500 error response.
151 | location ~ \.php(?:$|/) {
152 | # Required for legacy support
153 | rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|ocs-provider\/.+|.+\/richdocumentscode(_arm64)?\/proxy) /index.php$request_uri;
154 |
155 | fastcgi_split_path_info ^(.+?\.php)(/.*)$;
156 | set $path_info $fastcgi_path_info;
157 |
158 | try_files $fastcgi_script_name =404;
159 |
160 | include fastcgi_params;
161 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
162 | fastcgi_param PATH_INFO $path_info;
163 | fastcgi_param HTTPS on;
164 |
165 | fastcgi_param modHeadersAvailable true; # Avoid sending the security headers twice
166 | fastcgi_param front_controller_active true; # Enable pretty urls
167 | fastcgi_pass php-handler;
168 |
169 | fastcgi_intercept_errors on;
170 | fastcgi_request_buffering off;
171 | fastcgi_param REMOTE_ADDR $remote_addr;
172 |
173 | fastcgi_max_temp_file_size 0;
174 | }
175 |
176 | # Serve static files
177 | location ~ \.(?:css|js|mjs|svg|gif|ico|jpg|png|webp|wasm|tflite|map|ogg|flac)$ {
178 | try_files $uri /index.php$request_uri;
179 | # HTTP response headers borrowed from Nextcloud `.htaccess`
180 | add_header Cache-Control "public, max-age=15778463$asset_immutable";
181 | add_header Referrer-Policy "no-referrer" always;
182 | add_header X-Content-Type-Options "nosniff" always;
183 | add_header X-Frame-Options "SAMEORIGIN" always;
184 | add_header X-Permitted-Cross-Domain-Policies "none" always;
185 | add_header X-Robots-Tag "noindex, nofollow" always;
186 | add_header X-XSS-Protection "1; mode=block" always;
187 | access_log off; # Optional: Don't log access to assets
188 | }
189 |
190 | location ~ \.(otf|woff2?)$ {
191 | try_files $uri /index.php$request_uri;
192 | expires 7d; # Cache-Control policy borrowed from `.htaccess`
193 | access_log off; # Optional: Don't log access to assets
194 | }
195 |
196 | # Rule borrowed from `.htaccess`
197 | location /remote {
198 | return 301 /remote.php$request_uri;
199 | }
200 |
201 | location / {
202 | try_files $uri $uri/ /index.php$request_uri;
203 | }
204 | }
205 | }
--------------------------------------------------------------------------------
/config/php-fpm.conf:
--------------------------------------------------------------------------------
1 | ;;;;;;;;;;;;;;;;;;;;;
2 | ; FPM Configuration ;
3 | ;;;;;;;;;;;;;;;;;;;;;
4 |
5 | ; All relative paths in this configuration file are relative to PHP's install
6 | ; prefix (/opt/syncloud-nextcloud/php). This prefix can be dynamically changed by using the
7 | ; '-p' argument from the command line.
8 |
9 | ; Include one or more files. If glob(3) exists, it is used to include a bunch of
10 | ; files from a glob(3) pattern. This directive can be used everywhere in the
11 | ; file.
12 | ; Relative path can also be used. They will be prefixed by:
13 | ; - the global prefix if it's been set (-p argument)
14 | ; - /opt/syncloud-nextcloud/php otherwise
15 | ;include=etc/fpm.d/*.conf
16 |
17 | ;;;;;;;;;;;;;;;;;;
18 | ; Global Options ;
19 | ;;;;;;;;;;;;;;;;;;
20 |
21 | [global]
22 | ; Pid file
23 | ; Note: the default prefix is /opt/syncloud-nextcloud/php/var
24 | ; Default Value: none
25 | pid = {{ common_dir }}/php-fpm.pid
26 |
27 | ; Error log file
28 | ; If it's set to "syslog", log is sent to syslogd instead of being written
29 | ; in a local file.
30 | ; Note: the default prefix is /opt/syncloud-nextcloud/php/var
31 | ; Default Value: log/php-fpm.log
32 | error_log = syslog
33 |
34 | ; syslog_facility is used to specify what type of program is logging the
35 | ; message. This lets syslogd specify that messages from different facilities
36 | ; will be handled differently.
37 | ; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON)
38 | ; Default Value: daemon
39 | ;syslog.facility = daemon
40 |
41 | ; syslog_ident is prepended to every message. If you have multiple FPM
42 | ; instances running on the same server, you can change the default value
43 | ; which must suit common needs.
44 | ; Default Value: php-fpm
45 | syslog.ident = nextcloud.php-fpm
46 |
47 | ; Log level
48 | ; Possible Values: alert, error, warning, notice, debug
49 | ; Default Value: notice
50 | ;log_level = notice
51 |
52 | ; If this number of child processes exit with SIGSEGV or SIGBUS within the time
53 | ; interval set by emergency_restart_interval then FPM will restart. A value
54 | ; of '0' means 'Off'.
55 | ; Default Value: 0
56 | ;emergency_restart_threshold = 0
57 |
58 | ; Interval of time used by emergency_restart_interval to determine when
59 | ; a graceful restart will be initiated. This can be useful to work around
60 | ; accidental corruptions in an accelerator's shared memory.
61 | ; Available Units: s(econds), m(inutes), h(ours), or d(ays)
62 | ; Default Unit: seconds
63 | ; Default Value: 0
64 | ;emergency_restart_interval = 0
65 |
66 | ; Time limit for child processes to wait for a reaction on signals from master.
67 | ; Available units: s(econds), m(inutes), h(ours), or d(ays)
68 | ; Default Unit: seconds
69 | ; Default Value: 0
70 | ;process_control_timeout = 0
71 |
72 | ; The maximum number of processes FPM will fork. This has been design to control
73 | ; the global number of processes when using dynamic PM within a lot of pools.
74 | ; Use it with caution.
75 | ; Note: A value of 0 indicates no limit
76 | ; Default Value: 0
77 | ; process.max = 128
78 |
79 | ; Specify the nice(2) priority to apply to the master process (only if set)
80 | ; The value can vary from -19 (highest priority) to 20 (lower priority)
81 | ; Note: - It will only work if the FPM master process is launched as root
82 | ; - The pool process will inherit the master process priority
83 | ; unless it specified otherwise
84 | ; Default Value: no set
85 | ; process.priority = -19
86 |
87 | ; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging.
88 | ; Default Value: yes
89 | ;daemonize = yes
90 |
91 | ; Set open file descriptor rlimit for the master process.
92 | ; Default Value: system defined value
93 | ;rlimit_files = 1024
94 |
95 | ; Set max core size rlimit for the master process.
96 | ; Possible Values: 'unlimited' or an integer greater or equal to 0
97 | ; Default Value: system defined value
98 | ;rlimit_core = 0
99 |
100 | ; Specify the event mechanism FPM will use. The following is available:
101 | ; - select (any POSIX os)
102 | ; - poll (any POSIX os)
103 | ; - epoll (linux >= 2.5.44)
104 | ; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0)
105 | ; - /dev/poll (Solaris >= 7)
106 | ; - port (Solaris >= 10)
107 | ; Default Value: not set (auto detection)
108 | ;events.mechanism = epoll
109 |
110 | ; When FPM is build with systemd integration, specify the interval,
111 | ; in second, between health report notification to systemd.
112 | ; Set to 0 to disable.
113 | ; Available Units: s(econds), m(inutes), h(ours)
114 | ; Default Unit: seconds
115 | ; Default value: 10
116 | ;systemd_interval = 10
117 |
118 | ;;;;;;;;;;;;;;;;;;;;
119 | ; Pool Definitions ;
120 | ;;;;;;;;;;;;;;;;;;;;
121 |
122 | ; Multiple pools of child processes may be started with different listening
123 | ; ports and different management options. The name of the pool will be
124 | ; used in logs and stats. There is no limitation on the number of pools which
125 | ; FPM can handle. Your system will tell you anyway :)
126 |
127 | ; Start a new pool named 'www'.
128 | ; the variable $pool can we used in any directive and will be replaced by the
129 | ; pool name ('www' here)
130 | [www]
131 |
132 | ; Per pool prefix
133 | ; It only applies on the following directives:
134 | ; - 'access.log'
135 | ; - 'slowlog'
136 | ; - 'listen' (unixsocket)
137 | ; - 'chroot'
138 | ; - 'chdir'
139 | ; - 'php_values'
140 | ; - 'php_admin_values'
141 | ; When not set, the global prefix (or /opt/syncloud-nextcloud/php) applies instead.
142 | ; Note: This directive can also be relative to the global prefix.
143 | ; Default Value: none
144 | ;prefix = /path/to/pools/$pool
145 |
146 | ; Unix user/group of processes
147 | ; Note: The user is mandatory. If the group is not set, the default user's group
148 | ; will be used.
149 | user = nextcloud
150 | group = nextcloud
151 |
152 | ; The address on which to accept FastCGI requests.
153 | ; Valid syntaxes are:
154 | ; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on
155 | ; a specific port;
156 | ; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
157 | ; a specific port;
158 | ; 'port' - to listen on a TCP socket to all IPv4 addresses on a
159 | ; specific port;
160 | ; '[::]:port' - to listen on a TCP socket to all addresses
161 | ; (IPv6 and IPv4-mapped) on a specific port;
162 | ; '/path/to/unix/socket' - to listen on a unix socket.
163 | ; Note: This value is mandatory.
164 | listen = {{ common_dir }}/log/php5-fpm.sock
165 |
166 | ; Set listen(2) backlog.
167 | ; Default Value: 65535 (-1 on FreeBSD and OpenBSD)
168 | ;listen.backlog = 65535
169 |
170 | ; Set permissions for unix socket, if one is used. In Linux, read/write
171 | ; permissions must be set in order to allow connections from a web server. Many
172 | ; BSD-derived systems allow connections regardless of permissions.
173 | ; Default Values: user and group are set as the running user
174 | ; mode is set to 0660
175 | ;listen.owner = nobody
176 | ;listen.group = nobody
177 | ;listen.mode = 0660
178 | ; When POSIX Access Control Lists are supported you can set them using
179 | ; these options, value is a comma separated list of user/group names.
180 | ; When set, listen.owner and listen.group are ignored
181 | ;listen.acl_users =
182 | ;listen.acl_groups =
183 |
184 | ; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect.
185 | ; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original
186 | ; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address
187 | ; must be separated by a comma. If this value is left blank, connections will be
188 | ; accepted from any ip address.
189 | ; Default Value: any
190 | ;listen.allowed_clients = 127.0.0.1
191 |
192 | ; Specify the nice(2) priority to apply to the pool processes (only if set)
193 | ; The value can vary from -19 (highest priority) to 20 (lower priority)
194 | ; Note: - It will only work if the FPM master process is launched as root
195 | ; - The pool processes will inherit the master process priority
196 | ; unless it specified otherwise
197 | ; Default Value: no set
198 | ; process.priority = -19
199 |
200 | ; Choose how the process manager will control the number of child processes.
201 | ; Possible Values:
202 | ; static - a fixed number (pm.max_children) of child processes;
203 | ; dynamic - the number of child processes are set dynamically based on the
204 | ; following directives. With this process management, there will be
205 | ; always at least 1 children.
206 | ; pm.max_children - the maximum number of children that can
207 | ; be alive at the same time.
208 | ; pm.start_servers - the number of children created on startup.
209 | ; pm.min_spare_servers - the minimum number of children in 'idle'
210 | ; state (waiting to process). If the number
211 | ; of 'idle' processes is less than this
212 | ; number then some children will be created.
213 | ; pm.max_spare_servers - the maximum number of children in 'idle'
214 | ; state (waiting to process). If the number
215 | ; of 'idle' processes is greater than this
216 | ; number then some children will be killed.
217 | ; ondemand - no children are created at startup. Children will be forked when
218 | ; new requests will connect. The following parameter are used:
219 | ; pm.max_children - the maximum number of children that
220 | ; can be alive at the same time.
221 | ; pm.process_idle_timeout - The number of seconds after which
222 | ; an idle process will be killed.
223 | ; Note: This value is mandatory.
224 | pm = dynamic
225 |
226 | ; The number of child processes to be created when pm is set to 'static' and the
227 | ; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
228 | ; This value sets the limit on the number of simultaneous requests that will be
229 | ; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
230 | ; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
231 | ; CGI. The below defaults are based on a server without much resources. Don't
232 | ; forget to tweak pm.* to fit your needs.
233 | ; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
234 | ; Note: This value is mandatory.
235 | pm.max_children = 10
236 |
237 | ; The number of child processes created on startup.
238 | ; Note: Used only when pm is set to 'dynamic'
239 | ; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2
240 | pm.start_servers = 2
241 |
242 | ; The desired minimum number of idle server processes.
243 | ; Note: Used only when pm is set to 'dynamic'
244 | ; Note: Mandatory when pm is set to 'dynamic'
245 | pm.min_spare_servers = 1
246 |
247 | ; The desired maximum number of idle server processes.
248 | ; Note: Used only when pm is set to 'dynamic'
249 | ; Note: Mandatory when pm is set to 'dynamic'
250 | pm.max_spare_servers = 3
251 |
252 | ; The number of seconds after which an idle process will be killed.
253 | ; Note: Used only when pm is set to 'ondemand'
254 | ; Default Value: 10s
255 | ;pm.process_idle_timeout = 10s;
256 |
257 | ; The number of requests each child process should execute before respawning.
258 | ; This can be useful to work around memory leaks in 3rd party libraries. For
259 | ; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.
260 | ; Default Value: 0
261 | ;pm.max_requests = 500
262 |
263 | ; The URI to view the FPM status page. If this value is not set, no URI will be
264 | ; recognized as a status page. It shows the following informations:
265 | ; pool - the name of the pool;
266 | ; process manager - static, dynamic or ondemand;
267 | ; start time - the date and time FPM has started;
268 | ; start since - number of seconds since FPM has started;
269 | ; accepted conn - the number of request accepted by the pool;
270 | ; listen queue - the number of request in the queue of pending
271 | ; connections (see backlog in listen(2));
272 | ; max listen queue - the maximum number of requests in the queue
273 | ; of pending connections since FPM has started;
274 | ; listen queue len - the size of the socket queue of pending connections;
275 | ; idle processes - the number of idle processes;
276 | ; active processes - the number of active processes;
277 | ; total processes - the number of idle + active processes;
278 | ; max active processes - the maximum number of active processes since FPM
279 | ; has started;
280 | ; max children reached - number of times, the process limit has been reached,
281 | ; when pm tries to start more children (works only for
282 | ; pm 'dynamic' and 'ondemand');
283 | ; Value are updated in real time.
284 | ; Example output:
285 | ; pool: www
286 | ; process manager: static
287 | ; start time: 01/Jul/2011:17:53:49 +0200
288 | ; start since: 62636
289 | ; accepted conn: 190460
290 | ; listen queue: 0
291 | ; max listen queue: 1
292 | ; listen queue len: 42
293 | ; idle processes: 4
294 | ; active processes: 11
295 | ; total processes: 15
296 | ; max active processes: 12
297 | ; max children reached: 0
298 | ;
299 | ; By default the status page output is formatted as text/plain. Passing either
300 | ; 'html', 'xml' or 'json' in the query string will return the corresponding
301 | ; output syntax. Example:
302 | ; http://www.foo.bar/status
303 | ; http://www.foo.bar/status?json
304 | ; http://www.foo.bar/status?html
305 | ; http://www.foo.bar/status?xml
306 | ;
307 | ; By default the status page only outputs short status. Passing 'full' in the
308 | ; query string will also return status for each pool process.
309 | ; Example:
310 | ; http://www.foo.bar/status?full
311 | ; http://www.foo.bar/status?json&full
312 | ; http://www.foo.bar/status?html&full
313 | ; http://www.foo.bar/status?xml&full
314 | ; The Full status returns for each process:
315 | ; pid - the PID of the process;
316 | ; state - the state of the process (Idle, Running, ...);
317 | ; start time - the date and time the process has started;
318 | ; start since - the number of seconds since the process has started;
319 | ; requests - the number of requests the process has served;
320 | ; request duration - the duration in µs of the requests;
321 | ; request method - the request method (GET, POST, ...);
322 | ; request URI - the request URI with the query string;
323 | ; content length - the content length of the request (only with POST);
324 | ; user - the user (PHP_AUTH_USER) (or '-' if not set);
325 | ; script - the main script called (or '-' if not set);
326 | ; last request cpu - the %cpu the last request consumed
327 | ; it's always 0 if the process is not in Idle state
328 | ; because CPU calculation is done when the request
329 | ; processing has terminated;
330 | ; last request memory - the max amount of memory the last request consumed
331 | ; it's always 0 if the process is not in Idle state
332 | ; because memory calculation is done when the request
333 | ; processing has terminated;
334 | ; If the process is in Idle state, then informations are related to the
335 | ; last request the process has served. Otherwise informations are related to
336 | ; the current request being served.
337 | ; Example output:
338 | ; ************************
339 | ; pid: 31330
340 | ; state: Running
341 | ; start time: 01/Jul/2011:17:53:49 +0200
342 | ; start since: 63087
343 | ; requests: 12808
344 | ; request duration: 1250261
345 | ; request method: GET
346 | ; request URI: /test_mem.php?N=10000
347 | ; content length: 0
348 | ; user: -
349 | ; script: /home/fat/web/docs/php/test_mem.php
350 | ; last request cpu: 0.00
351 | ; last request memory: 0
352 | ;
353 | ; Note: There is a real-time FPM status monitoring sample web page available
354 | ; It's available in: /opt/syncloud-nextcloud/php/share/php/fpm/status.html
355 | ;
356 | ; Note: The value must start with a leading slash (/). The value can be
357 | ; anything, but it may not be a good idea to use the .php extension or it
358 | ; may conflict with a real PHP file.
359 | ; Default Value: not set
360 | ;pm.status_path = /status
361 |
362 | ; The ping URI to call the monitoring page of FPM. If this value is not set, no
363 | ; URI will be recognized as a ping page. This could be used to test from outside
364 | ; that FPM is alive and responding, or to
365 | ; - create a graph of FPM availability (rrd or such);
366 | ; - remove a server from a group if it is not responding (load balancing);
367 | ; - trigger alerts for the operating team (24/7).
368 | ; Note: The value must start with a leading slash (/). The value can be
369 | ; anything, but it may not be a good idea to use the .php extension or it
370 | ; may conflict with a real PHP file.
371 | ; Default Value: not set
372 | ;ping.path = /ping
373 |
374 | ; This directive may be used to customize the response of a ping request. The
375 | ; response is formatted as text/plain with a 200 response code.
376 | ; Default Value: pong
377 | ;ping.response = pong
378 |
379 | ; The access log file
380 | ; Default: not set
381 | ;access.log = log/$pool.access.log
382 |
383 | ; The access log format.
384 | ; The following syntax is allowed
385 | ; %%: the '%' character
386 | ; %C: %CPU used by the request
387 | ; it can accept the following format:
388 | ; - %{user}C for user CPU only
389 | ; - %{system}C for system CPU only
390 | ; - %{total}C for user + system CPU (default)
391 | ; %d: time taken to serve the request
392 | ; it can accept the following format:
393 | ; - %{seconds}d (default)
394 | ; - %{miliseconds}d
395 | ; - %{mili}d
396 | ; - %{microseconds}d
397 | ; - %{micro}d
398 | ; %e: an environment variable (same as $_ENV or $_SERVER)
399 | ; it must be associated with embraces to specify the name of the env
400 | ; variable. Some exemples:
401 | ; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e
402 | ; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e
403 | ; %f: script filename
404 | ; %l: content-length of the request (for POST request only)
405 | ; %m: request method
406 | ; %M: peak of memory allocated by PHP
407 | ; it can accept the following format:
408 | ; - %{bytes}M (default)
409 | ; - %{kilobytes}M
410 | ; - %{kilo}M
411 | ; - %{megabytes}M
412 | ; - %{mega}M
413 | ; %n: pool name
414 | ; %o: output header
415 | ; it must be associated with embraces to specify the name of the header:
416 | ; - %{Content-Type}o
417 | ; - %{X-Powered-By}o
418 | ; - %{Transfert-Encoding}o
419 | ; - ....
420 | ; %p: PID of the child that serviced the request
421 | ; %P: PID of the parent of the child that serviced the request
422 | ; %q: the query string
423 | ; %Q: the '?' character if query string exists
424 | ; %r: the request URI (without the query string, see %q and %Q)
425 | ; %R: remote IP address
426 | ; %s: status (response code)
427 | ; %t: server time the request was received
428 | ; it can accept a strftime(3) format:
429 | ; %d/%b/%Y:%H:%M:%S %z (default)
430 | ; %T: time the log has been written (the request has finished)
431 | ; it can accept a strftime(3) format:
432 | ; %d/%b/%Y:%H:%M:%S %z (default)
433 | ; %u: remote user
434 | ;
435 | ; Default: "%R - %u %t \"%m %r\" %s"
436 | ;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
437 |
438 | ; The log file for slow requests
439 | ; Default Value: not set
440 | ; Note: slowlog is mandatory if request_slowlog_timeout is set
441 | ;slowlog = log/$pool.log.slow
442 |
443 | ; The timeout for serving a single request after which a PHP backtrace will be
444 | ; dumped to the 'slowlog' file. A value of '0s' means 'off'.
445 | ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
446 | ; Default Value: 0
447 | ;request_slowlog_timeout = 0
448 |
449 | ; The timeout for serving a single request after which the worker process will
450 | ; be killed. This option should be used when the 'max_execution_time' ini option
451 | ; does not stop script execution for some reason. A value of '0' means 'off'.
452 | ; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
453 | ; Default Value: 0
454 | ;request_terminate_timeout = 0
455 |
456 | ; Set open file descriptor rlimit.
457 | ; Default Value: system defined value
458 | ;rlimit_files = 1024
459 |
460 | ; Set max core size rlimit.
461 | ; Possible Values: 'unlimited' or an integer greater or equal to 0
462 | ; Default Value: system defined value
463 | ;rlimit_core = 0
464 |
465 | ; Chroot to this directory at the start. This value must be defined as an
466 | ; absolute path. When this value is not set, chroot is not used.
467 | ; Note: you can prefix with '$prefix' to chroot to the pool prefix or one
468 | ; of its subdirectories. If the pool prefix is not set, the global prefix
469 | ; will be used instead.
470 | ; Note: chrooting is a great security feature and should be used whenever
471 | ; possible. However, all PHP paths will be relative to the chroot
472 | ; (error_log, sessions.save_path, ...).
473 | ; Default Value: not set
474 | ;chroot =
475 |
476 | ; Chdir to this directory at the start.
477 | ; Note: relative path can be used.
478 | ; Default Value: current directory or / when chroot
479 | ;chdir = /var/www
480 |
481 | ; Redirect worker stdout and stderr into main error log. If not set, stdout and
482 | ; stderr will be redirected to /dev/null according to FastCGI specs.
483 | ; Note: on highloaded environement, this can cause some delay in the page
484 | ; process time (several ms).
485 | ; Default Value: no
486 | catch_workers_output = yes
487 |
488 | ; Clear environment in FPM workers
489 | ; Prevents arbitrary environment variables from reaching FPM worker processes
490 | ; by clearing the environment in workers before env vars specified in this
491 | ; pool configuration are added.
492 | ; Setting to "no" will make all environment variables available to PHP code
493 | ; via getenv(), $_ENV and $_SERVER.
494 | ; Default Value: yes
495 | ;clear_env = no
496 |
497 | ; Limits the extensions of the main script FPM will allow to parse. This can
498 | ; prevent configuration mistakes on the web server side. You should only limit
499 | ; FPM to .php extensions to prevent malicious users to use other extensions to
500 | ; exectute php code.
501 | ; Note: set an empty value to allow all extensions.
502 | ; Default Value: .php
503 | ;security.limit_extensions = .php .php3 .php4 .php5
504 |
505 | ; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from
506 | ; the current environment.
507 | ; Default Value: clean env
508 | env[HOSTNAME] = $HOSTNAME
509 | env[PATH] = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
510 | env[TMP] = /data/nextcloud/tmp
511 | env[TMPDIR] = /data/nextcloud/tmp
512 | env[TEMP] = /data/nextcloud/tmp
513 | env[NEXTCLOUD_CONFIG_DIR]={{ data_dir }}/nextcloud/config
514 | env[MAGICK_CODER_MODULE_PATH] = /snap/nextcloud/current/php/usr/lib/ImageMagickCoders
515 |
516 | ; Additional php.ini defines, specific to this pool of workers. These settings
517 | ; overwrite the values previously defined in the php.ini. The directives are the
518 | ; same as the PHP SAPI:
519 | ; php_value/php_flag - you can set classic ini defines which can
520 | ; be overwritten from PHP call 'ini_set'.
521 | ; php_admin_value/php_admin_flag - these directives won't be overwritten by
522 | ; PHP call 'ini_set'
523 | ; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.
524 |
525 | ; Defining 'extension' will load the corresponding shared extension from
526 | ; extension_dir. Defining 'disable_functions' or 'disable_classes' will not
527 | ; overwrite previously defined php.ini values, but will append the new value
528 | ; instead.
529 |
530 | ; Note: path INI options can be relative and will be expanded with the prefix
531 | ; (pool, global or /opt/syncloud-nextcloud/php)
532 |
533 | ; Default Value: nothing is defined by default except the values in php.ini and
534 | ; specified at startup with the -d argument
535 | ;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
536 | ;php_flag[display_errors] = off
537 | php_admin_value[error_log] = syslog
538 | php_admin_flag[log_errors] = on
539 | ;php_admin_value[memory_limit] = 32M
540 |
--------------------------------------------------------------------------------
/config/postgresql.conf:
--------------------------------------------------------------------------------
1 | # -----------------------------
2 | # PostgreSQL configuration file
3 | # -----------------------------
4 | #
5 | # This file consists of lines of the form:
6 | #
7 | # name = value
8 | #
9 | # (The "=" is optional.) Whitespace may be used. Comments are introduced with
10 | # "#" anywhere on a line. The complete list of parameter names and allowed
11 | # values can be found in the PostgreSQL documentation.
12 | #
13 | # The commented-out settings shown in this file represent the default values.
14 | # Re-commenting a setting is NOT sufficient to revert it to the default value;
15 | # you need to reload the server.
16 | #
17 | # This file is read on server startup and when the server receives a SIGHUP
18 | # signal. If you edit the file on a running system, you have to SIGHUP the
19 | # server for the changes to take effect, or use "pg_ctl reload". Some
20 | # parameters, which are marked below, require a server shutdown and restart to
21 | # take effect.
22 | #
23 | # Any parameter can also be given as a command-line option to the server, e.g.,
24 | # "postgres -c log_connections=on". Some parameters can be changed at run time
25 | # with the "SET" SQL command.
26 | #
27 | # Memory units: kB = kilobytes Time units: ms = milliseconds
28 | # MB = megabytes s = seconds
29 | # GB = gigabytes min = minutes
30 | # TB = terabytes h = hours
31 | # d = days
32 |
33 |
34 | #------------------------------------------------------------------------------
35 | # FILE LOCATIONS
36 | #------------------------------------------------------------------------------
37 |
38 | # The default values of these variables are driven from the -D command-line
39 | # option or PGDATA environment variable, represented here as ConfigDir.
40 |
41 | #data_directory = 'ConfigDir' # use data in another directory
42 | # (change requires restart)
43 | #hba_file = 'ConfigDir/pg_hba.conf' # host-based authentication file
44 | # (change requires restart)
45 | #ident_file = 'ConfigDir/pg_ident.conf' # ident configuration file
46 | # (change requires restart)
47 |
48 | # If external_pid_file is not explicitly set, no extra PID file is written.
49 | #external_pid_file = '' # write an extra PID file
50 | # (change requires restart)
51 |
52 |
53 | #------------------------------------------------------------------------------
54 | # CONNECTIONS AND AUTHENTICATION
55 | #------------------------------------------------------------------------------
56 |
57 | # - Connection Settings -
58 |
59 | listen_addresses = '' # what IP address(es) to listen on;
60 | # comma-separated list of addresses;
61 | # defaults to 'localhost'; use '*' for all
62 | # (change requires restart)
63 | port = {{ db_psql_port }} # (change requires restart)
64 | #max_connections = 100 # (change requires restart)
65 | # Note: Increasing max_connections costs ~400 bytes of shared memory per
66 | # connection slot, plus lock space (see max_locks_per_transaction).
67 | #superuser_reserved_connections = 3 # (change requires restart)
68 | unix_socket_directories = '{{ database_dir }}' # comma-separated list of directories
69 | # (change requires restart)
70 | #unix_socket_group = '' # (change requires restart)
71 | #unix_socket_permissions = 0777 # begin with 0 to use octal notation
72 | # (change requires restart)
73 | #bonjour = off # advertise server via Bonjour
74 | # (change requires restart)
75 | #bonjour_name = '' # defaults to the computer name
76 | # (change requires restart)
77 |
78 | # - Security and Authentication -
79 |
80 | #authentication_timeout = 1min # 1s-600s
81 | #ssl = off # (change requires restart)
82 | #ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
83 | # (change requires restart)
84 | #ssl_prefer_server_ciphers = on # (change requires restart)
85 | #ssl_ecdh_curve = 'prime256v1' # (change requires restart)
86 | #ssl_renegotiation_limit = 512MB # amount of data between renegotiations
87 | #ssl_cert_file = 'server.crt' # (change requires restart)
88 | #ssl_key_file = 'server.key' # (change requires restart)
89 | #ssl_ca_file = '' # (change requires restart)
90 | #ssl_crl_file = '' # (change requires restart)
91 | #password_encryption = on
92 | #db_user_namespace = off
93 |
94 | # GSSAPI using Kerberos
95 | #krb_server_keyfile = ''
96 | #krb_caseins_users = off
97 |
98 | # - TCP Keepalives -
99 | # see "man 7 tcp" for details
100 |
101 | #tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds;
102 | # 0 selects the system default
103 | #tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds;
104 | # 0 selects the system default
105 | #tcp_keepalives_count = 0 # TCP_KEEPCNT;
106 | # 0 selects the system default
107 |
108 |
109 | #------------------------------------------------------------------------------
110 | # RESOURCE USAGE (except WAL)
111 | #------------------------------------------------------------------------------
112 |
113 | # - Memory -
114 |
115 | #shared_buffers = 32MB # min 128kB
116 | # (change requires restart)
117 | #huge_pages = try # on, off, or try
118 | # (change requires restart)
119 | #temp_buffers = 8MB # min 800kB
120 | #max_prepared_transactions = 0 # zero disables the feature
121 | # (change requires restart)
122 | # Note: Increasing max_prepared_transactions costs ~600 bytes of shared memory
123 | # per transaction slot, plus lock space (see max_locks_per_transaction).
124 | # It is not advisable to set max_prepared_transactions nonzero unless you
125 | # actively intend to use prepared transactions.
126 | #work_mem = 4MB # min 64kB
127 | #maintenance_work_mem = 64MB # min 1MB
128 | #autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem
129 | #max_stack_depth = 2MB # min 100kB
130 | #dynamic_shared_memory_type = posix # the default is the first option
131 | # supported by the operating system:
132 | # posix
133 | # sysv
134 | # windows
135 | # mmap
136 | # use none to disable dynamic shared memory
137 |
138 | # - Disk -
139 |
140 | #temp_file_limit = -1 # limits per-session temp file space
141 | # in kB, or -1 for no limit
142 |
143 | # - Kernel Resource Usage -
144 |
145 | #max_files_per_process = 1000 # min 25
146 | # (change requires restart)
147 | #shared_preload_libraries = '' # (change requires restart)
148 |
149 | # - Cost-Based Vacuum Delay -
150 |
151 | #vacuum_cost_delay = 0 # 0-100 milliseconds
152 | #vacuum_cost_page_hit = 1 # 0-10000 credits
153 | #vacuum_cost_page_miss = 10 # 0-10000 credits
154 | #vacuum_cost_page_dirty = 20 # 0-10000 credits
155 | #vacuum_cost_limit = 200 # 1-10000 credits
156 |
157 | # - Background Writer -
158 |
159 | #bgwriter_delay = 200ms # 10-10000ms between rounds
160 | #bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round
161 | #bgwriter_lru_multiplier = 2.0 # 0-10.0 multipler on buffers scanned/round
162 |
163 | # - Asynchronous Behavior -
164 |
165 | #effective_io_concurrency = 1 # 1-1000; 0 disables prefetching
166 | #max_worker_processes = 8
167 |
168 |
169 | #------------------------------------------------------------------------------
170 | # WRITE AHEAD LOG
171 | #------------------------------------------------------------------------------
172 |
173 | # - Settings -
174 |
175 | #wal_level = minimal # minimal, archive, hot_standby, or logical
176 | # (change requires restart)
177 | #fsync = on # turns forced synchronization on or off
178 | #synchronous_commit = on # synchronization level;
179 | # off, local, remote_write, or on
180 | #wal_sync_method = fsync # the default is the first option
181 | # supported by the operating system:
182 | # open_datasync
183 | # fdatasync (default on Linux)
184 | # fsync
185 | # fsync_writethrough
186 | # open_sync
187 | #full_page_writes = on # recover from partial page writes
188 | #wal_log_hints = off # also do full page writes of non-critical updates
189 | # (change requires restart)
190 | #wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers
191 | # (change requires restart)
192 | #wal_writer_delay = 200ms # 1-10000 milliseconds
193 |
194 | #commit_delay = 0 # range 0-100000, in microseconds
195 | #commit_siblings = 5 # range 1-1000
196 |
197 | # - Checkpoints -
198 |
199 | #checkpoint_segments = 3 # in logfile segments, min 1, 16MB each
200 | #checkpoint_timeout = 5min # range 30s-1h
201 | #checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0
202 | #checkpoint_warning = 30s # 0 disables
203 |
204 | # - Archiving -
205 |
206 | #archive_mode = off # allows archiving to be done
207 | # (change requires restart)
208 | #archive_command = '' # command to use to archive a logfile segment
209 | # placeholders: %p = path of file to archive
210 | # %f = file name only
211 | # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'
212 | #archive_timeout = 0 # force a logfile segment switch after this
213 | # number of seconds; 0 disables
214 |
215 |
216 | #------------------------------------------------------------------------------
217 | # REPLICATION
218 | #------------------------------------------------------------------------------
219 |
220 | # - Sending Server(s) -
221 |
222 | # Set these on the master and on any standby that will send replication data.
223 |
224 | #max_wal_senders = 0 # max number of walsender processes
225 | # (change requires restart)
226 | #wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables
227 | #wal_sender_timeout = 60s # in milliseconds; 0 disables
228 |
229 | #max_replication_slots = 0 # max number of replication slots
230 | # (change requires restart)
231 |
232 | # - Master Server -
233 |
234 | # These settings are ignored on a standby server.
235 |
236 | #synchronous_standby_names = '' # standby servers that provide sync rep
237 | # comma-separated list of application_name
238 | # from standby(s); '*' = all
239 | #vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed
240 |
241 | # - Standby Servers -
242 |
243 | # These settings are ignored on a master server.
244 |
245 | #hot_standby = off # "on" allows queries during recovery
246 | # (change requires restart)
247 | #max_standby_archive_delay = 30s # max delay before canceling queries
248 | # when reading WAL from archive;
249 | # -1 allows indefinite delay
250 | #max_standby_streaming_delay = 30s # max delay before canceling queries
251 | # when reading streaming WAL;
252 | # -1 allows indefinite delay
253 | #wal_receiver_status_interval = 10s # send replies at least this often
254 | # 0 disables
255 | #hot_standby_feedback = off # send info from standby to prevent
256 | # query conflicts
257 | #wal_receiver_timeout = 60s # time that receiver waits for
258 | # communication from master
259 | # in milliseconds; 0 disables
260 |
261 |
262 | #------------------------------------------------------------------------------
263 | # QUERY TUNING
264 | #------------------------------------------------------------------------------
265 |
266 | # - Planner Method Configuration -
267 |
268 | #enable_bitmapscan = on
269 | #enable_hashagg = on
270 | #enable_hashjoin = on
271 | #enable_indexscan = on
272 | #enable_indexonlyscan = on
273 | #enable_material = on
274 | #enable_mergejoin = on
275 | #enable_nestloop = on
276 | #enable_seqscan = on
277 | #enable_sort = on
278 | #enable_tidscan = on
279 |
280 | # - Planner Cost Constants -
281 |
282 | #seq_page_cost = 1.0 # measured on an arbitrary scale
283 | #random_page_cost = 4.0 # same scale as above
284 | #cpu_tuple_cost = 0.01 # same scale as above
285 | #cpu_index_tuple_cost = 0.005 # same scale as above
286 | #cpu_operator_cost = 0.0025 # same scale as above
287 | #effective_cache_size = 4GB
288 |
289 | # - Genetic Query Optimizer -
290 |
291 | #geqo = on
292 | #geqo_threshold = 12
293 | #geqo_effort = 5 # range 1-10
294 | #geqo_pool_size = 0 # selects default based on effort
295 | #geqo_generations = 0 # selects default based on effort
296 | #geqo_selection_bias = 2.0 # range 1.5-2.0
297 | #geqo_seed = 0.0 # range 0.0-1.0
298 |
299 | # - Other Planner Options -
300 |
301 | #default_statistics_target = 100 # range 1-10000
302 | #constraint_exclusion = partition # on, off, or partition
303 | #cursor_tuple_fraction = 0.1 # range 0.0-1.0
304 | #from_collapse_limit = 8
305 | #join_collapse_limit = 8 # 1 disables collapsing of explicit
306 | # JOIN clauses
307 |
308 |
309 | #------------------------------------------------------------------------------
310 | # ERROR REPORTING AND LOGGING
311 | #------------------------------------------------------------------------------
312 |
313 | # - Where to Log -
314 |
315 | log_destination = 'syslog' # Valid values are combinations of
316 | # stderr, csvlog, syslog, and eventlog,
317 | # depending on platform. csvlog
318 | # requires logging_collector to be on.
319 |
320 | # This is used when logging to stderr:
321 | #logging_collector = off # Enable capturing of stderr and csvlog
322 | # into log files. Required to be on for
323 | # csvlogs.
324 | # (change requires restart)
325 |
326 | # These are only used if logging_collector is on:
327 | #log_directory = 'pg_log' # directory where log files are written,
328 | # can be absolute or relative to PGDATA
329 | #log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern,
330 | # can include strftime() escapes
331 | #log_file_mode = 0600 # creation mode for log files,
332 | # begin with 0 to use octal notation
333 | #log_truncate_on_rotation = off # If on, an existing log file with the
334 | # same name as the new log file will be
335 | # truncated rather than appended to.
336 | # But such truncation only occurs on
337 | # time-driven rotation, not on restarts
338 | # or size-driven rotation. Default is
339 | # off, meaning append to existing files
340 | # in all cases.
341 | #log_rotation_age = 1d # Automatic rotation of logfiles will
342 | # happen after that time. 0 disables.
343 | #log_rotation_size = 10MB # Automatic rotation of logfiles will
344 | # happen after that much log output.
345 | # 0 disables.
346 |
347 | # These are relevant when logging to syslog:
348 | #syslog_facility = 'LOCAL0'
349 | syslog_ident = 'nextcloud.postgres'
350 |
351 | # This is only relevant when logging to eventlog (win32):
352 | #event_source = 'PostgreSQL'
353 |
354 | # - When to Log -
355 |
356 | #client_min_messages = notice # values in order of decreasing detail:
357 | # debug5
358 | # debug4
359 | # debug3
360 | # debug2
361 | # debug1
362 | # log
363 | # notice
364 | # warning
365 | # error
366 |
367 | #log_min_messages = warning # values in order of decreasing detail:
368 | # debug5
369 | # debug4
370 | # debug3
371 | # debug2
372 | # debug1
373 | # info
374 | # notice
375 | # warning
376 | # error
377 | # log
378 | # fatal
379 | # panic
380 |
381 | #log_min_error_statement = error # values in order of decreasing detail:
382 | # debug5
383 | # debug4
384 | # debug3
385 | # debug2
386 | # debug1
387 | # info
388 | # notice
389 | # warning
390 | # error
391 | # log
392 | # fatal
393 | # panic (effectively off)
394 |
395 | #log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements
396 | # and their durations, > 0 logs only
397 | # statements running at least this number
398 | # of milliseconds
399 |
400 |
401 | # - What to Log -
402 |
403 | #debug_print_parse = off
404 | #debug_print_rewritten = off
405 | #debug_print_plan = off
406 | #debug_pretty_print = on
407 | #log_checkpoints = off
408 | #log_connections = off
409 | #log_disconnections = off
410 | #log_duration = off
411 | #log_error_verbosity = default # terse, default, or verbose messages
412 | #log_hostname = off
413 | #log_line_prefix = '' # special values:
414 | # %a = application name
415 | # %u = user name
416 | # %d = database name
417 | # %r = remote host and port
418 | # %h = remote host
419 | # %p = process ID
420 | # %t = timestamp without milliseconds
421 | # %m = timestamp with milliseconds
422 | # %i = command tag
423 | # %e = SQL state
424 | # %c = session ID
425 | # %l = session line number
426 | # %s = session start timestamp
427 | # %v = virtual transaction ID
428 | # %x = transaction ID (0 if none)
429 | # %q = stop here in non-session
430 | # processes
431 | # %% = '%'
432 | # e.g. '<%u%%%d> '
433 | #log_lock_waits = off # log lock waits >= deadlock_timeout
434 | #log_statement = 'none' # none, ddl, mod, all
435 | #log_temp_files = -1 # log temporary files equal or larger
436 | # than the specified size in kilobytes;
437 | # -1 disables, 0 logs all temp files
438 | #log_timezone = 'GMT'
439 |
440 |
441 | #------------------------------------------------------------------------------
442 | # RUNTIME STATISTICS
443 | #------------------------------------------------------------------------------
444 |
445 | # - Query/Index Statistics Collector -
446 |
447 | #track_activities = on
448 | #track_counts = on
449 | #track_io_timing = off
450 | #track_functions = none # none, pl, all
451 | #track_activity_query_size = 1024 # (change requires restart)
452 | #update_process_title = on
453 | #stats_temp_directory = 'pg_stat_tmp'
454 |
455 |
456 | # - Statistics Monitoring -
457 |
458 | #log_parser_stats = off
459 | #log_planner_stats = off
460 | #log_executor_stats = off
461 | #log_statement_stats = off
462 |
463 |
464 | #------------------------------------------------------------------------------
465 | # AUTOVACUUM PARAMETERS
466 | #------------------------------------------------------------------------------
467 |
468 | #autovacuum = on # Enable autovacuum subprocess? 'on'
469 | # requires track_counts to also be on.
470 | #log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and
471 | # their durations, > 0 logs only
472 | # actions running at least this number
473 | # of milliseconds.
474 | #autovacuum_max_workers = 3 # max number of autovacuum subprocesses
475 | # (change requires restart)
476 | #autovacuum_naptime = 1min # time between autovacuum runs
477 | #autovacuum_vacuum_threshold = 50 # min number of row updates before
478 | # vacuum
479 | #autovacuum_analyze_threshold = 50 # min number of row updates before
480 | # analyze
481 | #autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum
482 | #autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze
483 | #autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum
484 | # (change requires restart)
485 | #autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age
486 | # before forced vacuum
487 | # (change requires restart)
488 | #autovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for
489 | # autovacuum, in milliseconds;
490 | # -1 means use vacuum_cost_delay
491 | #autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for
492 | # autovacuum, -1 means use
493 | # vacuum_cost_limit
494 |
495 |
496 | #------------------------------------------------------------------------------
497 | # CLIENT CONNECTION DEFAULTS
498 | #------------------------------------------------------------------------------
499 |
500 | # - Statement Behavior -
501 |
502 | #search_path = '"$user",public' # schema names
503 | #default_tablespace = '' # a tablespace name, '' uses the default
504 | #temp_tablespaces = '' # a list of tablespace names, '' uses
505 | # only default tablespace
506 | #check_function_bodies = on
507 | #default_transaction_isolation = 'read committed'
508 | #default_transaction_read_only = off
509 | #default_transaction_deferrable = off
510 | #session_replication_role = 'origin'
511 | #statement_timeout = 0 # in milliseconds, 0 is disabled
512 | #lock_timeout = 0 # in milliseconds, 0 is disabled
513 | #vacuum_freeze_min_age = 50000000
514 | #vacuum_freeze_table_age = 150000000
515 | #vacuum_multixact_freeze_min_age = 5000000
516 | #vacuum_multixact_freeze_table_age = 150000000
517 | #bytea_output = 'hex' # hex, escape
518 | #xmlbinary = 'base64'
519 | #xmloption = 'content'
520 |
521 | # - Locale and Formatting -
522 |
523 | #datestyle = 'iso, mdy'
524 | #intervalstyle = 'postgres'
525 | #timezone = 'GMT'
526 | #timezone_abbreviations = 'Default' # Select the set of available time zone
527 | # abbreviations. Currently, there are
528 | # Default
529 | # Australia (historical usage)
530 | # India
531 | # You can create your own file in
532 | # share/timezonesets/.
533 | #extra_float_digits = 0 # min -15, max 3
534 | #client_encoding = sql_ascii # actually, defaults to database
535 | # encoding
536 |
537 | # These settings are initialized by initdb, but they can be changed.
538 | #lc_messages = 'C' # locale for system error message
539 | # strings
540 | #lc_monetary = 'C' # locale for monetary formatting
541 | #lc_numeric = 'C' # locale for number formatting
542 | #lc_time = 'C' # locale for time formatting
543 |
544 | # default configuration for text search
545 | #default_text_search_config = 'pg_catalog.simple'
546 |
547 | # - Other Defaults -
548 |
549 | #dynamic_library_path = '$libdir'
550 | #local_preload_libraries = ''
551 | #session_preload_libraries = ''
552 |
553 |
554 | #------------------------------------------------------------------------------
555 | # LOCK MANAGEMENT
556 | #------------------------------------------------------------------------------
557 |
558 | #deadlock_timeout = 1s
559 | #max_locks_per_transaction = 64 # min 10
560 | # (change requires restart)
561 | # Note: Each lock table slot uses ~270 bytes of shared memory, and there are
562 | # max_locks_per_transaction * (max_connections + max_prepared_transactions)
563 | # lock table slots.
564 | #max_pred_locks_per_transaction = 64 # min 10
565 | # (change requires restart)
566 |
567 |
568 | #------------------------------------------------------------------------------
569 | # VERSION/PLATFORM COMPATIBILITY
570 | #------------------------------------------------------------------------------
571 |
572 | # - Previous PostgreSQL Versions -
573 |
574 | #array_nulls = on
575 | #backslash_quote = safe_encoding # on, off, or safe_encoding
576 | #default_with_oids = off
577 | #escape_string_warning = on
578 | #lo_compat_privileges = off
579 | #quote_all_identifiers = off
580 | #sql_inheritance = on
581 | #standard_conforming_strings = on
582 | #synchronize_seqscans = on
583 |
584 | # - Other Platforms and Clients -
585 |
586 | #transform_null_equals = off
587 |
588 |
589 | #------------------------------------------------------------------------------
590 | # ERROR HANDLING
591 | #------------------------------------------------------------------------------
592 |
593 | #exit_on_error = off # terminate session on any error?
594 | #restart_after_crash = on # reinitialize after backend crash?
595 |
596 |
597 | #------------------------------------------------------------------------------
598 | # CONFIG FILE INCLUDES
599 | #------------------------------------------------------------------------------
600 |
601 | # These options allow settings to be loaded from files other than the
602 | # default postgresql.conf.
603 |
604 | #include_dir = 'conf.d' # include files ending in '.conf' from
605 | # directory 'conf.d'
606 | #include_if_exists = 'exists.conf' # include file only if it exists
607 | #include = 'special.conf' # include file
608 |
609 |
610 | #------------------------------------------------------------------------------
611 | # CUSTOMIZED OPTIONS
612 | #------------------------------------------------------------------------------
613 |
614 | # Add settings for extensions here
615 |
--------------------------------------------------------------------------------
/config/redis.conf:
--------------------------------------------------------------------------------
1 | port 0
2 | bind 127.0.0.1
3 | unixsocket /var/snap/nextcloud/current/redis.sock
4 | unixsocketperm 770
5 | maxmemory 50M
--------------------------------------------------------------------------------
/download.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -ex
2 |
3 | DIR=$( cd "$( dirname "$0" )" && pwd )
4 | cd ${DIR}
5 |
6 | ARCH=$(uname -m)
7 | DOWNLOAD_URL=https://github.com/syncloud/3rdparty/releases/download/
8 | VERSION=$1
9 | apt update
10 | apt install -y wget bzip2
11 |
12 | BUILD_DIR=${DIR}/build/snap
13 | mkdir -p $BUILD_DIR
14 |
15 | cd ${DIR}/build
16 | wget https://download.nextcloud.com/server/releases/nextcloud-${VERSION}.tar.bz2 -O nextcloud.tar.bz2
17 | tar xf nextcloud.tar.bz2
18 | mv nextcloud ${BUILD_DIR}
19 |
--------------------------------------------------------------------------------
/hooks/access-change:
--------------------------------------------------------------------------------
1 | #!/snap/nextcloud/current/python/bin/python
2 |
3 | from installer import Installer
4 | Installer().on_domain_change()
5 |
--------------------------------------------------------------------------------
/hooks/access-change.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 |
3 | print(subprocess.check_output('snap run nextcloud.access-change', shell=True))
4 |
5 |
--------------------------------------------------------------------------------
/hooks/backup-pre-stop:
--------------------------------------------------------------------------------
1 | #!/snap/nextcloud/current/python/bin/python
2 |
3 | from installer import Installer
4 | Installer().backup_pre_stop()
5 |
--------------------------------------------------------------------------------
/hooks/installer.py:
--------------------------------------------------------------------------------
1 | from os.path import isfile
2 | from os.path import join
3 | from os.path import realpath
4 |
5 | import logging
6 | import re
7 | import shutil
8 | import uuid
9 | from crontab import CronTab
10 | from subprocess import check_output
11 | from syncloudlib import fs, linux, gen, logger
12 | from syncloudlib.application import paths, urls, storage, service
13 |
14 | from octools import OCConsole, OCConfig
15 | from postgres import Database
16 |
17 | APP_NAME = 'nextcloud'
18 |
19 | USER_NAME = APP_NAME
20 | DB_NAME = APP_NAME
21 | DB_USER = APP_NAME
22 | DB_PASSWORD = APP_NAME
23 | OCC_RUNNER_PATH = 'bin/occ-runner'
24 | LOG_PATH = 'log/{0}.log'.format(APP_NAME)
25 | CRON_USER = APP_NAME
26 | APP_CONFIG_PATH = '{0}/config'.format(APP_NAME)
27 | PSQL_PORT = 5436
28 |
29 | SYSTEMD_NGINX = '{0}.nginx'.format(APP_NAME)
30 | SYSTEMD_PHP_FPM = '{0}.php-fpm'.format(APP_NAME)
31 | SYSTEMD_POSTGRESQL = '{0}.postgresql'.format(APP_NAME)
32 |
33 | class Installer:
34 | def __init__(self):
35 | if not logger.factory_instance:
36 | logger.init(logging.DEBUG, True)
37 |
38 | self.log = logger.get_logger('nextcloud_installer')
39 | self.app_dir = paths.get_app_dir(APP_NAME)
40 | self.common_dir = paths.get_data_dir(APP_NAME)
41 | self.data_dir = join('/var/snap', APP_NAME, 'current')
42 | self.config_dir = join(self.data_dir, 'config')
43 | self.extra_apps_dir = join(self.data_dir, 'extra-apps')
44 | self.occ = OCConsole(join(self.app_dir, OCC_RUNNER_PATH))
45 | self.nextcloud_config_path = join(self.data_dir, 'nextcloud', 'config')
46 | self.nextcloud_config_file = join(self.nextcloud_config_path, 'config.php')
47 | self.cron = Cron(CRON_USER)
48 | self.db = Database(self.app_dir, self.data_dir, self.config_dir, PSQL_PORT)
49 | self.oc_config = OCConfig(join(self.app_dir, 'bin/nextcloud-config'))
50 |
51 | def install_config(self):
52 |
53 | home_folder = join('/home', USER_NAME)
54 | linux.useradd(USER_NAME, home_folder=home_folder)
55 | storage.init_storage(APP_NAME, USER_NAME)
56 | templates_path = join(self.app_dir, 'config')
57 |
58 | variables = {
59 | 'app_dir': self.app_dir,
60 | 'common_dir': self.common_dir,
61 | 'data_dir': self.data_dir,
62 | 'db_psql_port': PSQL_PORT,
63 | 'database_dir': self.db.database_dir,
64 | 'config_dir': self.config_dir,
65 | 'domain': urls.get_app_domain_name(APP_NAME)
66 | }
67 | gen.generate_files(templates_path, self.config_dir, variables)
68 |
69 | fs.makepath(self.nextcloud_config_path)
70 | fs.makepath(join(self.common_dir, 'log'))
71 | fs.makepath(join(self.common_dir, 'nginx'))
72 |
73 | fs.makepath(self.extra_apps_dir)
74 |
75 | self.fix_permissions()
76 |
77 | def install(self):
78 | self.install_config()
79 |
80 | default_config_file = join(self.config_dir, 'config.php')
81 | shutil.copy(default_config_file, self.nextcloud_config_file)
82 | self.fix_config_permission()
83 |
84 | self.db.init()
85 | self.db.init_config()
86 |
87 | def pre_refresh(self):
88 | self.db.backup()
89 |
90 | def post_refresh(self):
91 | self.install_config()
92 | self.migrate_nextcloud_config_file()
93 | self.fix_version_specific_dbhost()
94 |
95 | self.db.remove()
96 | self.db.init()
97 |
98 | self.db.init_config()
99 |
100 | def configure(self):
101 |
102 | if self.installed():
103 | self.upgrade()
104 | else:
105 | self.initialize()
106 |
107 | app_storage_dir = storage.get_storage_dir(APP_NAME)
108 | self.occ.run('ldap:set-config s01 ldapEmailAttribute mail')
109 | self.occ.run('config:system:set apps_paths 1 path --value="{0}"'.format(self.extra_apps_dir))
110 | self.occ.run('config:system:set dbhost --value="{0}"'.format(self.db.database_host))
111 | # migrate to systemd cron units
112 | self.cron.remove()
113 | self.cron.create()
114 |
115 | self.occ.run("config:system:set memcache.local --value='\\OC\\Memcache\\APCu'")
116 | self.occ.run("config:system:set redis host --value=/var/snap/nextcloud/current/redis.sock")
117 | self.occ.run("config:system:set redis port --value=0")
118 | self.occ.run("config:system:set memcache.distributed --value='\\OC\\Memcache\\Redis'")
119 | self.occ.run("config:system:set memcache.locking --value='\\OC\\Memcache\\Redis'")
120 | self.occ.run("config:system:set maintenance_window_start --value=1")
121 | self.oc_config.set_value('loglevel', '2')
122 | self.oc_config.set_value('logfile', join(self.common_dir, LOG_PATH))
123 | real_app_storage_dir = realpath(app_storage_dir)
124 | self.oc_config.set_value('datadirectory', real_app_storage_dir)
125 | # oc_config.set_value('integrity.check.disabled', 'true')
126 | self.oc_config.set_value('mail_smtpmode', 'smtp')
127 | self.oc_config.set_value('mail_smtphost', 'localhost:25')
128 | # oc_config.set_value('mail_smtpsecure', '')
129 | self.oc_config.set_value('mail_smtpauth', 'false')
130 | # oc_config.set_value('mail_smtpname', '')
131 | # oc_config.set_value('mail_smtppassword', '')
132 |
133 | self.occ.run("app:disable logreader")
134 |
135 | self.on_domain_change()
136 |
137 | self.fix_permissions()
138 |
139 | def fix_permissions(self):
140 | check_output('chown -R {0}.{0} {1}'.format(USER_NAME, self.common_dir), shell=True)
141 | check_output('chown -R {0}.{0} {1}/'.format(USER_NAME, self.data_dir), shell=True)
142 |
143 | def migrate_nextcloud_config_file(self):
144 | if not isfile(self.nextcloud_config_file):
145 | old_nextcloud_config_file = join(self.common_dir, 'nextcloud', 'config', 'config.php')
146 | if isfile(old_nextcloud_config_file):
147 | shutil.copy(old_nextcloud_config_file, self.nextcloud_config_file)
148 | self.fix_config_permission()
149 |
150 | def fix_config_permission(self):
151 | fs.chownpath(self.nextcloud_config_file, USER_NAME)
152 |
153 | def fix_version_specific_dbhost(self):
154 | content = self.read_nextcloud_config()
155 | pattern = r"'dbhost'\s*=>\s*'.*?'"
156 | replacement = "'dbhost' => '{0}'".format(self.db.database_host)
157 | new_content = re.sub(pattern, replacement, content)
158 | self.write_nextcloud_config(new_content)
159 | self.fix_config_permission()
160 |
161 | def read_nextcloud_config(self):
162 | with open(self.nextcloud_config_file) as f:
163 | return f.read()
164 |
165 | def write_nextcloud_config(self, content):
166 | with open(self.nextcloud_config_file, "w") as f:
167 | f.write(content)
168 |
169 | def installed(self):
170 | return 'installed' in open(self.nextcloud_config_file).read().strip()
171 |
172 | def upgrade(self):
173 | self.db.restore()
174 | self.prepare_storage()
175 | status = self.occ.run('status')
176 | self.log.info('status: {0}'.format(status))
177 | # if 'require upgrade' in status:
178 | self.log.info('upgrading nextcloud')
179 | # self.occ.run('maintenance:mode --on')
180 | self.occ.run('upgrade')
181 | # self.occ.run('app:update --all')
182 | self.occ.run('maintenance:mode --off')
183 | self.occ.run('db:add-missing-indices')
184 | self.occ.run('db:add-missing-columns')
185 | self.occ.run('db:add-missing-primary-keys')
186 | # else:
187 | # self.log.info('not upgrading nextcloud')
188 |
189 | def initialize(self):
190 | self.prepare_storage()
191 | app_storage_dir = storage.get_storage_dir(APP_NAME)
192 | self.db.execute('postgres', DB_USER, "ALTER USER {0} WITH PASSWORD '{1}';".format(DB_USER, DB_PASSWORD))
193 | self.db.execute('postgres', DB_USER, "CREATE DATABASE nextcloud OWNER {0} TEMPLATE template0 ENCODING 'UTF8';".format(DB_USER))
194 | self.db.execute('postgres', DB_USER, "GRANT CREATE ON SCHEMA public TO {0};".format(DB_USER))
195 |
196 | real_app_storage_dir = realpath(app_storage_dir)
197 | install_user_name = 'installer-{0}'.format(uuid.uuid4().hex)
198 | install_user_password = uuid.uuid4().hex
199 | self.occ.run('maintenance:install --database pgsql --database-host {0}:{1}'
200 | ' --database-name nextcloud --database-user {2} --database-pass {3}'
201 | ' --admin-user {4} --admin-pass {5} --data-dir {6}'
202 | .format(self.db.get_database_path(), PSQL_PORT, DB_USER, DB_PASSWORD,
203 | install_user_name, install_user_password, real_app_storage_dir))
204 |
205 | self.occ.run('app:enable user_ldap')
206 |
207 | # https://doc.owncloud.org/server/8.0/admin_manual/configuration_server/occ_command.html
208 | self.occ.run('ldap:create-empty-config')
209 |
210 | self.occ.run('ldap:set-config s01 ldapHost ldap://localhost')
211 | self.occ.run('ldap:set-config s01 ldapPort 389')
212 | self.occ.run('ldap:set-config s01 ldapAgentName cn=admin,dc=syncloud,dc=org')
213 | self.occ.run('ldap:set-config s01 ldapBase dc=syncloud,dc=org')
214 | self.occ.run('ldap:set-config s01 ldapAgentPassword syncloud')
215 |
216 | self.occ.run('ldap:set-config s01 hasMemberOfFilterSupport 0')
217 | self.occ.run('ldap:set-config s01 ldapLoginFilter "(&(|(objectclass=inetOrgPerson))(cn=%uid))"')
218 |
219 | self.occ.run('ldap:set-config s01 ldapUserFilter "(|(objectclass=inetOrgPerson))"')
220 | self.occ.run('ldap:set-config s01 ldapUserFilterObjectclass inetOrgPerson')
221 |
222 | self.occ.run('ldap:set-config s01 ldapBaseUsers ou=users,dc=syncloud,dc=org')
223 | self.occ.run('ldap:set-config s01 ldapUserDisplayName cn')
224 | self.occ.run('ldap:set-config s01 ldapExpertUsernameAttr cn')
225 |
226 | self.occ.run('ldap:set-config s01 ldapGroupFilterObjectclass posixGroup')
227 | self.occ.run('ldap:set-config s01 ldapGroupDisplayName cn')
228 | self.occ.run('ldap:set-config s01 ldapBaseGroups ou=groups,dc=syncloud,dc=org')
229 | self.occ.run('ldap:set-config s01 ldapGroupFilter "(&(|(objectclass=posixGroup)))"')
230 | # self.occ.run('ldap:set-config s01 ldapGroupFilterGroups syncloud')
231 | self.occ.run('ldap:set-config s01 ldapGroupMemberAssocAttr memberUid')
232 |
233 | self.occ.run('ldap:set-config s01 ldapTLS 0')
234 | self.occ.run('ldap:set-config s01 turnOffCertCheck 1')
235 | self.occ.run('ldap:set-config s01 ldapConfigurationActive 1')
236 |
237 | self.occ.run('db:convert-filecache-bigint')
238 |
239 | # cron takes a lot of time and fails the installation on big existing file storage
240 | self.cron.run()
241 |
242 | self.db.execute(DB_NAME, DB_USER, "select * from oc_ldap_group_mapping;")
243 | self.db.execute(DB_NAME, DB_USER,
244 | "update oc_ldap_group_mapping set owncloud_name = 'admin' where owncloud_name = 'syncloud';")
245 |
246 | self.occ.run('user:delete {0}'.format(install_user_name))
247 | self.occ.run('db:add-missing-indices')
248 | self.occ.run('ldap:promote-group admin -y')
249 |
250 | def on_disk_change(self):
251 | storage.init_storage(APP_NAME, USER_NAME)
252 | self.prepare_storage()
253 | self.occ.run('config:system:delete instanceid')
254 | service.restart(SYSTEMD_PHP_FPM)
255 | service.restart(SYSTEMD_NGINX)
256 |
257 | def prepare_storage(self):
258 | app_storage_dir = storage.get_storage_dir(APP_NAME)
259 | ncdata = join(app_storage_dir, '.ncdata')
260 | fs.touchfile(ncdata)
261 | check_output('chown {0}. {1}'.format(USER_NAME, ncdata), shell=True)
262 | check_output('chmod 777 {0}'.format(app_storage_dir), shell=True)
263 | tmp_storage_path = join(app_storage_dir, 'tmp')
264 | fs.makepath(tmp_storage_path)
265 | fs.chownpath(tmp_storage_path, USER_NAME)
266 | real_app_storage_dir = realpath(app_storage_dir)
267 | self.fix_datadirectory(real_app_storage_dir)
268 |
269 | def on_domain_change(self):
270 | app_domain = urls.get_app_domain_name(APP_NAME)
271 | local_ip = check_output(["hostname", "-I"]).decode().split(" ")[0]
272 | self.oc_config.set_value('trusted_domains', "localhost {0} {1}".format(local_ip, app_domain))
273 | self.oc_config.set_value('trusted_proxies', "127.0.0.1 {0}".format(local_ip))
274 | self.oc_config.set_value('overwrite.cli.url', "https://{0}".format(app_domain))
275 |
276 | def backup_pre_stop(self):
277 | self.pre_refresh()
278 |
279 | def restore_pre_start(self):
280 | self.post_refresh()
281 |
282 | def restore_post_start(self):
283 | self.configure()
284 |
285 | def fix_datadirectory(self, dir):
286 | content = self.read_nextcloud_config()
287 | pattern = r"'datadirectory'\s*=>\s*'.*?'"
288 | replacement = "'datadirectory' => '{0}'".format(dir)
289 | new_content = re.sub(pattern, replacement, content)
290 | self.write_nextcloud_config(new_content)
291 | self.fix_config_permission()
292 |
293 |
294 | class Cron:
295 |
296 | def __init__(self, cron_user):
297 | self.cron_cmd = '/usr/bin/snap run nextcloud.cron'
298 | self.cron_user = cron_user
299 | self.log = logger.get_logger('cron')
300 |
301 | def remove(self):
302 | print("remove crontab task")
303 | cron = CronTab(user=self.cron_user)
304 | for job in cron.find_command(self.cron_user):
305 | cron.remove(job)
306 | cron.write()
307 |
308 | def create(self):
309 | cron = CronTab(user=self.cron_user)
310 | print("create crontab task")
311 | ci_job = cron.new(command=self.cron_cmd)
312 | ci_job.setall('*/15 * * * *')
313 | cron.write()
314 |
315 | def run(self):
316 | self.log.info("running: {0}".format(self.cron_cmd))
317 | self.log.info(check_output(self.cron_cmd, shell=True))
318 |
--------------------------------------------------------------------------------
/hooks/octools.py:
--------------------------------------------------------------------------------
1 | from subprocess import check_output, CalledProcessError
2 | from syncloudlib import logger
3 |
4 |
5 | class OCConsole:
6 | def __init__(self, occ_runner_path):
7 | self.occ_runner_path = occ_runner_path
8 | self.log = logger.get_logger('nextcloud_occ')
9 |
10 | def run(self, args):
11 | self.log.info(f'running: {self.occ_runner_path} {args}')
12 | try:
13 | output = check_output('{0} {1}'.format(self.occ_runner_path, args), shell=True).decode().strip()
14 | if output:
15 | self.log.info(output)
16 | return output
17 | except CalledProcessError as e:
18 | self.log.error("occ error: " + e.output.decode())
19 | raise e
20 |
21 |
22 | class OCConfig:
23 | def __init__(self, oc_config_path):
24 | self.oc_config_path = oc_config_path
25 | self.log = logger.get_logger('nextcloud_config')
26 |
27 | def set_value(self, key, value):
28 | self.log.info('setting value: {0} = {1}'.format(key, value))
29 | try:
30 | output = check_output('{0} {1} {2}'.format(
31 | self.oc_config_path,
32 | key,
33 | value), shell=True).decode().strip()
34 | if output:
35 | self.log.info(output)
36 | except CalledProcessError as e:
37 | self.log.error("occ config error: " + e.output.decode())
38 | raise e
39 |
--------------------------------------------------------------------------------
/hooks/postgres.py:
--------------------------------------------------------------------------------
1 | import shutil
2 | from os.path import join, isfile, isdir
3 | from subprocess import check_output, CalledProcessError
4 |
5 | from syncloudlib import logger
6 |
7 |
8 | class Database:
9 |
10 | def __init__(self, app_dir, data_dir, config_path, port):
11 | self.log = logger.get_logger('database')
12 | self.app_dir = app_dir
13 | self.config_path = config_path
14 | self.data_dir = data_dir
15 | self.postgresql_config = join(self.config_path, 'postgresql.conf')
16 | self.database_dir = join(self.data_dir, 'database')
17 | self.old_major_version_file = join(self.data_dir, 'db.major.version')
18 | self.new_major_version_file = join(self.app_dir, 'db.major.version')
19 | self.backup_file = join(self.data_dir, 'database.dump')
20 | self.database_host = '{0}:{1}'.format(self.database_dir, port)
21 |
22 | def get_database_path(self):
23 | return self.database_dir
24 |
25 | def remove(self):
26 | if not isfile(self.backup_file):
27 | raise Exception("Backup file does not exist: {0}".format(self.backup_file))
28 |
29 | if isdir(self.database_dir):
30 | shutil.rmtree(self.database_dir)
31 |
32 | def init(self):
33 | self.run('{0}/bin/initdb.sh {1}'.format(self.app_dir, self.database_dir))
34 |
35 | def init_config(self):
36 | shutil.copy(self.postgresql_config, self.database_dir)
37 |
38 | def execute(self, database, user, sql):
39 | self.run('snap run nextcloud.psql -U {0} -d {1} -c "{2}"'.format(user, database, sql))
40 |
41 | def restore(self):
42 | self.run('snap run nextcloud.psql -f {0} postgres'.format(self.backup_file))
43 |
44 | def backup(self):
45 | self.run('snap run nextcloud.pgdumpall -f {0}'.format(self.backup_file))
46 | shutil.copy(self.new_major_version_file, self.old_major_version_file)
47 |
48 | def run(self, cmd):
49 | try:
50 | self.log.info("postgres executing: {0}".format(cmd))
51 | output = check_output(cmd, shell=True).decode()
52 | self.log.info(output)
53 | except CalledProcessError as e:
54 | self.log.error("postgres error: " + e.output.decode())
55 | raise e
56 |
--------------------------------------------------------------------------------
/hooks/restore-post-start:
--------------------------------------------------------------------------------
1 | #!/snap/nextcloud/current/python/bin/python
2 |
3 | from installer import Installer
4 | Installer().restore_post_start()
5 |
--------------------------------------------------------------------------------
/hooks/restore-pre-start:
--------------------------------------------------------------------------------
1 | #!/snap/nextcloud/current/python/bin/python
2 |
3 | from installer import Installer
4 | Installer().restore_pre_start()
5 |
--------------------------------------------------------------------------------
/hooks/storage-change:
--------------------------------------------------------------------------------
1 | #!/snap/nextcloud/current/python/bin/python
2 |
3 | from installer import Installer
4 | Installer().on_disk_change()
5 |
--------------------------------------------------------------------------------
/hooks/storage-change.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 |
3 | print(subprocess.check_output('snap run nextcloud.storage-change', shell=True))
4 |
--------------------------------------------------------------------------------
/meta/hooks/configure:
--------------------------------------------------------------------------------
1 | #!/snap/nextcloud/current/python/bin/python
2 |
3 | import os, sys
4 | sys.path.append(os.path.join(os.environ['SNAP'], 'hooks'))
5 |
6 | from installer import Installer
7 | Installer().configure()
8 |
--------------------------------------------------------------------------------
/meta/hooks/install:
--------------------------------------------------------------------------------
1 | #!/snap/nextcloud/current/python/bin/python
2 |
3 | import os, sys
4 | sys.path.append(os.path.join(os.environ['SNAP'], 'hooks'))
5 |
6 | from installer import Installer
7 | Installer().install()
8 |
--------------------------------------------------------------------------------
/meta/hooks/post-refresh:
--------------------------------------------------------------------------------
1 | #!/snap/nextcloud/current/python/bin/python
2 |
3 | import os, sys
4 | sys.path.append(os.path.join(os.environ['SNAP'], 'hooks'))
5 |
6 | from installer import Installer
7 | Installer().post_refresh()
8 |
--------------------------------------------------------------------------------
/meta/hooks/pre-refresh:
--------------------------------------------------------------------------------
1 | #!/snap/nextcloud/current/python/bin/python
2 |
3 | import os, sys
4 | sys.path.append(os.path.join(os.environ['SNAP'], 'hooks'))
5 |
6 | from installer import Installer
7 | Installer().pre_refresh()
8 |
--------------------------------------------------------------------------------
/meta/snap.yaml:
--------------------------------------------------------------------------------
1 | apps:
2 | postgresql:
3 | user: nextcloud
4 | command: bin/service.postgresql.sh start
5 | daemon: forking
6 | plugs:
7 | - network
8 | - network-bind
9 | restart-condition: always
10 | before: [php-fpm]
11 |
12 | redis:
13 | user: nextcloud
14 | daemon: simple
15 | command: bin/service.redis.sh
16 | restart-condition: always
17 | before: [php-fpm]
18 |
19 | php-fpm:
20 | user: nextcloud
21 | command: bin/service.php-fpm.sh start
22 | daemon: forking
23 | plugs:
24 | - network
25 | - network-bind
26 | restart-condition: always
27 | post-start-command: bin/service.php-fpm.sh post-start
28 | after: [postgresql]
29 | before: [nginx]
30 |
31 | nginx:
32 | command: bin/service.nginx.sh
33 | user: nextcloud
34 | daemon: simple
35 | plugs:
36 | - network
37 | - network-bind
38 | restart-condition: always
39 |
40 | occ:
41 | command: bin/occ-runner
42 |
43 | psql:
44 | command: bin/psql.sh
45 |
46 | pgdumpall:
47 | command: bin/pg_dumpall.sh
48 |
49 | cron:
50 | command: bin/nextcloud-cron
51 |
52 | php:
53 | command: bin/php-runner
54 |
55 | storage-change:
56 | command: hooks/storage-change
57 |
58 | access-change:
59 | command: hooks/access-change
60 |
61 | backup-pre-stop:
62 | command: hooks/backup-pre-stop
63 |
64 | restore-pre-start:
65 | command: hooks/restore-pre-start
66 |
67 | restore-post-start:
68 | command: hooks/restore-post-start
69 |
70 | confinement: strict
71 | description: Nextcloud
72 | grade: stable
73 | name: nextcloud
74 | summary: Nextcloud
75 |
--------------------------------------------------------------------------------
/nginx/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -ex
2 |
3 | DIR=$( cd "$( dirname "$0" )" && pwd )
4 | cd ${DIR}
5 | VERSION=$1
6 | BUILD_DIR=${DIR}/../build/snap/nginx
7 | while ! docker create --name=nginx nginx:$VERSION ; do
8 | sleep 1
9 | echo "retry docker"
10 | done
11 | mkdir -p ${BUILD_DIR}
12 | cd ${BUILD_DIR}
13 | docker export nginx -o app.tar
14 | tar xf app.tar
15 | rm -rf app.tar
16 | cp ${DIR}/nginx.sh ${BUILD_DIR}/bin/
17 |
--------------------------------------------------------------------------------
/nginx/nginx.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
3 | LIBS=$(echo ${DIR}/lib/*-linux-gnu*)
4 | LIBS=$LIBS:$(echo ${DIR}/usr/lib/*-linux-gnu*)
5 | ${DIR}/lib/*-linux*/ld-*.so --library-path $LIBS ${DIR}/usr/sbin/nginx "$@"
6 |
--------------------------------------------------------------------------------
/package.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 |
3 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
4 | cd ${DIR}
5 |
6 | if [[ -z "$2" ]]; then
7 | echo "usage $0 app version"
8 | exit 1
9 | fi
10 |
11 | NAME=$1
12 | VERSION=$2
13 | ARCH=$(dpkg --print-architecture)
14 |
15 | SNAP_DIR=${DIR}/build/snap
16 |
17 | apt update
18 | apt -y install squashfs-tools
19 |
20 | cp -r ${DIR}/bin ${SNAP_DIR}
21 | cp -r ${DIR}/config ${SNAP_DIR}
22 | cp -r ${DIR}/hooks ${SNAP_DIR}
23 | cp -r ${DIR}/meta ${SNAP_DIR}
24 |
25 | echo "version: $VERSION" >> ${SNAP_DIR}/meta/snap.yaml
26 | echo "architectures:" >> ${SNAP_DIR}/meta/snap.yaml
27 | echo "- ${ARCH}" >> ${SNAP_DIR}/meta/snap.yaml
28 |
29 | PACKAGE=${NAME}_${VERSION}_${ARCH}.snap
30 | echo ${PACKAGE} > ${DIR}/package.name
31 | mksquashfs ${SNAP_DIR} ${DIR}/${PACKAGE} -noappend -comp xz -no-xattrs -all-root
32 | mkdir ${DIR}/artifact
33 | cp ${DIR}/${PACKAGE} ${DIR}/artifact
34 |
--------------------------------------------------------------------------------
/php/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.3.9-fpm-bullseye
2 | RUN apt-get update && apt-get install -y \
3 | libfreetype6-dev \
4 | libjpeg62-turbo-dev \
5 | libpng-dev \
6 | libzip-dev \
7 | libsmbclient-dev \
8 | libxml2-dev \
9 | libsqlite3-dev \
10 | libpq-dev \
11 | libldap2-dev \
12 | libsasl2-dev \
13 | libfreetype6-dev \
14 | liblqr-1-0-dev \
15 | libfftw3-dev \
16 | libjbig-dev \
17 | libtiff5-dev \
18 | libwebp-dev \
19 | libmemcached-dev \
20 | libmcrypt-dev \
21 | zip \
22 | wget \
23 | unzip \
24 | libgmp-dev \
25 | libonig-dev \
26 | libicu-dev \
27 | libmagickwand-dev \
28 | libbz2-dev \
29 | git \
30 | --no-install-recommends
31 |
32 | RUN mkdir -p /usr/src/php/ext/memcached
33 | WORKDIR /usr/src/php/ext/memcached
34 | RUN wget https://github.com/php-memcached-dev/php-memcached/archive/v3.1.5.zip; unzip /usr/src/php/ext/memcached/v*.zip
35 | RUN mv /usr/src/php/ext/memcached/php-memcached-*/* /usr/src/php/ext/memcached/
36 |
37 | RUN docker-php-ext-install bz2
38 | RUN docker-php-ext-configure memcached
39 | RUN docker-php-ext-install memcached
40 | RUN docker-php-ext-install gmp
41 | #RUN pecl install imagick
42 | RUN git clone https://github.com/Imagick/imagick.git --depth 1 /tmp/imagick && \
43 | cd /tmp/imagick && \
44 | git fetch origin master && \
45 | git switch master && \
46 | cd /tmp/imagick && \
47 | phpize && \
48 | ./configure && \
49 | make && \
50 | make install && \
51 | docker-php-ext-enable imagick
52 |
53 | RUN pecl install smbclient
54 | RUN pecl install apcu
55 | RUN pecl install mcrypt-1.0.7
56 | RUN pecl install redis
57 | RUN docker-php-ext-enable redis
58 | RUN docker-php-ext-configure intl
59 | RUN docker-php-ext-install intl
60 | RUN docker-php-ext-enable apcu
61 | RUN docker-php-ext-install ldap
62 | RUN docker-php-ext-enable mcrypt
63 | RUN docker-php-ext-install bcmath
64 | RUN docker-php-ext-install pdo_mysql
65 | RUN docker-php-ext-install mysqli
66 | RUN docker-php-ext-install mbstring
67 | RUN docker-php-ext-install opcache
68 | RUN docker-php-ext-install zip
69 | RUN docker-php-ext-install pcntl
70 | RUN docker-php-ext-install exif
71 | RUN docker-php-ext-install sysvsem
72 | #RUN docker-php-ext-enable imagick
73 |
74 | RUN docker-php-ext-enable smbclient
75 | RUN docker-php-ext-install pdo pdo_pgsql
76 | RUN docker-php-ext-configure gd --with-freetype --with-jpeg
77 | RUN docker-php-ext-install -j2 gd
78 | RUN rm -rf /var/lib/apt/lists/*
79 | RUN apt remove -y git
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/php/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -xe
2 |
3 | DIR=$( cd "$( dirname "$0" )" && pwd )
4 | cd ${DIR}
5 |
6 | BUILD_DIR=${DIR}/../build/snap/php
7 |
8 | docker ps -a -q --filter ancestor=php:syncloud --format="{{.ID}}" | xargs docker stop | xargs docker rm || true
9 | docker rmi php:syncloud || true
10 | docker build -t php:syncloud .
11 | docker run php:syncloud php -i
12 | docker create --name=php php:syncloud
13 | mkdir -p ${BUILD_DIR}
14 | cd ${BUILD_DIR}
15 | docker export php -o php.tar
16 | tar xf php.tar
17 | rm -rf php.tar
18 | mv ${BUILD_DIR}/usr/lib/*-linux*/ImageMagick-*/modules-*/coders ${BUILD_DIR}/usr/lib/ImageMagickCoders
19 | ls -la ${BUILD_DIR}/usr/lib/ImageMagickCoders
20 | cp ${DIR}/php.sh ${BUILD_DIR}/bin
21 | cp ${DIR}/php-fpm.sh ${BUILD_DIR}/bin
22 | mkdir -p ${BUILD_DIR}/lib/php/extensions
23 | mv ${BUILD_DIR}/usr/local/lib/php/extensions/*/*.so ${BUILD_DIR}/lib/php/extensions
24 | rm -rf ${BUILD_DIR}/usr/src
25 |
--------------------------------------------------------------------------------
/php/php-fpm.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
3 | LIBS=$(echo ${DIR}/lib/*-linux-gnu*)
4 | LIBS=$LIBS:$(echo ${DIR}/usr/lib/*-linux-gnu*)
5 | LIBS=$LIBS:$(echo ${DIR}/usr/lib)
6 | LIBS=$LIBS:$(echo ${DIR}/usr/lib/*-linux-gnu*/samba)
7 | MAGICK_CODER_MODULE_PATH=$(echo ${DIR}/usr/lib/ImageMagickCoders) PHP_INI_SCAN_DIR=${DIR}/usr/local/etc/php/conf.d ${DIR}/lib/*-linux*/ld-*.so --library-path $LIBS ${DIR}/usr/local/sbin/php-fpm "$@"
8 |
--------------------------------------------------------------------------------
/php/php.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
3 | LIBS=$(echo ${DIR}/lib/*-linux-gnu*)
4 | LIBS=$LIBS:$(echo ${DIR}/usr/lib/*-linux-gnu*)
5 | LIBS=$LIBS:$(echo ${DIR}/usr/lib)
6 | LIBS=$LIBS:$(echo ${DIR}/usr/lib/*-linux-gnu*/samba)
7 | MAGICK_CODER_MODULE_PATH=$(echo ${DIR}/usr/lib/ImageMagickCoders) PHP_INI_SCAN_DIR=${DIR}/usr/local/etc/php/conf.d ${DIR}/lib/*-linux*/ld-*.so --library-path $LIBS ${DIR}/usr/local/bin/php "$@"
8 |
--------------------------------------------------------------------------------
/postgresql/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG MAJOR_VERSION
2 | FROM postgres:$MAJOR_VERSION-bullseye
--------------------------------------------------------------------------------
/postgresql/bin/initdb.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
3 | LIBS=$(echo ${DIR}/lib/*linux*/)
4 | LIBS=$LIBS:$(echo ${DIR}/usr/lib/*linux*)
5 | exec ${DIR}/lib/*/ld-*.so --library-path $LIBS ${DIR}/usr/lib/postgresql/*/bin/initdb "$@"
6 |
--------------------------------------------------------------------------------
/postgresql/bin/pg_ctl.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
3 | LIBS=$(echo ${DIR}/lib/*linux*/)
4 | LIBS=$LIBS:$(echo ${DIR}/usr/lib/*linux*)
5 | exec ${DIR}/lib/*/ld-*.so --library-path $LIBS ${DIR}/usr/lib/postgresql/*/bin/pg_ctl "$@"
6 |
--------------------------------------------------------------------------------
/postgresql/bin/pg_dumpall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
3 | LIBS=$(echo ${DIR}/lib/*linux*/)
4 | LIBS=$LIBS:$(echo ${DIR}/usr/lib/*linux*)
5 | exec ${DIR}/lib/*/ld-*.so --library-path $LIBS ${DIR}/usr/lib/postgresql/*/bin/pg_dumpall "$@"
6 |
--------------------------------------------------------------------------------
/postgresql/bin/psql.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
3 | LIBS=$(echo ${DIR}/lib/*linux*/)
4 | LIBS=$LIBS:$(echo ${DIR}/usr/lib/*linux*)
5 | exec ${DIR}/lib/*/ld-*.so --library-path $LIBS ${DIR}/usr/lib/postgresql/*/bin/psql "$@"
6 |
--------------------------------------------------------------------------------
/postgresql/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -ex
2 |
3 | DIR=$( cd "$( dirname "$0" )" && pwd )
4 | cd ${DIR}
5 |
6 | MAJOR_VERSION=16
7 |
8 | BUILD_DIR=${DIR}/../build/snap/postgresql
9 |
10 | docker ps -a -q --filter ancestor=postgres:syncloud --format="{{.ID}}" | xargs docker stop | xargs docker rm || true
11 | docker rmi postgres:syncloud || true
12 | docker build --build-arg MAJOR_VERSION=$MAJOR_VERSION -t postgres:syncloud .
13 | docker run postgres:syncloud postgres --help
14 | docker create --name=postgres postgres:syncloud
15 | mkdir -p ${BUILD_DIR}
16 | cd ${BUILD_DIR}
17 | echo "${MAJOR_VERSION}" > ${BUILD_DIR}/../db.major.version
18 | docker export postgres -o postgres.tar
19 | tar xf postgres.tar
20 | rm -rf postgres.tar
21 | ls -la
22 | ls -la bin
23 | ls -la usr/bin
24 | ls -ls usr/share/postgresql-common/pg_wrapper
25 | PGBIN=$(echo usr/lib/postgresql/*/bin)
26 | ldd $PGBIN/initdb || true
27 | mv $PGBIN/postgres $PGBIN/postgres.bin
28 | mv $PGBIN/pg_dump $PGBIN/pg_dump.bin
29 | cp $DIR/bin/* bin
30 | cp $DIR/pgbin/* $PGBIN
31 |
--------------------------------------------------------------------------------
/postgresql/pgbin/pg_dump:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd ../../../../.. && pwd )
3 | LIBS=$(echo ${DIR}/lib/*linux*/)
4 | LIBS=$LIBS:$(echo ${DIR}/usr/lib/*linux*)
5 | exec ${DIR}/lib/*/ld-*.so --library-path $LIBS ${DIR}/usr/lib/postgresql/*/bin/pg_dump.bin "$@"
6 |
--------------------------------------------------------------------------------
/postgresql/pgbin/postgres:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd ../../../../.. && pwd )
3 | LIBS=$(echo ${DIR}/lib/*linux*/)
4 | LIBS=$LIBS:$(echo ${DIR}/usr/lib/*linux*)
5 | exec ${DIR}/lib/*/ld-*.so --library-path $LIBS ${DIR}/usr/lib/postgresql/*/bin/postgres.bin "$@"
6 |
--------------------------------------------------------------------------------
/python/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.8-slim-buster
2 | COPY requirements.txt /
3 | RUN pip install -r /requirements.txt
4 | RUN rm -rf /var/lib/apt/lists/*
--------------------------------------------------------------------------------
/python/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -ex
2 |
3 | DIR=$( cd "$( dirname "$0" )" && pwd )
4 | cd ${DIR}
5 |
6 | BUILD_DIR=${DIR}/../build/snap/python
7 | docker ps -a -q --filter ancestor=python:syncloud --format="{{.ID}}" | xargs docker stop | xargs docker rm || true
8 | docker rmi python:syncloud || true
9 | docker build -t python:syncloud .
10 | docker run python:syncloud python --help
11 | docker create --name=python python:syncloud
12 | mkdir -p ${BUILD_DIR}
13 | cd ${BUILD_DIR}
14 | docker export python -o python.tar
15 | tar xf python.tar
16 | rm -rf python.tar
17 | cp ${DIR}/python ${BUILD_DIR}/bin/
18 | ls -la ${BUILD_DIR}/bin
19 | rm -rf ${BUILD_DIR}/usr/src
20 |
--------------------------------------------------------------------------------
/python/python:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
3 | LIBS=$(echo ${DIR}/lib/*-linux-gnu*)
4 | LIBS=$LIBS:$(echo ${DIR}/lib/*-linux-gnu*)
5 | LIBS=$LIBS:$(echo ${DIR}/usr/lib/*-linux-gnu*)
6 | LIBS=$LIBS:$(echo ${DIR}/usr/local/lib)
7 | ${DIR}/lib/*-linux*/ld-*.so --library-path $LIBS ${DIR}/usr/local/bin/python3 "$@"
8 |
--------------------------------------------------------------------------------
/python/requirements.txt:
--------------------------------------------------------------------------------
1 | beautifulsoup4==4.4.0
2 | requests-unixsocket==0.1.5
3 | massedit==0.67.1
4 | python-crontab==1.7.2
5 | syncloud-lib==278
6 |
--------------------------------------------------------------------------------
/redis/bin/redis.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )
3 | LIBS=$(echo ${DIR}/lib/*-linux-gnu*)
4 | exec ${DIR}/lib/*-linux*/ld-*.so.* --library-path $LIBS ${DIR}/usr/local/bin/redis-server "$@"
--------------------------------------------------------------------------------
/redis/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -ex
2 |
3 | DIR=$( cd "$( dirname "$0" )" && pwd )
4 | cd ${DIR}
5 | BUILD_DIR=${DIR}/../build/snap/redis
6 | mkdir $BUILD_DIR
7 | cp -r /usr ${BUILD_DIR}
8 | cp -r /lib ${BUILD_DIR}
9 | cp -r ${DIR}/bin ${BUILD_DIR}/bin
10 |
--------------------------------------------------------------------------------
/redis/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -ex
2 |
3 | DIR=$( cd "$( dirname "$0" )" && pwd )
4 | cd ${DIR}
5 | BUILD_DIR=${DIR}/../build/snap/redis
6 | $BUILD_DIR/bin/redis.sh -v
7 |
--------------------------------------------------------------------------------
/test/.gitignore:
--------------------------------------------------------------------------------
1 | screenshot
2 | firefox
3 | *.xpi
4 | debug.py
5 | *.png
--------------------------------------------------------------------------------
/test/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncloud/nextcloud/bf69613b595b1415457ab11139c69b350469139b/test/__init__.py
--------------------------------------------------------------------------------
/test/conftest.py:
--------------------------------------------------------------------------------
1 | from os.path import dirname, join
2 | from syncloudlib.integration.conftest import *
3 |
4 | DIR = dirname(__file__)
5 |
6 |
7 | @pytest.fixture(scope="session")
8 | def project_dir():
9 | return join(DIR, '..')
10 |
--------------------------------------------------------------------------------
/test/deps.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | apt-get update
4 | apt-get install -y sshpass openssh-client netcat rustc file libxml2-dev libxslt-dev build-essential libz-dev curl
5 | pip install -r requirements.txt
6 |
--------------------------------------------------------------------------------
/test/requirements.txt:
--------------------------------------------------------------------------------
1 | pytest==6.2.4
2 | selenium==4.21.0
3 | syncloud-lib==319
4 |
5 |
--------------------------------------------------------------------------------
/test/test.odt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/syncloud/nextcloud/bf69613b595b1415457ab11139c69b350469139b/test/test.odt
--------------------------------------------------------------------------------
/test/test.py:
--------------------------------------------------------------------------------
1 | import os
2 | import json
3 | import pytest
4 | import requests
5 | import shutil
6 | from os.path import join
7 | from requests.auth import HTTPBasicAuth
8 | from requests.packages.urllib3.exceptions import InsecureRequestWarning
9 | from subprocess import check_output
10 | from syncloudlib.integration.hosts import add_host_alias
11 | from syncloudlib.integration.installer import local_install, wait_for_installer
12 | from syncloudlib.integration.loop import loop_device_add, loop_device_cleanup
13 | from syncloudlib.http import wait_for_response
14 |
15 | TMP_DIR = '/tmp/syncloud'
16 |
17 | requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
18 |
19 |
20 | @pytest.fixture(scope="session")
21 | def module_setup(request, device, platform_data_dir, app_dir, artifact_dir):
22 | def module_teardown():
23 | platform_log_dir = join(artifact_dir, 'platform_log')
24 | os.mkdir(platform_log_dir)
25 | device.scp_from_device('{0}/log/*'.format(platform_data_dir), platform_log_dir)
26 | device.run_ssh('ls -la /var/snap/nextcloud/current/nextcloud/config > {0}/config.ls.log'.format(TMP_DIR), throw=False)
27 | device.run_ssh('cp /var/snap/nextcloud/current/nextcloud/config/config.php {0}'.format(TMP_DIR), throw=False)
28 | device.run_ssh('snap run nextcloud.occ > {1}/occ.help.log'.format(app_dir, TMP_DIR), throw=False)
29 | device.run_ssh('top -bn 1 -w 500 -c > {0}/top.log'.format(TMP_DIR), throw=False)
30 | device.run_ssh('ps auxfw > {0}/ps.log'.format(TMP_DIR), throw=False)
31 | device.run_ssh('systemctl status snap.nextcloud.php-fpm > {0}/nextcloud.php-fpm.status.log'.format(TMP_DIR),
32 | throw=False)
33 | device.run_ssh('netstat -nlp > {0}/netstat.log'.format(TMP_DIR), throw=False)
34 | device.run_ssh('journalctl | tail -1000 > {0}/journalctl.log'.format(TMP_DIR), throw=False)
35 | device.run_ssh('ls -la /snap > {0}/snap.ls.log'.format(TMP_DIR), throw=False)
36 | device.run_ssh('ls -la /snap/nextcloud > {0}/snap.nextcloud.ls.log'.format(TMP_DIR), throw=False)
37 | device.run_ssh('ls -la /var/snap > {0}/var.snap.ls.log'.format(TMP_DIR), throw=False)
38 | device.run_ssh('ls -la /var/snap/nextcloud > {0}/var.snap.nextcloud.ls.log'.format(TMP_DIR), throw=False)
39 | device.run_ssh('ls -la /var/snap/nextcloud/current/ > {0}/var.snap.nextcloud.current.ls.log'.format(TMP_DIR), throw=False)
40 | device.run_ssh('ls -la /var/snap/nextcloud/current/nextcloud > {0}/var.snap.nextcloud.current.nextcloud.ls.log'.format(TMP_DIR), throw=False)
41 | device.run_ssh('ls -la /snap/nextcloud/current/nextcloud > {0}/snap.nextcloud.current.nextcloud.ls.log'.format(TMP_DIR), throw=False)
42 | device.run_ssh('ls -la /var/snap/nextcloud/common > {0}/var.snap.nextcloud.common.ls.log'.format(TMP_DIR),
43 | throw=False)
44 | device.run_ssh('ls -la /data > {0}/data.ls.log'.format(TMP_DIR), throw=False)
45 | device.run_ssh('ls -la /data/nextcloud > {0}/data.nextcloud.ls.log'.format(TMP_DIR), throw=False)
46 |
47 | app_log_dir = join(artifact_dir, 'log')
48 | os.mkdir(app_log_dir)
49 | device.scp_from_device('/var/snap/nextcloud/common/log/*.log', app_log_dir)
50 | device.scp_from_device('{0}/*'.format(TMP_DIR), app_log_dir)
51 | shutil.copy2('/etc/hosts', app_log_dir)
52 | check_output('chmod -R a+r {0}'.format(artifact_dir), shell=True)
53 |
54 | request.addfinalizer(module_teardown)
55 |
56 |
57 | def test_start(module_setup, device, device_host, app, domain):
58 | add_host_alias(app, device_host, domain)
59 | device.run_ssh('date', retries=100)
60 | device.run_ssh('mkdir {0}'.format(TMP_DIR))
61 |
62 |
63 | def test_activate_device(device):
64 | response = device.activate_custom()
65 | assert response.status_code == 200, response.text
66 |
67 |
68 | def test_install(app_archive_path, device_session, device_host, device_password):
69 | local_install(device_host, device_password, app_archive_path)
70 |
71 |
72 | # noinspection PyUnresolvedReferences
73 | @pytest.mark.parametrize("megabytes", [1, 50])
74 | def test_sync(app_domain, megabytes, device, device_user, device_password):
75 | sync_file = 'test.file-{0}'.format(megabytes)
76 | if os.path.isfile(sync_file):
77 | os.remove(sync_file)
78 | print(check_output('dd if=/dev/zero of={0} count={1} bs=1M'.format(sync_file, megabytes), shell=True))
79 | webdav_upload(device_user, device_password, sync_file, sync_file, app_domain)
80 |
81 | sync_file_download = 'test.file.download'
82 | if os.path.isfile(sync_file_download):
83 | os.remove(sync_file_download)
84 | webdav_download(device_user, device_password, sync_file, sync_file_download, app_domain)
85 |
86 | assert os.path.isfile(sync_file_download)
87 | device.run_ssh('rm /data/nextcloud/{0}/files/{1}'.format(device_user, sync_file))
88 | files_scan(device)
89 |
90 |
91 | def webdav_upload(user, password, file_from, file_to, app_domain):
92 | print(check_output('curl -k -T {2} https://{0}:{1}@{4}/remote.php/webdav/{3}'.format(user, password, file_from, file_to,
93 | app_domain), shell=True))
94 |
95 |
96 | def webdav_download(user, password, file_from, file_to, app_domain):
97 | print(check_output('curl -k -o {3} https://{0}:{1}@{4}/remote.php/webdav/{2}'.format(user, password, file_from, file_to,
98 | app_domain), shell=True))
99 |
100 |
101 | def files_scan(device):
102 | device.run_ssh('snap run nextcloud.occ files:scan --all')
103 |
104 |
105 | def test_occ(device):
106 | device.run_ssh('snap run nextcloud.occ')
107 |
108 |
109 | def test_psql_oc_ldap_group_mapping(device):
110 | device.run_ssh("snap run nextcloud.psql -c 'select * from oc_ldap_group_mapping' > {0}/psql.oc_ldap_group_mapping.log".format(TMP_DIR))
111 |
112 |
113 | def test_cron(device):
114 | device.run_ssh('snap run nextcloud.cron')
115 |
116 |
117 | def test_visible_through_platform(app_domain):
118 | response = requests.get('https://{0}'.format(app_domain), verify=False)
119 | assert response.status_code == 200, response.text
120 |
121 |
122 | def test_occ_users(device):
123 | device.run_ssh('snap run nextcloud.occ user:list')
124 |
125 |
126 | def test_occ_check(device):
127 | device.run_ssh('snap run nextcloud.occ check')
128 |
129 |
130 | def test_occ_status(device):
131 | device.run_ssh('snap run nextcloud.occ status')
132 |
133 |
134 | def test_webdav(app_domain, artifact_dir, device_user, device_password):
135 | response = requests.request('PROPFIND', 'https://{0}:{1}@{2}/remote.php/webdav/'.format(
136 | device_user, device_password, app_domain), verify=False)
137 | with open(join(artifact_dir, 'webdav.list.log'), 'w') as f:
138 | f.write(str(response.text).replace(',', '\n'))
139 |
140 |
141 | def test_carddav(app_domain, artifact_dir, device_user, device_password):
142 | response = requests.request(
143 | 'PROPFIND',
144 | 'https://{0}/.well-known/carddav'.format(app_domain),
145 | allow_redirects=True,
146 | verify=False,
147 | auth=HTTPBasicAuth(device_user, device_password))
148 | with open(join(artifact_dir, 'well-known.carddav.headers.log'), 'w') as f:
149 | f.write(str(response.headers).replace(',', '\n'))
150 |
151 |
152 | def test_caldav(app_domain, artifact_dir, device_user, device_password):
153 | response = requests.request(
154 | 'PROPFIND',
155 | 'https://{0}/.well-known/caldav'.format(app_domain),
156 | allow_redirects=True,
157 | verify=False,
158 | auth=HTTPBasicAuth(device_user, device_password))
159 | with open(join(artifact_dir, 'well-known.caldav.headers.log'), 'w') as f:
160 | f.write(str(response.headers).replace(',', '\n'))
161 |
162 |
163 | def test_relative_redirect(app_domain, artifact_dir, device_user, device_password):
164 | response = requests.get(
165 | 'https://{0}/apps/files'.format(app_domain),
166 | allow_redirects=False,
167 | verify=False)
168 | assert response.headers['Location'] == '/apps/files/'
169 |
170 |
171 | def test_disk(app_domain, device, domain, device_user, device_password, artifact_dir):
172 | loop_device_cleanup(domain, '/tmp/test0', device_password)
173 | loop_device_cleanup(domain, '/tmp/test1', device_password)
174 |
175 | __create_test_dir('test00', app_domain, device_user, device_password, artifact_dir)
176 | files_scan(device)
177 | __check_test_dir(device_user, device_password, 'test00', app_domain, artifact_dir)
178 |
179 | device0 = loop_device_add(domain, 'ext4', '/tmp/test0', device_password)
180 | __activate_disk(device0, device, domain)
181 | __create_test_dir('test0', app_domain, device_user, device_password, artifact_dir)
182 | __check_test_dir(device_user, device_password, 'test0', app_domain, artifact_dir)
183 |
184 | device1 = loop_device_add(domain, 'ext2', '/tmp/test1', device_password)
185 | __activate_disk(device1, device, domain)
186 | __create_test_dir('test1', app_domain, device_user, device_password, artifact_dir)
187 | __check_test_dir(device_user, device_password, 'test1', app_domain, artifact_dir)
188 |
189 | __activate_disk(device0, device, domain)
190 | __check_test_dir(device_user, device_password, 'test0', app_domain, artifact_dir)
191 |
192 | __deactivate_disk(device, domain)
193 |
194 |
195 | def __log_data_dir(device):
196 | device.run_ssh('ls -la /data')
197 | device.run_ssh('mount')
198 | device.run_ssh('ls -la /data/')
199 | device.run_ssh('ls -la /data/nextcloud')
200 |
201 |
202 | def __activate_disk(loop_device, device, domain):
203 | __log_data_dir(device)
204 | session = device.login()
205 | response = session.post('https://{0}/rest/storage/activate/disk'.format(domain),
206 | json={'devices': [loop_device]}, allow_redirects=False, verify=False)
207 | assert response.status_code == 200, response.text
208 |
209 | wait_for_response(session, 'https://{0}/rest/job/status'.format(domain),
210 | lambda r: json.loads(r.text)['data']['status'] == 'Idle',
211 | attempts=100)
212 |
213 | __log_data_dir(device)
214 | files_scan(device)
215 | device.run_ssh('snap run nextcloud.occ > {0}/occ.activate.log'.format(TMP_DIR))
216 |
217 |
218 | def __deactivate_disk(device, domain):
219 | response = device.login().post('https://{0}/rest/storage/deactivate'.format(domain),
220 | allow_redirects=False, verify=False)
221 | files_scan(device)
222 | assert response.status_code == 200, response.text
223 |
224 |
225 | def __create_test_dir(test_dir, app_domain, device_user, device_password, artifact_dir):
226 | response = requests.request('MKCOL', 'https://{0}:{1}@{2}/remote.php/webdav/{3}'.format(
227 | device_user, device_password, app_domain, test_dir), verify=False)
228 | with open(join(artifact_dir, 'create.{0}.dir.log'.format(test_dir)), 'w') as f:
229 | f.write(response.text)
230 | assert response.status_code == 201, response.text
231 |
232 |
233 | def __check_test_dir(device_user, device_password, test_dir, app_domain, artifact_dir):
234 | response = requests.request('PROPFIND', 'https://{0}:{1}@{2}/remote.php/webdav/'.format(
235 | device_user, device_password, app_domain), verify=False)
236 | with open(join(artifact_dir, 'check.{0}.dir.log'.format(test_dir)), 'w') as f:
237 | f.write(response.text)
238 | #dirs = map(lambda v: v['name'], info['data']['files'])
239 | assert test_dir in response.text, response.text
240 |
241 |
242 | def test_phpinfo(device):
243 | device.run_ssh('snap run nextcloud.php -i > {0}/phpinfo.log'.format(TMP_DIR))
244 |
245 |
246 | def test_php_dns(device):
247 | ip = device.run_ssh('snap run nextcloud.php -r \\\"echo gethostbyname(\'apps.nextcloud.com\');\\\"')
248 | assert ip != "apps.nextcloud.com"
249 |
250 |
251 | def test_storage_change_event(device):
252 | device.run_ssh('snap run nextcloud.storage-change > {0}/storage-change.log'.format(TMP_DIR))
253 |
254 |
255 | def test_access_change_event(device):
256 | device.run_ssh('snap run nextcloud.access-change > {0}/access-change.log'.format(TMP_DIR))
257 |
258 |
259 | def test_remove(device, app):
260 | response = device.app_remove(app)
261 | assert response.status_code == 200, response.text
262 |
263 |
264 | def test_reinstall(app_archive_path, device_host, device_password):
265 | local_install(device_host, device_password, app_archive_path)
266 |
267 |
268 | def test_upgrade(app_archive_path, device_host, device_password):
269 | local_install(device_host, device_password, app_archive_path)
270 |
271 |
272 | def test_upgrade_from_store(device, app, app_archive_path, device_host, device_password):
273 | response = device.app_remove(app)
274 | assert response.status_code == 200, response.text
275 | response = device.app_install(app)
276 | assert response.status_code == 200, response.text
277 | local_install(device_host, device_password, app_archive_path)
278 |
279 |
280 | def test_install_calendar(device):
281 | device.run_ssh('snap run nextcloud.occ app:install calendar', retries=10, sleep=10)
282 |
283 |
284 | def test_install_contacts(device):
285 | device.run_ssh('snap run nextcloud.occ app:install contacts', retries=10, sleep=10)
286 |
287 |
288 | def test_install_office(device, arch):
289 | device.run_ssh('snap run nextcloud.occ app:install richdocuments', retries=10, sleep=10)
290 |
291 |
292 | def test_setupchecks(device, artifact_dir):
293 | output = device.run_ssh('snap run nextcloud.occ setupchecks --output=json_pretty', throw=False)
294 | with open(join(artifact_dir, 'setupchecks.log'), 'w') as f:
295 | f.write(output)
296 | invalid = []
297 | jout = json.loads(output)
298 | for key in jout.keys():
299 | for name in jout[key].keys():
300 | if jout[key][name]['severity'] == 'error':
301 | print(jout[key][name])
302 | invalid.append(jout[key][name])
303 |
304 | assert len(invalid) == 0
305 |
306 |
307 | def test_upload_office_file(device, arch, device_user, device_password, app_domain):
308 | if arch == "arm":
309 | webdav_upload(device_user, device_password, 'test.odt', 'test.odt', app_domain)
310 | files_scan(device)
311 |
--------------------------------------------------------------------------------
/test/ui.py:
--------------------------------------------------------------------------------
1 | from os.path import dirname, join
2 | from subprocess import check_output
3 |
4 | import pytest
5 | from selenium.webdriver.common.by import By
6 | from selenium.webdriver.common.keys import Keys
7 | from selenium.webdriver.support import expected_conditions as EC
8 | from syncloudlib.integration.hosts import add_host_alias
9 |
10 | DIR = dirname(__file__)
11 | TMP_DIR = '/tmp/syncloud/ui'
12 |
13 |
14 | @pytest.fixture(scope="session")
15 | def module_setup(request, device, artifact_dir, ui_mode, selenium):
16 | def module_teardown():
17 | device.activated()
18 | device.run_ssh('mkdir -p {0}'.format(TMP_DIR), throw=False)
19 | device.run_ssh('journalctl > {0}/journalctl.ui.{1}.log'.format(TMP_DIR, ui_mode), throw=False)
20 | device.scp_from_device('{0}/*'.format(TMP_DIR), join(artifact_dir, 'log'))
21 | check_output('cp /videos/* {0}'.format(artifact_dir), shell=True)
22 | check_output('chmod -R a+r {0}'.format(artifact_dir), shell=True)
23 | selenium.log()
24 | request.addfinalizer(module_teardown)
25 |
26 |
27 | def test_start(module_setup, app, domain, device_host):
28 | add_host_alias(app, device_host, domain)
29 |
30 |
31 | def test_login(selenium, device_user, device_password):
32 | selenium.open_app()
33 | selenium.find_by_id("user").send_keys(device_user)
34 | password = selenium.find_by_id("password")
35 | password.send_keys(device_password)
36 | selenium.screenshot('login')
37 | password.send_keys(Keys.RETURN)
38 | #selenium.find_by_xpath("//span[contains(.,'Continue with this unsupported browser')]").click()
39 | wizard_close_button = selenium.find_by_xpath('//div[contains(@class, "first-run-wizard")]//div[@class="modal-container__content"]//button[@aria-label="Close"]')
40 | #wizard_close_button = selenium.find_by_xpath('//button[contains(@class, "close-button")]')
41 | selenium.screenshot('main_first_time')
42 | # hover = ActionChains(selenium.driver).move_to_element(wizard_close_button)
43 | # hover.perform()
44 | # selenium.screenshot('main_first_time-hover')
45 | # selenium.wait_driver.until(EC.element_to_be_clickable((By.CSS_SELECTOR, close_css_selector)))
46 | # selenium.screenshot('main_first_time-click')
47 | wizard_close_button.click()
48 |
49 | selenium.screenshot('main')
50 |
51 |
52 | def test_settings(selenium, app_domain):
53 | selenium.driver.get("https://{0}/settings/admin".format(app_domain))
54 | selenium.find_by_xpath("//h2[contains(.,'Background jobs')]")
55 | selenium.screenshot('admin')
56 |
57 |
58 | def test_settings_user(selenium, app_domain):
59 | selenium.driver.get("https://{0}/settings/user".format(app_domain))
60 | selenium.find_by_xpath("//label[contains(.,'Profile picture')]")
61 | selenium.screenshot('user')
62 |
63 |
64 | def test_settings_ldap(selenium, app_domain):
65 | selenium.driver.get("https://{0}/settings/admin/ldap".format(app_domain))
66 | selenium.find_by_xpath("//h2[text()='LDAP/AD integration']")
67 | selenium.screenshot('admin-ldap')
68 |
69 |
70 | def test_settings_security(selenium, app_domain):
71 | selenium.driver.get("https://{0}/settings/admin/overview#security-warning".format(app_domain))
72 | selenium.find_by_xpath("//h2[text()='Security & setup warnings']")
73 | progress_xpath = "//span[text()='Checking for system and security issues.']"
74 | selenium.find_by_xpath(progress_xpath)
75 | selenium.wait_or_screenshot(EC.invisibility_of_element_located((By.XPATH, progress_xpath)))
76 | source = selenium.driver.page_source
77 | selenium.screenshot('admin-security')
78 | assert 'no SVG support' not in source
79 |
80 |
81 | # def test_settings_additional(selenium, app_domain):
82 | # selenium.driver.get("https://{0}/settings/admin/additional".format(app_domain))
83 | # selenium.find_by_xpath("//h2[text()='Maps routing settings']")
84 | # selenium.screenshot('admin-additional')
85 |
86 |
87 | # def test_apps_calendar(selenium, app_domain):
88 | # selenium.driver.get("https://{0}/calendar".format(app_domain))
89 | # selenium.find_by_xpath("//span[@text()='+ New calendar']")
90 | # selenium.screenshot('calendar')
91 |
92 |
93 | def test_verification(selenium, app_domain):
94 | selenium.driver.get('https://{0}/settings/integrity/failed'.format(app_domain))
95 | selenium.find_by_xpath("//pre[text()='No errors have been found.']")
96 | selenium.screenshot('integrity-failed')
97 | source = selenium.driver.page_source
98 | assert 'INVALID_HASH' not in source
99 | assert 'EXCEPTION' not in source
100 |
101 |
102 | def test_users(selenium, app_domain, ui_mode):
103 | selenium.driver.get('https://{0}/settings/users'.format(app_domain))
104 | if ui_mode == "desktop":
105 | selenium.find_by_xpath("//a[@title='Admins']")
106 | selenium.screenshot('users')
107 | source = selenium.driver.page_source
108 | assert 'Server Error' not in source
109 |
110 | def test_office(selenium, app_domain):
111 | selenium.driver.get('https://{0}/settings/admin/richdocuments'.format(app_domain))
112 | selenium.find_by_xpath("//label[normalize-space(text())='Use your own server']").click()
113 | selenium.screenshot('office-own')
114 | url = selenium.find_by_xpath("//input[@id='wopi_url']")
115 | url.clear()
116 | url.send_keys("https://{0}".format(app_domain))
117 | selenium.find_by_xpath("//*[normalize-space(text())='Disable certificate verification (insecure)']").click()
118 | selenium.screenshot('office-own-url')
119 | selenium.find_by_xpath("//input[@value='Save']").click()
120 | #selenium.find_by_xpath("//span[normalize-space(text())='Collabora Online server is reachable.']")
121 | selenium.screenshot('office-status')
122 |
123 |
124 | def test_app_install(selenium, app_domain):
125 | selenium.driver.get('https://{0}/settings/apps/discover/memories'.format(app_domain))
126 | selenium.find_by(By.XPATH, "//input[@value='Download and enable']").click()
127 | assert not selenium.exists_by(By.XPATH, "//div[contains(.,'Error')]")
128 | selenium.screenshot('install-app')
129 |
--------------------------------------------------------------------------------
/test/upgrade.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from subprocess import check_output, run
3 | from syncloudlib.integration.hosts import add_host_alias
4 | from syncloudlib.integration.installer import local_install
5 | from syncloudlib.http import wait_for_rest
6 | import requests
7 |
8 | TMP_DIR = '/tmp/syncloud'
9 |
10 |
11 | @pytest.fixture(scope="session")
12 | def module_setup(request, device, artifact_dir):
13 | def module_teardown():
14 | device.run_ssh('journalctl > {0}/refresh.journalctl.log'.format(TMP_DIR), throw=False)
15 | device.scp_from_device('{0}/*'.format(TMP_DIR), artifact_dir)
16 | run('cp /videos/* {0}'.format(artifact_dir), shell=True)
17 | check_output('chmod -R a+r {0}'.format(artifact_dir), shell=True)
18 |
19 | request.addfinalizer(module_teardown)
20 |
21 |
22 | def test_start(module_setup, app, device_host, domain, device):
23 | add_host_alias(app, device_host, domain)
24 | device.activated()
25 | device.run_ssh('rm -rf {0}'.format(TMP_DIR), throw=False)
26 | device.run_ssh('mkdir {0}'.format(TMP_DIR), throw=False)
27 |
28 |
29 | def test_upgrade(device, device_user, device_password, device_host, app_archive_path, app_domain, app_dir):
30 | device.run_ssh('snap remove nextcloud')
31 | device.run_ssh('snap install nextcloud', retries=10)
32 | local_install(device_host, device_password, app_archive_path)
33 | wait_for_rest(requests.session(), "https://{0}".format(app_domain), 200, 10)
34 |
35 |
--------------------------------------------------------------------------------