From ab717f62e7bd57c179f55d6f6480660a96e196b1 Mon Sep 17 00:00:00 2001 From: Franziska Kunsmann Date: Sun, 22 Dec 2024 20:20:20 +0100 Subject: [PATCH] bundles/samba: add code to show up as time machine backup target --- bundles/samba/files/smb.conf | 28 +++++++++++++++++++++++++ bundles/samba/files/timemachine.service | 21 +++++++++++++++++++ bundles/samba/items.py | 26 +++++++++++++++++++++++ bundles/samba/metadata.py | 27 ++++++++++++++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 bundles/samba/files/timemachine.service diff --git a/bundles/samba/files/smb.conf b/bundles/samba/files/smb.conf index c9a7859..22905ee 100644 --- a/bundles/samba/files/smb.conf +++ b/bundles/samba/files/smb.conf @@ -13,6 +13,13 @@ map to guest = bad user load printers = no usershare allow guests = yes allow insecure wide links = yes +min protocol = SMB2 +% if timemachine: +vfs objects = fruit +fruit:aapl = yes +fruit:copyfile = yes +fruit:model = MacSamba +% endif % for name, opts in sorted(node.metadata.get('samba/shares', {}).items()): [${name}] @@ -37,3 +44,24 @@ follow symlinks = yes wide links = yes % endif % endfor +% for name in sorted(timemachine): + +[timemachine-${name}] +comment = Time Machine backup for ${name} +available = yes +browseable = yes +guest ok = no +read only = false +valid users = timemachine-${name} +path = /srv/timemachine/${name} +durable handles = yes +vfs objects = catia fruit streams_xattr + +fruit:delete_empty_adfiles = yes +fruit:metadata = stream +fruit:posix_rename = yes +fruit:time machine = yes +fruit:time machine max size = 750G +fruit:veto_appledouble = no +fruit:wipe_intentionally_left_blank_rfork = yes +% endfor diff --git a/bundles/samba/files/timemachine.service b/bundles/samba/files/timemachine.service new file mode 100644 index 0000000..d25e6e5 --- /dev/null +++ b/bundles/samba/files/timemachine.service @@ -0,0 +1,21 @@ + + + + %h + + _smb._tcp + 445 + + + _device-info._tcp + 0 + model=RackMac1,2 + + + _adisk._tcp +% for idx, share_name in enumerate(sorted(shares)): + dk${idx}=adVN=timemachine-${share_name},adVF=0x82 +% endfor + sys=waMa=0,adVF=0x100 + + diff --git a/bundles/samba/items.py b/bundles/samba/items.py index 333a338..a9567b4 100644 --- a/bundles/samba/items.py +++ b/bundles/samba/items.py @@ -11,9 +11,14 @@ svc_systemd = { }, } +timemachine_shares = node.metadata.get('samba/timemachine-shares', set()) + files = { '/etc/samba/smb.conf': { 'content_type': 'mako', + 'context': { + 'timemachine': timemachine_shares, + }, 'triggers': { 'svc_systemd:nmbd:restart', 'svc_systemd:smbd:restart', @@ -57,3 +62,24 @@ for user, uconfig in node.metadata.get('users', {}).items(): last_action = { f'action:smbpasswd_for_user_{user}', } + +if timemachine_shares: + assert node.has_bundle('avahi-daemon'), f'{node.name}: samba needs avahi-daemon to publish time machine shares' + + files['/etc/avahi/services/timemachine.service'] = { + 'content_type': 'mako', + 'context': { + 'shares': timemachine_shares, + }, + } + + for share_name in timemachine_shares: + users[f'timemachine-{share_name}'] = { + 'home': f'/srv/timemachine/{share_name}', + } + + directories[f'/srv/timemachine/{share_name}'] = { + 'owner': f'timemachine-{share_name}', + 'group': f'timemachine-{share_name}', + 'mode': '0700', + } diff --git a/bundles/samba/metadata.py b/bundles/samba/metadata.py index 7b9400c..c8243af 100644 --- a/bundles/samba/metadata.py +++ b/bundles/samba/metadata.py @@ -24,3 +24,30 @@ def firewall(metadata): }, }, } + + +@metadata_reactor.provides( + 'zfs/datasets', +) +def timemachine_zfs(metadata): + shares = metadata.get('samba/timemachine-shares', set()) + + if not shares: + return {} + + assert node.has_bundle('zfs'), f'{node.name}: time machine backups require zfs' + + datasets = { + 'tank/timemachine': {}, + } + + for share_name in shares: + datasets[f'tank/timemachine/{share_name}'] = { + 'mountpoint': f'/srv/timemachine/{share_name}', + } + + return { + 'zfs': { + 'datasets': datasets, + }, + }