Compare commits
10 commits
84e41704fd
...
fb64fb1eea
Author | SHA1 | Date | |
---|---|---|---|
Yureka | fb64fb1eea | ||
Yureka | 3350646db9 | ||
Yureka | 066248d032 | ||
7cfb401000 | |||
ebab970fd8 | |||
939cfbf5e6 | |||
40846d3b16 | |||
ca91cdb33b | |||
b9f8a02e3b | |||
5b0e841351 |
274
LICENSE
Normal file
274
LICENSE
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
European Union Public Licence
|
||||||
|
V. 1.2
|
||||||
|
|
||||||
|
EUPL © the European Union 2007, 2016
|
||||||
|
|
||||||
|
This European Union Public Licence (the ‘EUPL’) applies to the Work (as
|
||||||
|
defined below) which is provided under the terms of this Licence. Any use of
|
||||||
|
the Work, other than as authorised under this Licence is prohibited (to the
|
||||||
|
extent such use is covered by a right of the copyright holder of the Work).
|
||||||
|
|
||||||
|
The Work is provided under the terms of this Licence when the Licensor (as
|
||||||
|
defined below) has placed the following notice immediately following the
|
||||||
|
copyright notice for the Work: “Licensed under the EUPL”, or has expressed by
|
||||||
|
any other means his willingness to license under the EUPL.
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
In this Licence, the following terms have the following meaning:
|
||||||
|
— ‘The Licence’: this Licence.
|
||||||
|
— ‘The Original Work’: the work or software distributed or communicated by the
|
||||||
|
‘Licensor under this Licence, available as Source Code and also as
|
||||||
|
‘Executable Code as the case may be.
|
||||||
|
— ‘Derivative Works’: the works or software that could be created by the
|
||||||
|
‘Licensee, based upon the Original Work or modifications thereof. This
|
||||||
|
‘Licence does not define the extent of modification or dependence on the
|
||||||
|
‘Original Work required in order to classify a work as a Derivative Work;
|
||||||
|
‘this extent is determined by copyright law applicable in the country
|
||||||
|
‘mentioned in Article 15.
|
||||||
|
— ‘The Work’: the Original Work or its Derivative Works.
|
||||||
|
— ‘The Source Code’: the human-readable form of the Work which is the most
|
||||||
|
convenient for people to study and modify.
|
||||||
|
|
||||||
|
— ‘The Executable Code’: any code which has generally been compiled and which
|
||||||
|
is meant to be interpreted by a computer as a program.
|
||||||
|
— ‘The Licensor’: the natural or legal person that distributes or communicates
|
||||||
|
the Work under the Licence.
|
||||||
|
— ‘Contributor(s)’: any natural or legal person who modifies the Work under
|
||||||
|
the Licence, or otherwise contributes to the creation of a Derivative Work.
|
||||||
|
— ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
|
||||||
|
the Work under the terms of the Licence.
|
||||||
|
— ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
|
||||||
|
renting, distributing, communicating, transmitting, or otherwise making
|
||||||
|
available, online or offline, copies of the Work or providing access to its
|
||||||
|
essential functionalities at the disposal of any other natural or legal
|
||||||
|
person.
|
||||||
|
|
||||||
|
2. Scope of the rights granted by the Licence
|
||||||
|
|
||||||
|
The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
|
||||||
|
sublicensable licence to do the following, for the duration of copyright
|
||||||
|
vested in the Original Work:
|
||||||
|
|
||||||
|
— use the Work in any circumstance and for all usage,
|
||||||
|
— reproduce the Work,
|
||||||
|
— modify the Work, and make Derivative Works based upon the Work,
|
||||||
|
— communicate to the public, including the right to make available or display
|
||||||
|
the Work or copies thereof to the public and perform publicly, as the case
|
||||||
|
may be, the Work,
|
||||||
|
— distribute the Work or copies thereof,
|
||||||
|
— lend and rent the Work or copies thereof,
|
||||||
|
— sublicense rights in the Work or copies thereof.
|
||||||
|
|
||||||
|
Those rights can be exercised on any media, supports and formats, whether now
|
||||||
|
known or later invented, as far as the applicable law permits so.
|
||||||
|
|
||||||
|
In the countries where moral rights apply, the Licensor waives his right to
|
||||||
|
exercise his moral right to the extent allowed by law in order to make
|
||||||
|
effective the licence of the economic rights here above listed.
|
||||||
|
|
||||||
|
The Licensor grants to the Licensee royalty-free, non-exclusive usage rights
|
||||||
|
to any patents held by the Licensor, to the extent necessary to make use of
|
||||||
|
the rights granted on the Work under this Licence.
|
||||||
|
|
||||||
|
3. Communication of the Source Code
|
||||||
|
|
||||||
|
The Licensor may provide the Work either in its Source Code form, or as
|
||||||
|
Executable Code. If the Work is provided as Executable Code, the Licensor
|
||||||
|
provides in addition a machine-readable copy of the Source Code of the Work
|
||||||
|
along with each copy of the Work that the Licensor distributes or indicates,
|
||||||
|
in a notice following the copyright notice attached to the Work, a repository
|
||||||
|
where the Source Code is easily and freely accessible for as long as the
|
||||||
|
Licensor continues to distribute or communicate the Work.
|
||||||
|
|
||||||
|
4. Limitations on copyright
|
||||||
|
|
||||||
|
Nothing in this Licence is intended to deprive the Licensee of the benefits
|
||||||
|
from any exception or limitation to the exclusive rights of the rights owners
|
||||||
|
in the Work, of the exhaustion of those rights or of other applicable
|
||||||
|
limitations thereto.
|
||||||
|
|
||||||
|
5. Obligations of the Licensee
|
||||||
|
|
||||||
|
The grant of the rights mentioned above is subject to some restrictions and
|
||||||
|
obligations imposed on the Licensee. Those obligations are the following:
|
||||||
|
|
||||||
|
Attribution right: The Licensee shall keep intact all copyright, patent or
|
||||||
|
trademarks notices and all notices that refer to the Licence and to the
|
||||||
|
disclaimer of warranties. The Licensee must include a copy of such notices and
|
||||||
|
a copy of the Licence with every copy of the Work he/she distributes or
|
||||||
|
communicates. The Licensee must cause any Derivative Work to carry prominent
|
||||||
|
notices stating that the Work has been modified and the date of modification.
|
||||||
|
|
||||||
|
Copyleft clause: If the Licensee distributes or communicates copies of the
|
||||||
|
Original Works or Derivative Works, this Distribution or Communication will be
|
||||||
|
done under the terms of this Licence or of a later version of this Licence
|
||||||
|
unless the Original Work is expressly distributed only under this version of
|
||||||
|
the Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
|
||||||
|
(becoming Licensor) cannot offer or impose any additional terms or conditions
|
||||||
|
on the Work or Derivative Work that alter or restrict the terms of the
|
||||||
|
Licence.
|
||||||
|
|
||||||
|
Compatibility clause: If the Licensee Distributes or Communicates Derivative
|
||||||
|
Works or copies thereof based upon both the Work and another work licensed
|
||||||
|
under a Compatible Licence, this Distribution or Communication can be done
|
||||||
|
under the terms of this Compatible Licence. For the sake of this clause,
|
||||||
|
‘Compatible Licence’ refers to the licences listed in the appendix attached to
|
||||||
|
this Licence. Should the Licensee's obligations under the Compatible Licence
|
||||||
|
conflict with his/her obligations under this Licence, the obligations of the
|
||||||
|
Compatible Licence shall prevail.
|
||||||
|
|
||||||
|
Provision of Source Code: When distributing or communicating copies of the
|
||||||
|
Work, the Licensee will provide a machine-readable copy of the Source Code or
|
||||||
|
indicate a repository where this Source will be easily and freely available
|
||||||
|
for as long as the Licensee continues to distribute or communicate the Work.
|
||||||
|
|
||||||
|
Legal Protection: This Licence does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or names of the Licensor, except as required
|
||||||
|
for reasonable and customary use in describing the origin of the Work and
|
||||||
|
reproducing the content of the copyright notice.
|
||||||
|
|
||||||
|
6. Chain of Authorship
|
||||||
|
|
||||||
|
The original Licensor warrants that the copyright in the Original Work granted
|
||||||
|
hereunder is owned by him/her or licensed to him/her and that he/she has the
|
||||||
|
power and authority to grant the Licence.
|
||||||
|
|
||||||
|
Each Contributor warrants that the copyright in the modifications he/she
|
||||||
|
brings to the Work are owned by him/her or licensed to him/her and that he/she
|
||||||
|
has the power and authority to grant the Licence.
|
||||||
|
|
||||||
|
Each time You accept the Licence, the original Licensor and subsequent
|
||||||
|
Contributors grant You a licence to their contributions to the Work, under the
|
||||||
|
terms of this Licence.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty
|
||||||
|
|
||||||
|
The Work is a work in progress, which is continuously improved by numerous
|
||||||
|
Contributors. It is not a finished work and may therefore contain defects or
|
||||||
|
‘bugs’ inherent to this type of development.
|
||||||
|
|
||||||
|
For the above reason, the Work is provided under the Licence on an ‘as is’
|
||||||
|
basis and without warranties of any kind concerning the Work, including
|
||||||
|
without limitation merchantability, fitness for a particular purpose, absence
|
||||||
|
of defects or errors, accuracy, non-infringement of intellectual property
|
||||||
|
rights other than copyright as stated in Article 6 of this Licence.
|
||||||
|
|
||||||
|
This disclaimer of warranty is an essential part of the Licence and a
|
||||||
|
condition for the grant of any rights to the Work.
|
||||||
|
|
||||||
|
8. Disclaimer of Liability
|
||||||
|
|
||||||
|
Except in the cases of wilful misconduct or damages directly caused to natural
|
||||||
|
persons, the Licensor will in no event be liable for any direct or indirect,
|
||||||
|
material or moral, damages of any kind, arising out of the Licence or of the
|
||||||
|
use of the Work, including without limitation, damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, loss of data or any commercial
|
||||||
|
damage, even if the Licensor has been advised of the possibility of such
|
||||||
|
damage. However, the Licensor will be liable under statutory product liability
|
||||||
|
laws as far such laws apply to the Work.
|
||||||
|
|
||||||
|
9. Additional agreements
|
||||||
|
|
||||||
|
While distributing the Work, You may choose to conclude an additional
|
||||||
|
agreement, defining obligations or services consistent with this Licence.
|
||||||
|
However, if accepting obligations, You may act only on your own behalf and on
|
||||||
|
your sole responsibility, not on behalf of the original Licensor or any other
|
||||||
|
Contributor, and only if You agree to indemnify, defend, and hold each
|
||||||
|
Contributor harmless for any liability incurred by, or claims asserted against
|
||||||
|
such Contributor by the fact You have accepted any warranty or additional
|
||||||
|
liability.
|
||||||
|
|
||||||
|
10. Acceptance of the Licence
|
||||||
|
|
||||||
|
The provisions of this Licence can be accepted by clicking on an icon ‘I
|
||||||
|
agree’ placed under the bottom of a window displaying the text of this Licence
|
||||||
|
or by affirming consent in any other similar way, in accordance with the rules
|
||||||
|
of applicable law. Clicking on that icon indicates your clear and irrevocable
|
||||||
|
acceptance of this Licence and all of its terms and conditions.
|
||||||
|
|
||||||
|
Similarly, you irrevocably accept this Licence and all of its terms and
|
||||||
|
conditions by exercising any rights granted to You by Article 2 of this
|
||||||
|
Licence, such as the use of the Work, the creation by You of a Derivative Work
|
||||||
|
or the Distribution or Communication by You of the Work or copies thereof.
|
||||||
|
|
||||||
|
11. Information to the public
|
||||||
|
|
||||||
|
In case of any Distribution or Communication of the Work by means of
|
||||||
|
electronic communication by You (for example, by offering to download the Work
|
||||||
|
from a remote location) the distribution channel or media (for example, a
|
||||||
|
website) must at least provide to the public the information requested by the
|
||||||
|
applicable law regarding the Licensor, the Licence and the way it may be
|
||||||
|
accessible, concluded, stored and reproduced by the Licensee.
|
||||||
|
|
||||||
|
12. Termination of the Licence
|
||||||
|
|
||||||
|
The Licence and the rights granted hereunder will terminate automatically upon
|
||||||
|
any breach by the Licensee of the terms of the Licence. Such a termination
|
||||||
|
will not terminate the licences of any person who has received the Work from
|
||||||
|
the Licensee under the Licence, provided such persons remain in full
|
||||||
|
compliance with the Licence.
|
||||||
|
|
||||||
|
13. Miscellaneous
|
||||||
|
|
||||||
|
Without prejudice of Article 9 above, the Licence represents the complete
|
||||||
|
agreement between the Parties as to the Work.
|
||||||
|
|
||||||
|
If any provision of the Licence is invalid or unenforceable under applicable
|
||||||
|
law, this will not affect the validity or enforceability of the Licence as a
|
||||||
|
whole. Such provision will be construed or reformed so as necessary to make it
|
||||||
|
valid and enforceable.
|
||||||
|
|
||||||
|
The European Commission may publish other linguistic versions or new versions
|
||||||
|
of this Licence or updated versions of the Appendix, so far this is required
|
||||||
|
and reasonable, without reducing the scope of the rights granted by the
|
||||||
|
Licence. New versions of the Licence will be published with a unique version
|
||||||
|
number.
|
||||||
|
|
||||||
|
All linguistic versions of this Licence, approved by the European Commission,
|
||||||
|
have identical value. Parties can take advantage of the linguistic version of
|
||||||
|
their choice.
|
||||||
|
|
||||||
|
14. Jurisdiction
|
||||||
|
|
||||||
|
Without prejudice to specific agreement between parties,
|
||||||
|
— any litigation resulting from the interpretation of this License, arising
|
||||||
|
between the European Union institutions, bodies, offices or agencies, as a
|
||||||
|
Licensor, and any Licensee, will be subject to the jurisdiction of the Court
|
||||||
|
of Justice of the European Union, as laid down in article 272 of the Treaty
|
||||||
|
on the Functioning of the European Union,
|
||||||
|
— any litigation arising between other parties and resulting from the
|
||||||
|
interpretation of this License, will be subject to the exclusive
|
||||||
|
jurisdiction of the competent court where the Licensor resides or conducts
|
||||||
|
its primary business.
|
||||||
|
|
||||||
|
15. Applicable Law
|
||||||
|
|
||||||
|
Without prejudice to specific agreement between parties,
|
||||||
|
— this Licence shall be governed by the law of the European Union Member State
|
||||||
|
where the Licensor has his seat, resides or has his registered office,
|
||||||
|
— this licence shall be governed by Belgian law if the Licensor has no seat,
|
||||||
|
residence or registered office inside a European Union Member State.
|
||||||
|
|
||||||
|
Appendix
|
||||||
|
|
||||||
|
‘Compatible Licences’ according to Article 5 EUPL are:
|
||||||
|
— GNU General Public License (GPL) v. 2, v. 3
|
||||||
|
— GNU Affero General Public License (AGPL) v. 3
|
||||||
|
— Open Software License (OSL) v. 2.1, v. 3.0
|
||||||
|
— Eclipse Public License (EPL) v. 1.0
|
||||||
|
— CeCILL v. 2.0, v. 2.1
|
||||||
|
— Mozilla Public Licence (MPL) v. 2
|
||||||
|
— GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
|
||||||
|
— Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
|
||||||
|
works other than software
|
||||||
|
— European Union Public Licence (EUPL) v. 1.1, v. 1.2
|
||||||
|
— Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or
|
||||||
|
Strong Reciprocity (LiLiQ-R+)
|
||||||
|
|
||||||
|
— The European Commission may update this Appendix to later versions of the
|
||||||
|
above licences without producing a new version of the EUPL, as long as they
|
||||||
|
provide the rights granted in Article 2 of this Licence and protect the
|
||||||
|
covered Source Code from exclusive appropriation.
|
||||||
|
— All other changes or additions to this Appendix require the production of a
|
||||||
|
new EUPL version.
|
|
@ -6,6 +6,7 @@
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
cfg = config.services.tvix-binary-cache;
|
cfg = config.services.tvix-binary-cache;
|
||||||
|
settingsFormat = pkgs.formats.toml { };
|
||||||
systemdHardening = {
|
systemdHardening = {
|
||||||
PrivateDevices = true;
|
PrivateDevices = true;
|
||||||
PrivateTmp = true;
|
PrivateTmp = true;
|
||||||
|
@ -13,7 +14,7 @@ let
|
||||||
ProtectKernelTunables = true;
|
ProtectKernelTunables = true;
|
||||||
RestrictSUIDSGID = true;
|
RestrictSUIDSGID = true;
|
||||||
|
|
||||||
ProtectSystem = "strict";
|
#ProtectSystem = "strict";
|
||||||
ProtectKernelLogs = true;
|
ProtectKernelLogs = true;
|
||||||
ProtectProc = "invisible";
|
ProtectProc = "invisible";
|
||||||
PrivateUsers = true;
|
PrivateUsers = true;
|
||||||
|
@ -28,61 +29,78 @@ in
|
||||||
options = {
|
options = {
|
||||||
services.tvix-binary-cache = {
|
services.tvix-binary-cache = {
|
||||||
enable = lib.mkEnableOption "BinaryCache using tvix ca-store";
|
enable = lib.mkEnableOption "BinaryCache using tvix ca-store";
|
||||||
blob-service-addr = lib.mkOption {
|
castoreDir = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.nullOr lib.types.str;
|
||||||
default = "objectstore+file://%S/tvix-castore/blobs.object-store";
|
default = "/var/lib/castore";
|
||||||
description = ''
|
|
||||||
`blob-service-addr` option for the mutualized content addressed storage.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
directory-service-addr = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "sled://%S/tvix-castore/directories.sled";
|
|
||||||
description = ''
|
|
||||||
`directory-service-addr` option for the mutualized content addressed storage.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
caches = lib.mkOption {
|
caches = lib.mkOption {
|
||||||
type = lib.types.attrsOf (
|
type = lib.types.attrsOf (
|
||||||
lib.types.submodule (
|
lib.types.submodule (
|
||||||
{ name, ... }:
|
{ name, ... }@cacheAttrs:
|
||||||
{
|
{
|
||||||
options = {
|
config =
|
||||||
port = lib.mkOption {
|
let
|
||||||
type = lib.types.port;
|
common-composition = {
|
||||||
default = 9000;
|
blobservices.default = {
|
||||||
|
type = "objectstore";
|
||||||
|
object_store_url = "file://${cfg.castoreDir}/blobs.object-store";
|
||||||
|
object_store_options = { };
|
||||||
|
};
|
||||||
|
directoryservices = {
|
||||||
|
objectstore = {
|
||||||
|
type = "objectstore";
|
||||||
|
object_store_url = "file://${cfg.castoreDir}/directories.object-store";
|
||||||
|
object_store_options = { };
|
||||||
|
};
|
||||||
|
memory = {
|
||||||
|
type = "memory";
|
||||||
|
};
|
||||||
|
cache = {
|
||||||
|
type = "cache";
|
||||||
|
near = "memory";
|
||||||
|
far = "objectstore";
|
||||||
|
};
|
||||||
|
default = {
|
||||||
|
type = "router";
|
||||||
|
writes = "objectstore";
|
||||||
|
reads = "cache";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
nar-bridge-composition = lib.recursiveUpdate common-composition {
|
||||||
|
pathinfoservices.default = {
|
||||||
|
type = "grpc";
|
||||||
|
url = "grpc+http://${cacheAttrs.config.grpcListenAddress}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
tvix-daemon-composition = lib.recursiveUpdate common-composition {
|
||||||
|
pathinfoservices.default = {
|
||||||
|
type = "sled";
|
||||||
|
is_temporary = false;
|
||||||
|
path = "/var/lib/tvix-daemon-${name}/pathinfos.sled";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
options = {
|
||||||
|
grpcListenAddress = lib.mkOption { type = lib.types.str; };
|
||||||
|
narBridgeListenAddress = lib.mkOption { type = lib.types.str; };
|
||||||
|
nar-bridge-composition = lib.mkOption { inherit (settingsFormat) type; };
|
||||||
|
tvix-daemon-composition = lib.mkOption { inherit (settingsFormat) type; };
|
||||||
name = lib.mkOption {
|
name = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
description = "Name of the cache";
|
description = "Name of the cache";
|
||||||
default = name;
|
default = name;
|
||||||
defaultText = lib.literalMD "Defaults to attribute name in services.tvix-binary-cache.caches";
|
defaultText = lib.literalMD "Defaults to attribute name in services.tvix-binary-cache.caches";
|
||||||
};
|
};
|
||||||
path-info-service-addr = lib.mkOption {
|
|
||||||
type = with lib.types; str;
|
|
||||||
description = "Path info service path";
|
|
||||||
default = "sled://%S/%N/pathinfo.sled";
|
|
||||||
};
|
|
||||||
remote-path-info-service-addr = lib.mkOption {
|
remote-path-info-service-addr = lib.mkOption {
|
||||||
type = with lib.types; nullOr str;
|
type = with lib.types; nullOr str;
|
||||||
description = "Upstream cache to substitute from if nothing in ";
|
description = "Upstream cache to substitute from if nothing in ";
|
||||||
example = "nix+https://cache.nixos.org?trusted-public-keys=cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=";
|
example = "nix+https://cache.nixos.org?trusted-public-keys=cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=";
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
blob-service-addr = lib.mkOption {
|
|
||||||
type = with lib.types; nullOr str;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
Use a specific blob service and do not use the mutualized one.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
directory-service-addr = lib.mkOption {
|
|
||||||
type = with lib.types; nullOr str;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
Use a specific directory address and do not use the mutualized one.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -93,75 +111,48 @@ in
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
environment.systemPackages = [ pkgs.tvix-store ];
|
environment.systemPackages = [ pkgs.tvix ];
|
||||||
|
users.users.tvix-castore = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "tvix-castore";
|
||||||
|
};
|
||||||
|
users.groups.tvix-castore = { };
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [ "d ${cfg.castoreDir} 770 root tvix-castore -" ];
|
||||||
|
|
||||||
systemd.services = lib.mkMerge (
|
systemd.services = lib.mkMerge (
|
||||||
(lib.singleton {
|
(lib.singleton { })
|
||||||
tvix-castore = {
|
++ (lib.mapAttrsToList (name: cache: {
|
||||||
wants = [ "tvix-castore.service" ];
|
"tvix-daemon-${cache.name}" = {
|
||||||
after = [ "tvix-castore.service" ];
|
|
||||||
environment = {
|
environment = {
|
||||||
BLOB_SERVICE_ADDR = cfg.blob-service-addr;
|
EXPERIMENTAL_STORE_COMPOSITION = settingsFormat.generate "Config.toml" cache.tvix-daemon-composition;
|
||||||
DIRECTORY_SERVICE_ADDR = cfg.directory-service-addr;
|
|
||||||
PATH_INFO_SERVICE_ADDR = "sled://%S/tvix-castore/pathinfo.sled"; # Unused but probably needed
|
|
||||||
};
|
};
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${pkgs.tvix-store}/bin/tvix-store --otlp=false daemon --listen-address=\"%t/tvix-castore/socket\"";
|
UMask = "007";
|
||||||
DynamicUser = true;
|
#ExecStart = "${pkgs.tvix-store}/bin/tvix-store --otlp=false daemon --listen-address=\"%t/tvix-castore/socket\"";
|
||||||
User = "tvix-binary-cache";
|
ExecStart = "${pkgs.tvix}/bin/tvix-store --otlp=false daemon --listen-address=\"${cache.grpcListenAddress}\"";
|
||||||
StateDirectory = "tvix-castore";
|
StateDirectory = "tvix-daemon-${cache.name}";
|
||||||
RuntimeDirectory = "tvix-castore";
|
RuntimeDirectory = "tvix-daemon-${cache.name}";
|
||||||
|
User = "tvix-castore";
|
||||||
|
Group = "tvix-castore";
|
||||||
} // systemdHardening;
|
} // systemdHardening;
|
||||||
|
|
||||||
};
|
};
|
||||||
})
|
"narbridge-${cache.name}" = {
|
||||||
++ (lib.mapAttrsToList (
|
wantedBy = [ "multi-user.target" ];
|
||||||
name: cfg:
|
wants = [ "tvix-daemon-${cache.name}.service" ];
|
||||||
let
|
after = [ "tvix-daemon-${cache.name}.service" ];
|
||||||
unitName = "tvix-store-${cfg.name}";
|
environment = {
|
||||||
in
|
EXPERIMENTAL_STORE_COMPOSITION = settingsFormat.generate "Config.toml" cache.nar-bridge-composition;
|
||||||
{
|
|
||||||
"nar-bridge-${cfg.name}" = {
|
|
||||||
wants = [ "tvix-store-${cfg.name}.service" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
after = [ "tvix-store-${cfg.name}.service" ];
|
|
||||||
serviceConfig = rec {
|
|
||||||
ExecStart = "${lib.getExe pkgs.nar-bridge-go} --otlp=false --listen-addr=\"[::1]:${builtins.toString cfg.port}\" --store-addr=\"unix://%t/${unitName}/socket\"";
|
|
||||||
|
|
||||||
DynamicUser = true;
|
|
||||||
User = "tvix-binary-cache";
|
|
||||||
} // systemdHardening;
|
|
||||||
};
|
|
||||||
${unitName} = {
|
|
||||||
wants = [ "tvix-castore.service" ];
|
|
||||||
after = [ "tvix-castore.service" ];
|
|
||||||
environment = {
|
|
||||||
BLOB_SERVICE_ADDR =
|
|
||||||
if cfg.blob-service-addr != null then
|
|
||||||
cfg.blob-service-addr
|
|
||||||
else
|
|
||||||
"grpc+unix://%t/tvix-castore/socket";
|
|
||||||
DIRECTORY_SERVICE_ADDR =
|
|
||||||
if cfg.directory-service-addr != null then
|
|
||||||
cfg.directory-service-addr
|
|
||||||
else
|
|
||||||
"grpc+unix://%t/tvix-castore/socket";
|
|
||||||
PATH_INFO_SERVICE_ADDR = cfg.path-info-service-addr;
|
|
||||||
REMOTE_PATH_INFO_SERVICE_ADDR = lib.mkIf (
|
|
||||||
cfg.remote-path-info-service-addr != null
|
|
||||||
) cfg.remote-path-info-service-addr;
|
|
||||||
};
|
|
||||||
serviceConfig = {
|
|
||||||
ExecStart = "${pkgs.tvix-store}/bin/tvix-store --otlp=false daemon --listen-address=\"%t/${unitName}/socket\"";
|
|
||||||
DynamicUser = true;
|
|
||||||
User = "tvix-binary-cache";
|
|
||||||
StateDirectory = unitName;
|
|
||||||
RuntimeDirectory = unitName;
|
|
||||||
} // systemdHardening;
|
|
||||||
};
|
};
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = "${pkgs.tvix}/bin/nar-bridge --otlp=false --listen-address=\"${cache.narBridgeListenAddress}\"";
|
||||||
|
User = "tvix-castore";
|
||||||
|
Group = "tvix-castore";
|
||||||
|
RuntimeDirectory = "narbridge-${cache.name}";
|
||||||
|
} // systemdHardening;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}) cfg.caches)
|
||||||
) cfg.caches)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,12 +21,11 @@
|
||||||
enable = true;
|
enable = true;
|
||||||
recommendedProxySettings = true;
|
recommendedProxySettings = true;
|
||||||
virtualHosts.${config.services.tvix-binary-cache.nginx.host} = {
|
virtualHosts.${config.services.tvix-binary-cache.nginx.host} = {
|
||||||
default = true;
|
|
||||||
locations = lib.mkMerge (
|
locations = lib.mkMerge (
|
||||||
lib.mapAttrsToList (name: cfg: {
|
lib.mapAttrsToList (name: cfg: {
|
||||||
"/${name}".return = "302 /${name}/";
|
"/${name}".return = "302 /${name}/";
|
||||||
"/${name}/" = {
|
"/${name}/" = {
|
||||||
proxyPass = "http://localhost:${toString cfg.port}/";
|
proxyPass = "http://${toString cfg.narBridgeListenAddress}/";
|
||||||
};
|
};
|
||||||
}) config.services.tvix-binary-cache.caches
|
}) config.services.tvix-binary-cache.caches
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
{ buildGoModule, tvix-src }:
|
|
||||||
buildGoModule rec {
|
|
||||||
pname = "nar-bridge-go";
|
|
||||||
version = "0.1.0";
|
|
||||||
src = tvix-src;
|
|
||||||
sourceRoot = "${src.name}/tvix/nar-bridge-go";
|
|
||||||
vendorHash = "sha256-7jugbC5sEGhppjiZgnoLP5A6kQSaHK9vE6cXVZBG22s=";
|
|
||||||
meta.mainProgram = "nar-bridge-http";
|
|
||||||
}
|
|
|
@ -1,5 +1,8 @@
|
||||||
final: _: {
|
final: _: {
|
||||||
tvix-store = final.callPackage ./tvix { packages = [ "tvix-store" ]; };
|
tvix = final.callPackage ./tvix {
|
||||||
nar-bridge-go = final.callPackage ./nar-bridge-go { };
|
packages = [
|
||||||
tvix-src = final.callPackage ./tvix-src.nix { };
|
"nar-bridge"
|
||||||
|
"tvix-store"
|
||||||
|
];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
{ fetchgit }:
|
|
||||||
fetchgit {
|
|
||||||
name = "tvix";
|
|
||||||
url = "https://code.tvl.fyi/depot.git";
|
|
||||||
rev = "f0b0a6572ff7908c890963f6462af27dcef80bd7";
|
|
||||||
hash = "sha256-7l/UHq19oyF4743olRgAk0ikc92VUqKrxcfj17GAgt0=";
|
|
||||||
}
|
|
1263
pkgs/tvix/01-remote-path-info-nar-bridge.patch
Normal file
1263
pkgs/tvix/01-remote-path-info-nar-bridge.patch
Normal file
File diff suppressed because it is too large
Load diff
5296
pkgs/tvix/Cargo.lock
generated
5296
pkgs/tvix/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
tvix-src,
|
fetchgit,
|
||||||
rustPlatform,
|
rustPlatform,
|
||||||
protobuf,
|
protobuf,
|
||||||
packages ? [ ],
|
packages ? [ ],
|
||||||
|
@ -10,23 +10,33 @@ rustPlatform.buildRustPackage rec {
|
||||||
inherit pname;
|
inherit pname;
|
||||||
version = "0.1.0";
|
version = "0.1.0";
|
||||||
|
|
||||||
src = tvix-src;
|
src = fetchgit {
|
||||||
|
name = "tvix";
|
||||||
|
url = "https://cl.tvl.fyi/depot";
|
||||||
|
rev = "507a5c1b7376a2f9617b286f142ec8115cf19a6e";
|
||||||
|
hash = "sha256-QTAzM8b59NtQSjvlu5mcO13t4T58Mv00ax7/RnRENwk=";
|
||||||
|
};
|
||||||
|
|
||||||
sourceRoot = "${src.name}/tvix";
|
patches = [ ];
|
||||||
|
postPatch = "cd tvix";
|
||||||
|
|
||||||
doCheck = false;
|
doCheck = false;
|
||||||
|
|
||||||
cargoBuildFlags = builtins.concatStringsSep " " (builtins.map (v: "-p ${v}") packages);
|
cargoBuildFlags = builtins.concatStringsSep " " (
|
||||||
|
builtins.map (v: "-p ${v}") packages
|
||||||
|
++ [
|
||||||
|
"--features"
|
||||||
|
"tvix-store/xp-store-composition"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
nativeBuildInputs = [ protobuf ];
|
nativeBuildInputs = [ protobuf ];
|
||||||
|
|
||||||
PROTO_ROOT = "/build/${src.name}";
|
PROTO_ROOT = "/build/${src.name}";
|
||||||
|
|
||||||
cargoLock = {
|
cargoLock = {
|
||||||
lockFile = ./Cargo.lock;
|
lockFile = src + "/tvix/Cargo.lock";
|
||||||
outputHashes = {
|
allowBuiltinFetchGit = true;
|
||||||
"wu-manber-0.1.0" = "sha256-7YIttaQLfFC/32utojh2DyOHVsZiw8ul/z0lvOhAE/4=";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
meta = { };
|
meta = { };
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
pkgs ? import nixpkgs { overlays = [ (import ../pkgs/overlay.nix) ]; },
|
pkgs ? import nixpkgs { overlays = [ (import ../pkgs/overlay.nix) ]; },
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
# Disabled since nar-bridge doesn't expose gRPC
|
||||||
|
# ingest = pkgs.callPackage ./ingest.nix { };
|
||||||
multi-cache = pkgs.callPackage ./multi-cache.nix { };
|
multi-cache = pkgs.callPackage ./multi-cache.nix { };
|
||||||
ingest = pkgs.callPackage ./ingest.nix { };
|
|
||||||
substitution = pkgs.callPackage ./substitution.nix { };
|
substitution = pkgs.callPackage ./substitution.nix { };
|
||||||
|
upstream-cache-tvix = pkgs.callPackage ./upstream-cache-tvix.nix { };
|
||||||
|
upstream-cache-http-directory = pkgs.callPackage ./upstream-cache-http-directory.nix { };
|
||||||
|
upstream-cache-nix-serve = pkgs.callPackage ./upstream-cache-nix-serve.nix { };
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ pkgs.testers.runNixOSTest (_: {
|
||||||
import time
|
import time
|
||||||
start_all()
|
start_all()
|
||||||
cache.wait_for_unit("nginx.service")
|
cache.wait_for_unit("nginx.service")
|
||||||
cache.wait_for_unit("nar-bridge-cache.service")
|
cache.wait_for_unit("tvix-store-cache.service")
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
socket_addr = "grpc+unix:///run/tvix-store-cache/socket"
|
socket_addr = "grpc+unix:///run/tvix-store-cache/socket"
|
||||||
cache.succeed(f"BLOB_SERVICE_ADDR={socket_addr} DIRECTORY_SERVICE_ADDR={socket_addr} PATH_INFO_SERVICE_ADDR={socket_addr} tvix-store copy ${builtins.toString references}")
|
cache.succeed(f"BLOB_SERVICE_ADDR={socket_addr} DIRECTORY_SERVICE_ADDR={socket_addr} PATH_INFO_SERVICE_ADDR={socket_addr} tvix-store copy ${builtins.toString references}")
|
||||||
|
|
|
@ -35,23 +35,19 @@ pkgs.testers.runNixOSTest (_: {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
testScript = ''
|
testScript = ''
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
start_all()
|
start_all()
|
||||||
machine.wait_for_unit("nginx.service")
|
machine.wait_for_unit("nginx.service")
|
||||||
machine.wait_for_unit("nar-bridge-one.service")
|
machine.wait_for_unit("tvix-store-one.service")
|
||||||
machine.wait_for_unit("nar-bridge-two.service")
|
machine.wait_for_unit("tvix-store-two.service")
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
with subtest("Nar bridge home"):
|
with subtest("Nar bridge home"):
|
||||||
out = machine.succeed("curl -L http://127.0.0.1/one")
|
machine.succeed("curl -L http://127.0.0.1/one/nix-cache-info")
|
||||||
if out != "nar-bridge":
|
|
||||||
sys.exit(1)
|
|
||||||
with subtest("Nar upload"):
|
with subtest("Nar upload"):
|
||||||
machine.succeed("nix copy --to 'http://127.0.0.1/one/?compression=none' ${hello}")
|
machine.succeed("nix copy --to 'http://127.0.0.1/one/?compression=none' ${hello}")
|
||||||
with subtest("narinfo retrieve"):
|
with subtest("narinfo retrieve"):
|
||||||
narHash = "${hello}"[11:11+32]
|
narHash = "${hello}"[11:11+32]
|
||||||
machine.succeed(f"curl -f 'http://127.0.0.1/one/{narHash}.narinfo'")
|
machine.succeed(f"curl -f 'http://127.0.0.1/one/{narHash}.narinfo'")
|
||||||
machine.fail(f"curl -f 'http://127.0.0.1/two/{narHash}.narinfo'")
|
machine.fail(f"curl -f 'http://127.0.0.1/two/{narHash}.narinfo'")
|
||||||
|
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
|
|
|
@ -22,7 +22,8 @@ pkgs.testers.runNixOSTest (_: {
|
||||||
host = "cache";
|
host = "cache";
|
||||||
};
|
};
|
||||||
caches = {
|
caches = {
|
||||||
cache.port = 8000;
|
cache.grpcListenAddress = "[::1]:5000";
|
||||||
|
cache.narBridgeListenAddress = "[::1]:8000";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,16 +43,13 @@ pkgs.testers.runNixOSTest (_: {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
testScript = ''
|
testScript = ''
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
start_all()
|
start_all()
|
||||||
cache.wait_for_unit("nginx.service")
|
cache.wait_for_unit("nginx.service")
|
||||||
cache.wait_for_unit("nar-bridge-cache.service")
|
cache.wait_for_unit("narbridge-cache.service")
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
with subtest("Nar bridge home"):
|
with subtest("Nar bridge home"):
|
||||||
out = cache.succeed("curl -L http://127.0.0.1/cache")
|
cache.succeed("curl -f http://127.0.0.1/cache/nix-cache-info")
|
||||||
if out != "nar-bridge":
|
|
||||||
sys.exit(1)
|
|
||||||
with subtest("Path signature and copy"):
|
with subtest("Path signature and copy"):
|
||||||
# Sign
|
# Sign
|
||||||
cache.succeed("nix store sign -k ${./cache-keys/privkey} ${hello}")
|
cache.succeed("nix store sign -k ${./cache-keys/privkey} ${hello}")
|
||||||
|
|
81
tests/upstream-cache-http-directory.nix
Normal file
81
tests/upstream-cache-http-directory.nix
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
{ pkgs }:
|
||||||
|
let
|
||||||
|
#hello = pkgs.hello.overrideAttrs { pname = "custom-hello"; };
|
||||||
|
inherit (pkgs) hello;
|
||||||
|
in
|
||||||
|
pkgs.testers.runNixOSTest (_: {
|
||||||
|
name = "caching of upstream nar-store";
|
||||||
|
nodes = {
|
||||||
|
cache = {
|
||||||
|
imports = [
|
||||||
|
./common
|
||||||
|
../modules
|
||||||
|
];
|
||||||
|
|
||||||
|
system.extraDependencies = [ hello ];
|
||||||
|
|
||||||
|
services = {
|
||||||
|
tvix-binary-cache = {
|
||||||
|
enable = true;
|
||||||
|
enableNginx = true;
|
||||||
|
nginx = {
|
||||||
|
clientMaxBodySize = "50G";
|
||||||
|
host = "cache";
|
||||||
|
};
|
||||||
|
caches = {
|
||||||
|
cache = {
|
||||||
|
port = 8000;
|
||||||
|
remote-path-info-service-addr = "nix+http://localhost/upstream/"; # ?trusted-public-keys=${lib.escapeURL (builtins.readFile ./cache-keys/pubkey)}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nginx = {
|
||||||
|
virtualHosts.cache = {
|
||||||
|
default = true;
|
||||||
|
locations = {
|
||||||
|
"/upstream".return = "302 /upstream/";
|
||||||
|
"/upstream/".alias = "/srv/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
networking.firewall.allowedTCPPorts = [ 80 ];
|
||||||
|
};
|
||||||
|
client =
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
imports = [ ./common ];
|
||||||
|
nix.settings = {
|
||||||
|
substituters = lib.mkForce [ "http://cache/cache" ];
|
||||||
|
trusted-public-keys = lib.mkForce [ (builtins.readFile ./cache-keys/pubkey) ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
testScript = ''
|
||||||
|
import time
|
||||||
|
start_all()
|
||||||
|
cache.wait_for_unit("nginx.service")
|
||||||
|
cache.wait_for_unit("tvix-store-cache.service")
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
def delete_and_substitute():
|
||||||
|
client.succeed("nix-store --delete ${hello}")
|
||||||
|
client.fail("stat ${hello}")
|
||||||
|
client.succeed("nix-store -r ${hello}")
|
||||||
|
client.succeed("stat ${hello}")
|
||||||
|
|
||||||
|
with subtest("Upload"):
|
||||||
|
cache.succeed("nix store sign -k ${./cache-keys/privkey} ${hello}")
|
||||||
|
cache.succeed("nix copy --to file:///srv ${hello}")
|
||||||
|
narHash = "${hello}"[11:11+32]
|
||||||
|
out = cache.succeed(f"curl -f 'http://localhost/upstream/{narHash}.narinfo'")
|
||||||
|
print(out)
|
||||||
|
cache.succeed(f"curl -f 'http://localhost/cache/{narHash}.narinfo'")
|
||||||
|
with subtest("Try to substitute from cache"):
|
||||||
|
delete_and_substitute()
|
||||||
|
with subtest("Check effective caching"):
|
||||||
|
cache.succeed("rm -rf /srv")
|
||||||
|
delete_and_substitute()
|
||||||
|
'';
|
||||||
|
})
|
87
tests/upstream-cache-nix-serve.nix
Normal file
87
tests/upstream-cache-nix-serve.nix
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
{ pkgs }:
|
||||||
|
let
|
||||||
|
#hello = pkgs.hello.overrideAttrs { pname = "custom-hello"; };
|
||||||
|
inherit (pkgs) hello;
|
||||||
|
in
|
||||||
|
pkgs.testers.runNixOSTest (_: {
|
||||||
|
name = "caching of upstream nar-store";
|
||||||
|
nodes = {
|
||||||
|
cache = {
|
||||||
|
imports = [
|
||||||
|
./common
|
||||||
|
../modules
|
||||||
|
];
|
||||||
|
|
||||||
|
system.extraDependencies = [ hello ];
|
||||||
|
|
||||||
|
services = {
|
||||||
|
tvix-binary-cache = {
|
||||||
|
enable = true;
|
||||||
|
enableNginx = true;
|
||||||
|
nginx = {
|
||||||
|
clientMaxBodySize = "50G";
|
||||||
|
host = "cache";
|
||||||
|
};
|
||||||
|
caches = {
|
||||||
|
cache = {
|
||||||
|
port = 8000;
|
||||||
|
remote-path-info-service-addr = "nix+http://localhost/upstream/"; # ?trusted-public-keys=${lib.escapeURL (builtins.readFile ./cache-keys/pubkey)}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nix-serve = {
|
||||||
|
enable = true;
|
||||||
|
port = 8001;
|
||||||
|
secretKeyFile = "${./cache-keys/privkey}";
|
||||||
|
};
|
||||||
|
|
||||||
|
nginx = {
|
||||||
|
virtualHosts.cache = {
|
||||||
|
default = true;
|
||||||
|
locations = {
|
||||||
|
"/upstream".return = "302 /upstream/";
|
||||||
|
"/upstream/".proxyPass = "http://localhost:8001/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
networking.firewall.allowedTCPPorts = [ 80 ];
|
||||||
|
};
|
||||||
|
client =
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
imports = [ ./common ];
|
||||||
|
nix.settings = {
|
||||||
|
substituters = lib.mkForce [ "http://cache/cache" ];
|
||||||
|
trusted-public-keys = lib.mkForce [ (builtins.readFile ./cache-keys/pubkey) ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
testScript = ''
|
||||||
|
import time
|
||||||
|
start_all()
|
||||||
|
cache.wait_for_unit("nginx.service")
|
||||||
|
cache.wait_for_unit("tvix-store-cache.service")
|
||||||
|
cache.wait_for_unit("nix-serve.service")
|
||||||
|
cache.wait_for_open_port(8001)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
def delete_and_substitute():
|
||||||
|
client.succeed("nix-store --delete ${hello}")
|
||||||
|
client.fail("stat ${hello}")
|
||||||
|
client.succeed("nix-store -r ${hello}")
|
||||||
|
client.succeed("stat ${hello}")
|
||||||
|
|
||||||
|
with subtest("Upload"):
|
||||||
|
narHash = "${hello}"[11:11+32]
|
||||||
|
cache.succeed(f"curl -f 'http://127.0.0.1/upstream/{narHash}.narinfo'")
|
||||||
|
cache.succeed(f"curl -f 'http://127.0.0.1/cache/{narHash}.narinfo'")
|
||||||
|
with subtest("Try to substitute from cache"):
|
||||||
|
delete_and_substitute()
|
||||||
|
with subtest("Check effective caching"):
|
||||||
|
cache.succeed("systemctl stop nix-serve.service")
|
||||||
|
delete_and_substitute()
|
||||||
|
'';
|
||||||
|
})
|
79
tests/upstream-cache-tvix.nix
Normal file
79
tests/upstream-cache-tvix.nix
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
{ pkgs }:
|
||||||
|
let
|
||||||
|
inherit (pkgs) hello;
|
||||||
|
in
|
||||||
|
pkgs.testers.runNixOSTest (_: {
|
||||||
|
name = "caching of upstream nar-store";
|
||||||
|
nodes = {
|
||||||
|
cache = {
|
||||||
|
imports = [
|
||||||
|
./common
|
||||||
|
../modules
|
||||||
|
];
|
||||||
|
|
||||||
|
system.extraDependencies = [ hello ];
|
||||||
|
|
||||||
|
services.tvix-binary-cache = {
|
||||||
|
enable = true;
|
||||||
|
enableNginx = true;
|
||||||
|
nginx = {
|
||||||
|
clientMaxBodySize = "50G";
|
||||||
|
host = "cache";
|
||||||
|
};
|
||||||
|
caches = {
|
||||||
|
cache = {
|
||||||
|
port = 8000;
|
||||||
|
path-info-service-addr = "nix+http://localhost/upstream/"; # ?trusted-public-keys=${lib.escapeURL (builtins.readFile ./cache-keys/pubkey)}";
|
||||||
|
};
|
||||||
|
upstream = {
|
||||||
|
port = 8001;
|
||||||
|
blob-service-addr = "objectstore+file://%S/tvix-store-upstream/blobs.object-store";
|
||||||
|
directory-service-addr = "sled://%S/tvix-store-upstream/directories.sled";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx = {
|
||||||
|
virtualHosts.cache = {
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
networking.firewall.allowedTCPPorts = [ 80 ];
|
||||||
|
};
|
||||||
|
client =
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
imports = [ ./common ];
|
||||||
|
nix.settings = {
|
||||||
|
substituters = lib.mkForce [ "http://cache/cache" ];
|
||||||
|
trusted-public-keys = lib.mkForce [ (builtins.readFile ./cache-keys/pubkey) ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
testScript = ''
|
||||||
|
import time
|
||||||
|
start_all()
|
||||||
|
cache.wait_for_unit("nginx.service")
|
||||||
|
cache.wait_for_unit("tvix-store-cache.service")
|
||||||
|
cache.wait_for_unit("tvix-store-upstream.service")
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
def delete_and_substitute():
|
||||||
|
client.succeed("nix-store --delete ${hello}")
|
||||||
|
client.fail("stat ${hello}")
|
||||||
|
client.succeed("nix-store -r ${hello}")
|
||||||
|
client.succeed("stat ${hello}")
|
||||||
|
|
||||||
|
with subtest("Upload"):
|
||||||
|
cache.succeed("nix store sign -k ${./cache-keys/privkey} ${hello}")
|
||||||
|
cache.succeed("nix copy --to 'http://localhost/upstream/?compression=none' ${hello}")
|
||||||
|
narHash = "${hello}"[11:11+32]
|
||||||
|
cache.succeed(f"curl -f 'http://localhost/upstream/{narHash}.narinfo'")
|
||||||
|
cache.succeed(f"curl -f 'http://localhost/cache/{narHash}.narinfo'")
|
||||||
|
with subtest("Try to substitute from cache"):
|
||||||
|
delete_and_substitute()
|
||||||
|
with subtest("Check effective caching"):
|
||||||
|
cache.succeed("systemctl stop tvix-store-upstream.service")
|
||||||
|
delete_and_substitute()
|
||||||
|
'';
|
||||||
|
})
|
Loading…
Reference in a new issue