]>
git.proxmox.com Git - pve-guest-common.git/blob - PVE/ReplicationConfig.pm
1 package PVE
:: ReplicationConfig
;
8 use PVE
:: JSONSchema
qw(get_standard_option) ;
10 use PVE
:: SectionConfig
;
11 use PVE
:: CalendarEvent
;
13 use PVE
:: Cluster
qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file) ;
15 use base
qw(PVE::SectionConfig) ;
17 my $replication_cfg_filename = 'replication.cfg' ;
19 cfs_register_file
( $replication_cfg_filename,
20 sub { __PACKAGE__-
> parse_config ( @_ ); },
21 sub { __PACKAGE__-
> write_config ( @_ ); });
23 PVE
:: JSONSchema
:: register_format
( 'pve-replication-job-id' ,
24 \
& parse_replication_job_id
);
25 sub parse_replication_job_id
{
26 my ( $id, $noerr ) = @_ ;
28 my $msg = "invalid replication job id ' $id '" ;
30 if ( $id =~ m/^(\d+)-(\d+)$/ ) {
31 my ( $guest, $jobnum ) = ( int ( $1 ), int ( $2 ));
32 die " $msg (guest IDs < 100 are reseved) \n " if $guest < 100 ;
33 my $parsed_id = " $guest - $jobnum " ; # use parsed integers
34 return wantarray ?
( $guest, $jobnum, $parsed_id ) : $parsed_id ;
37 return undef if $noerr ;
42 PVE
:: JSONSchema
:: register_standard_option
( 'pve-replication-id' , {
43 description
=> "Replication Job ID. The ID is composed of a Guest ID and a job number, separated by a hyphen, i.e. '<GUEST>-<JOBNUM>'." ,
44 type
=> 'string' , format
=> 'pve-replication-job-id' ,
45 pattern
=> '[1-9][0-9]{2,8}-\d{1,9}' ,
50 type
=> { description
=> "Section type." },
51 id
=> get_standard_option
( 'pve-replication-id' ),
53 description
=> "Flag to disable/deactivate the entry." ,
58 description
=> "Description." ,
64 description
=> "Mark the replication job for removal. The job will remove all local replication snapshots. When set to 'full', it also tries to remove replicated volumes on the target. The job then removes itself from the configuration file." ,
66 enum
=> [ 'local' , 'full' ],
70 description
=> "Rate limit in mbps (megabytes per second) as floating point number." ,
76 description
=> "Storage replication schedule. The format is a subset of `systemd` calender events." ,
77 type
=> 'string' , format
=> 'pve-calendar-event' ,
89 sub parse_section_header
{
90 my ( $class, $line ) = @_ ;
92 if ( $line =~ m/^(\S+):\s*(\d+)-(\d+)\s*$/ ) {
93 my ( $type, $guest, $subid ) = ( lc ( $1 ), int ( $2 ), int ( $3 ));
94 my $id = " $guest - $subid " ; # use parsed integers
95 my $errmsg = undef ; # set if you want to skip whole section
96 eval { parse_replication_job_id
( $id ); };
99 return ( $type, $id, $errmsg, $config );
104 # Note: We want only one replication job per target to
105 # avoid confusion. This method should return a string
106 # which uniquely identifies the target.
107 sub get_unique_target_id
{
108 my ( $class, $data ) = @_ ;
110 die "please overwrite in subclass" ;
114 my ( $class, $filename, $raw ) = @_ ;
116 my $cfg = $class -> SUPER :: parse_config
( $filename, $raw );
118 my $target_hash = {};
120 foreach my $id ( sort keys %{ $cfg ->{ ids
}}) {
121 my $data = $cfg ->{ ids
}->{ $id };
123 my ( $guest, $jobnum ) = parse_replication_job_id
( $id );
125 $data ->{ guest
} = $guest ;
126 $data ->{ jobnum
} = $jobnum ;
128 $data ->{ comment
} = PVE
:: Tools
:: decode_text
( $data ->{ comment
})
129 if defined ( $data ->{ comment
});
131 my $plugin = $class -> lookup ( $data ->{ type
});
132 my $tid = $plugin -> get_unique_target_id ( $data );
133 my $vmid = $data ->{ guest
};
135 # should not happen, but we want to be sure
136 if ( defined ( $target_hash ->{ $vmid }->{ $tid })) {
137 warn "delete job $id : replication job for guest ' $vmid ' to target ' $tid ' already exists \n " ;
138 delete $cfg ->{ ids
}->{ $id };
140 $target_hash ->{ $vmid }->{ $tid } = 1 ;
147 my ( $class, $filename, $cfg ) = @_ ;
149 my $target_hash = {};
151 foreach my $id ( keys %{ $cfg ->{ ids
}}) {
152 my $data = $cfg ->{ ids
}->{ $id };
154 my $plugin = $class -> lookup ( $data ->{ type
});
155 my $tid = $plugin -> get_unique_target_id ( $data );
156 my $vmid = $data ->{ guest
};
158 die "property 'guest' has wrong value \n " if $id !~ m/^\Q$vmid\E-/ ;
159 die "replication job for guest ' $vmid ' to target ' $tid ' already exists \n "
160 if defined ( $target_hash ->{ $vmid }->{ $tid });
161 $target_hash ->{ $vmid }->{ $tid } = 1 ;
163 $data ->{ comment
} = PVE
:: Tools
:: encode_text
( $data ->{ comment
})
164 if defined ( $data ->{ comment
});
167 $class -> SUPER :: write_config
( $filename, $cfg );
173 my $class = ref ( $type ) || $type ;
175 my $cfg = cfs_read_file
( $replication_cfg_filename );
177 return bless $cfg, $class ;
183 cfs_write_file
( $replication_cfg_filename, $cfg );
187 my ( $code, $errmsg ) = @_ ;
189 cfs_lock_file
( $replication_cfg_filename, undef , $code );
192 $errmsg ?
die " $errmsg : $err " : die $err ;
196 sub check_for_existing_jobs
{
197 my ( $cfg, $vmid, $noerr ) = @_ ;
199 foreach my $id ( keys %{ $cfg ->{ ids
}}) {
200 my $data = $cfg ->{ ids
}->{ $id };
202 if ( $data ->{ guest
} == $vmid ) {
204 die "There is a replication job ' $id ' for guest ' $vmid ' - " .
205 "Please remove that first. \n "
216 my $cfg = __PACKAGE__-
> new ();
217 delete $cfg ->{ ids
}->{ $jobid };
224 package PVE
:: ReplicationConfig
:: Cluster
;
226 use base
qw(PVE::ReplicationConfig) ;
235 description
=> "Target node." ,
236 type
=> 'string' , format
=> 'pve-node' ,
243 target
=> { fixed
=> 1 , optional
=> 0 },
244 disable
=> { optional
=> 1 },
245 comment
=> { optional
=> 1 },
246 rate
=> { optional
=> 1 },
247 schedule
=> { optional
=> 1 },
248 remove_job
=> { optional
=> 1 },
252 sub get_unique_target_id
{
253 my ( $class, $data ) = @_ ;
255 return "local/ $data ->{target}" ;
258 PVE
:: ReplicationConfig
:: Cluster-
> register ();
259 PVE
:: ReplicationConfig-
> init ();