1from pydantic import BaseModel, Field, PositiveInt
2from enum import Enum
3import pathlib
4from typing import Optional, List
5from fastapi import Depends, FastAPI, HTTPException, status, Response, Path, Body, Query
6
7
8class Token(BaseModel):
9    access_token: str
10    token_type: str
11
12
13class TokenData(BaseModel):
14    username: Optional[str] = None
15
16
17class User(BaseModel):
18    username: str
19    directorName: Optional[str] = None
20
21
22class UserInDB(User):
23    hashed_password: str
24
25
26class bareosBool(str, Enum):
27    yes = "yes"
28    no = "no"
29
30    def __str__(self):
31        return self.name
32
33    def __bool__(self):
34        return self.name == "yes"
35
36
37class bareosFlag(str, Enum):
38    """
39    Same as bareosBool but with different internal handling
40    """
41
42    yes = "yes"
43    no = "no"
44
45    def __str__(self):
46        return self.name
47
48    def __bool__(self):
49        return self.name == "yes"
50
51
52class bareosTime(str):
53    # TODO: define this, stuff like "20 days" or "1 months"
54    def __str__(self):
55        return self.name
56
57
58class bareosReplaceOption(str, Enum):
59    """
60    Replace option used by restore command
61    """
62
63    always = "always"
64    never = "never"
65    ifolder = "ifolder"
66    ifnewer = "ifnewer"
67
68    def __str__(self):
69        return self.name
70
71
72class bareosSpeed(str):
73    # TODO: define this
74    def __str__(self):
75        return self.name
76
77
78class bareosSize(str):
79    # TODO: define this. Samples: 300, 10G
80    def __str__(self):
81        return self.name
82
83
84class bareosACL(str):
85    # TODO: define this.
86    def __str__(self):
87        return self.name
88
89
90class jobStatus(str, Enum):
91    """
92    Allowed job status chars
93    """
94
95    A = "A"
96    B = "B"
97    C = "C"
98    D = "D"
99    E = "E"
100    F = "F"
101    I = "I"
102    L = "L"
103    M = "M"
104    R = "R"
105    S = "S"
106    T = "T"
107    W = "W"
108    a = "a"
109    c = "c"
110    d = "d"
111    e = "e"
112    f = "f"
113    i = "i"
114    j = "j"
115    l = "l"
116    m = "m"
117    p = "p"
118    q = "q"
119    s = "s"
120    t = "t"
121
122    def __str__(self):
123        return self.name
124
125
126class jobLevelChr(str, Enum):
127    """
128    Allowed job level chars
129    """
130
131    F = "F"
132    I = "I"
133    D = "D"
134    S = "S"
135    C = "C"
136    V = "V"
137    O = "O"
138    d = "d"
139    A = "A"
140    B = "B"
141    f = "f"
142
143    def __str__(self):
144        return self.name
145
146
147class jobLevel(str, Enum):
148    """
149    Allowed job level full description strings
150    """
151
152    Base = "Base"
153    Full = "Full"
154    Incremental = "Incremental"
155    Differential = "Differential"
156    Since = "Since"
157    VerifyCatalog = "Verify Catalog"
158    InitCatalog = "Init Catalog"
159    VolumetoCatalog = "Volume to Catalog"
160
161    def __str__(self):
162        return self.name
163
164
165class aclCollection(BaseModel):
166    """
167    Possible ACL options
168    """
169
170    jobacl: Optional[bareosACL] = Field(None, title="")
171    clientacl: Optional[bareosACL] = Field(None, title="")
172    storageacl: Optional[bareosACL] = Field(None, title="")
173    scheduleacl: Optional[bareosACL] = Field(None, title="")
174    poolacl: Optional[bareosACL] = Field(None, title="")
175    commandacl: Optional[bareosACL] = Field(None, title="")
176    filesetacl: Optional[bareosACL] = Field(None, title="")
177    catalogacl: Optional[bareosACL] = Field(None, title="")
178    whereacl: Optional[bareosACL] = Field(None, title="")
179    pluginoptionsacl: Optional[bareosACL] = Field(None, title="")
180
181
182class tlsSettings(BaseModel):
183    """
184    Options for TLS settings
185    """
186
187    tlsauthenticate: Optional[bareosBool] = Field(None, title="")
188    tlsenable: Optional[bareosBool] = Field(None, title="")
189    tlsrequire: Optional[bareosBool] = Field(None, title="")
190    tlscipherlist: Optional[pathlib.Path] = Field(None, title="")
191    tlsdhfile: Optional[pathlib.Path] = Field(None, title="")
192    tlsverifypeer: Optional[bareosBool] = Field(None, title="")
193    tlscacertificatefile: Optional[pathlib.Path] = Field(None, title="")
194    tlscacertificatedir: Optional[pathlib.Path] = Field(None, title="")
195    tlscertificaterevocationlist: Optional[pathlib.Path] = Field(None, title="")
196    tlscertificate: Optional[pathlib.Path] = Field(None, title="")
197    tlskey: Optional[pathlib.Path] = Field(None, title="")
198    tlsallowedcn: Optional[List[str]] = Field(None, title="")
199
200
201class volumeQuery(BaseModel):
202    """
203    Allowed query fields for volume queries
204    """
205
206    volume: Optional[str] = Field(
207        None, title="volume name to query", example="myvolume"
208    )
209    jobid: Optional[int] = Field(
210        None, title="Search for volumes used by a certain job", example="1", gt=1
211    )
212    ujobid: Optional[str] = Field(
213        None,
214        title="Search for volumes used by a certain job given by full job-name",
215        example="DefaultJob.2020-08-20_12.56.27_25",
216    )
217    pool: Optional[str] = Field(
218        None, title="Query volumes from the given pool", example="Full"
219    )
220
221
222class volumeLabelDef(BaseModel):
223    """
224    Options for volume label operation
225    """
226
227    volume: str = Field(..., title="Name for the new volume", example="Full-1742")
228    pool: str = Field(..., title="New volume will get into this pool", example="Full")
229    storage: Optional[str] = Field(None, title="Storage for this volume")
230    slot: Optional[int] = Field(None, title="Slot for this volume", ge=0)
231    drive: Optional[int] = Field(None, title="Drive number", ge=0)
232    # TODO: handle [ barcodes ] [ encrypt ] flags
233
234
235class volumeRelabelDef(BaseModel):
236    """
237    Options for volume relabel operation
238    """
239
240    volume: str = Field(..., title="New Name for Volume", example="Full-001742")
241    storage: str = Field(..., title="Volume's storage", example="File")
242    pool: str = Field(
243        ...,
244        title="Volume's pool, can stay here or be moved to this pool",
245        example="Full",
246    )
247    encrypt: Optional[bareosFlag] = Field(None, title="Encrypt volume", example="yes")
248
249
250class volumeProperties(BaseModel):
251    """
252    Volume properties that can be set for _update volume_ operation
253    """
254
255    pool: Optional[str] = Field(None, title="New pool for this volume", example="Full")
256    slot: Optional[int] = Field(None, title="New slot for this volume", ge=0)
257    volstatus: Optional[str] = Field(
258        None, title="New status for this volume", example="Archive"
259    )
260    volretention: Optional[bareosTime] = Field(
261        None, title="Volume retention time", example="1 month"
262    )
263    actiononpurge: Optional[str] = Field(None, title="Action to execute on purge")
264    recycle: Optional[bareosBool] = Field(None, title="Set recycle flag")
265    inchanger: Optional[bareosBool] = Field(None, title="Set inchanger flag")
266    maxvolbytes: Optional[bareosSize] = Field(
267        None, title="Set max byte size for this volume", example="20G"
268    )
269    maxvolfiles: Optional[int] = Field(
270        None, title="Set max number of files for this volume", ge=0, example="10000"
271    )
272    maxvoljobs: Optional[int] = Field(
273        None, title="Set max number of jobs for this volume", ge=0, example="20"
274    )
275    enabled: Optional[bareosBool] = Field(None, title="Enable / disable volume")
276    recyclepool: Optional[str] = Field(
277        None, title="Define recyclepool for this volume", example="Scratch"
278    )
279
280
281class volumeMove(BaseModel):
282    # parameters used for move
283    storage: str = Field(..., title="Storage to use for move operation")
284    srcslots: str = Field(..., title="Source slot selection")
285    dstslots: str = Field(..., title="Destination slot selection")
286
287
288class volumeExport(BaseModel):
289    storage: str = Field(..., title="Storage to use for move operation")
290    srcslots: str = Field(..., title="Source slot selection")
291    dstslots: Optional[str] = Field(None, title="Destination slot selection")
292    volume: Optional[str] = Field(
293        None, title="Volume selection", example="A00020L4|A00007L4|A00005L4"
294    )
295    scan: Optional[bareosFlag] = Field(None, title="scan volume")
296
297
298class volumeImport(BaseModel):
299    storage: str = Field(..., title="Storage to use for import operation")
300    srcslots: Optional[str] = Field(..., title="Source slot selection")
301    dstslots: Optional[str] = Field(None, title="Destination slot selection")
302    volume: Optional[str] = Field(None, title="Volume name")
303    scan: Optional[bareosFlag] = Field(None, title="scan volume")
304
305
306class poolResource(BaseModel):
307    name: str = Body(..., title="Pool name")
308    description: Optional[str] = Field(None, title="")
309    pooltype: Optional[str] = Field(None, title="")
310    labelformat: Optional[str] = Field(None, title="")
311    labeltype: Optional[str] = Field(None, title="")
312    cleaningprefix: Optional[str] = Field(None, title="")
313    usecatalog: Optional[bareosBool] = Field(None, title="")
314    purgeoldestvolume: Optional[bareosBool] = Field(None, title="")
315    actiononpurge: Optional[str] = Field(None, title="")
316    recycleoldestvolume: Optional[bareosBool] = Field(None, title="")
317    recyclecurrentvolume: Optional[bareosBool] = Field(None, title="")
318    maximumvolumes: Optional[int] = Field(None, title="", ge=1)
319    maximumvolumejobs: Optional[int] = Field(None, title="", ge=1)
320    maximumvolumefiles: Optional[int] = Field(None, title="", ge=1)
321    maximumvolumebytes: Optional[int] = Field(None, title="")
322    catalogfiles: Optional[bareosBool] = Field(None, title="")
323    volumeretention: Optional[bareosTime] = Field(None, title="")
324    volumeuseduration: Optional[bareosTime] = Field(None, title="")
325    migrationtime: Optional[bareosTime] = Field(None, title="")
326    migrationhighbytes: Optional[int] = Field(None, title="")
327    migrationlowbytes: Optional[int] = Field(None, title="")
328    nextpool: Optional[str] = Field(None, title="")
329    storage: Optional[List[str]] = Field(None, title="")
330    autoprune: Optional[bareosBool] = Field(None, title="")
331    recycle: Optional[bareosBool] = Field(None, title="")
332    recyclepool: Optional[str] = Field(None, title="")
333    scratchpool: Optional[str] = Field(None, title="")
334    catalog: Optional[str] = Field(None, title="")
335    fileretention: Optional[bareosTime] = Field(None, title="")
336    jobretention: Optional[bareosTime] = Field(None, title="")
337    minimumblocksize: Optional[int] = Field(None, title="")
338    maximumblocksize: Optional[int] = Field(None, title="")
339
340
341class scheduleResource(BaseModel):
342    name: str = Body(..., title="Schedule name")
343    description: Optional[str] = Body(None, title="Schedule Description")
344    runCommand: Optional[List[str]] = Body(
345        None,
346        title="A list of run statements",
347        example=["Full 1st Sat at 12:00", "Incremental Sun-Fri at 11:00"],
348    )
349    enabled: Optional[bareosBool] = Body(
350        None, title="Schedule enabled? Yes, if unset", example="no"
351    )
352
353
354class profileResource(aclCollection):
355    name: str = Field(..., title="resource name")
356    description: Optional[str] = Field(None, title="Description")
357
358
359class userResource(profileResource):
360    profile: Optional[List[str]] = Field(
361        None, title="List of profile names for this user"
362    )
363
364
365class jobRange(BaseModel):
366    days: Optional[int] = Field(
367        None, title="Query jobs run max days ago", gt=1, example=7
368    )
369    hours: Optional[int] = Field(
370        None, title="Query jobs run max hours ago", gt=1, example=12
371    )
372    since_jobid: Optional[int] = Field(
373        None, title="Run all jobs since the given job by id", ge=1
374    )
375    unitl_jobid: Optional[int] = Field(
376        None, title="Run all jobs until the given job by id", ge=1
377    )
378
379
380# class bareosTimeSpec(BaseModel):
381#    # TODO: better specification / Regex?
382#    timeSpec: str = Field(None, title="Bareos universal time specification")
383
384
385class jobControl(BaseModel):
386    job: str = Field(..., title="Job name to run", example="myjob")
387    client: str = Field(None, title="Client to run job on", example="myclient-fd")
388    fileset: Optional[str] = Field(
389        None, title="Fileset to use", example="server-fileset"
390    )
391    level: Optional[jobLevel] = Field(None, title="Job level to query", example="Full")
392    storage: Optional[str] = Field(None, title="Storage to use")
393    when: Optional[str] = Field(
394        None, title="When to run job, Bareos universal timespec"
395    )
396    pool: Optional[str] = Field(None, title="Pool to use", example="LTO-Pool")
397    pluginoptions: Optional[str] = Field(
398        None, title="Overwrite eventual plugin options"
399    )
400    accurate: Optional[bareosBool] = Field(None, title="Set / unset accurate option")
401    comment: Optional[str] = Field(None, title="Comment")
402    spooldata: Optional[bareosBool] = Field(None, title="Spooling")
403    priority: Optional[str] = Field(
404        None, title="Priority, higher number means lower prio"
405    )
406    catalog: Optional[str] = Field(None, title="Catalog to use for this job")
407    # migrationjob in help run list but not in documentation
408    migrationjob: Optional[str] = Field(None)
409    backupformat: Optional[str] = Field(
410        None,
411        title="The backup format used for protocols which support multiple formats.",
412    )
413    nextpool: Optional[str] = Field(
414        None,
415        title="A Next Pool override used for Migration/Copy and Virtual Backup Jobs.",
416    )
417    # since in help run list but not in documentation
418    since: Optional[str] = Field(
419        None,
420        title="Set since time for differential / incremental jobs. Bareos universal timespec",
421    )
422    verifyjob: Optional[str] = Field(None)
423    verifylist: Optional[str] = Field(None)
424    migrationjob: Optional[str] = Field(None)
425
426
427class restoreJobControl(BaseModel):
428    client: str = Field(..., title="Restore data from this client")
429    where: Optional[pathlib.Path] = Field(
430        None, title="Filesystem prefix. Use _/_ for original location", example="/"
431    )
432    storage: Optional[str] = Field(None, title="")
433    bootstrap: Optional[str] = Field(None, title="")
434    restorejob: Optional[str] = Field(None, title="")
435    comment: Optional[str] = Field(None, title="")
436    jobid: Optional[int] = Field(
437        None, title="Restore all files backuped by a given jobid", ge=1
438    )
439    fileset: Optional[str] = Field(None, title="")
440    replace: Optional[bareosReplaceOption] = Field(
441        None, title="Set file-replace options", example="ifnewer"
442    )
443    pluginoptions: Optional[str] = Field(None, title="")
444    regexwhere: Optional[str] = Field(None, title="")
445    restoreclient: Optional[str] = Field(None, title="Restore data to this client")
446    backupformat: Optional[str] = Field(None, title="")
447    pool: Optional[str] = Field(None, title="")
448    file: Optional[str] = Field(None, title="")
449    # can't use pathlib.Path here, as it strips trailing /, which is required by Bareos to accept a path
450    directory: Optional[str] = Field(None, title="")
451    before: Optional[str] = Field(None, title="")
452    strip_prefix: Optional[str] = Field(None, title="")
453    add_prefix: Optional[str] = Field(None, title="")
454    add_suffix: Optional[str] = Field(None, title="")
455    select: Optional[str] = Field(None, title="use select=date")
456    selectAllDone: Optional[bareosBool] = Field(
457        None, title="Run restore job with _select all done_ option"
458    )
459
460
461class jobResource(BaseModel):
462    # TODO: complete field description 'title' and find meaningful examples
463    messages: str = Field(..., title="Message resource identifier", example="Standard")
464    name: str = Field(..., title="Name for this resource", example="DefaultJob")
465    pool: str = Field(..., title="Pool for this job", example="Full")
466    jobdefs: str = Field(..., title="Jobdefs to use", example="DefaultJob")
467    type: str = Field(..., title="Job type", example="Backup")
468    accurate: Optional[bareosBool] = Field(
469        None,
470        title="Accurate setting, will be default 'no' if unset here",
471        example="yes",
472    )
473    addprefix: Optional[str] = Field(None, title="")
474    addsuffix: Optional[str] = Field(None, title="")
475    allowduplicatejobs: Optional[bareosBool] = Field(None, title="")
476    allowhigherduplicates: Optional[bareosBool] = Field(None, title="")
477    allowmixedpriority: Optional[bareosBool] = Field(None, title="")
478    alwaysincremental: Optional[bareosBool] = Field(None, title="")
479    alwaysincrementaljobretention: Optional[bareosTime] = Field(
480        None, title="", example="20 days"
481    )
482    alwaysincrementalkeepnumber: Optional[int] = Field(None, title="", ge=1, example=5)
483    cancellowerlevelduplicates: Optional[bareosBool] = Field(None, title="")
484    cancelqueuedduplicates: Optional[bareosBool] = Field(None, title="")
485    cancelrunningduplicates: Optional[bareosBool] = Field(None, title="")
486    catalog: Optional[str] = Field(None, title="")
487    client: Optional[str] = Field(None, title="")
488    clientrunafterjob: Optional[str] = Field(None, title="")
489    clientrunbeforejob: Optional[str] = Field(None, title="")
490    description: Optional[str] = Field(None, title="")
491    differentialbackuppool: Optional[str] = Field(None, title="")
492    differentialmaxruntime: Optional[bareosTime] = Field(None, title="")
493    dirpluginoptions: List[str] = Field(None, title="")
494    enabled: Optional[bareosBool] = Field(None, title="")
495    fdpluginoptions: List[str] = Field(None, title="")
496    filehistorysize: Optional[int] = Field(None, title="", gt=1)
497    fileset: Optional[str] = Field(None, title="")
498    fullbackuppool: Optional[str] = Field(None, title="")
499    fullmaxruntime: Optional[bareosTime] = Field(None, title="")
500    incrementalbackuppool: Optional[str] = Field(None, title="")
501    incrementalmaxruntime: Optional[bareosTime] = Field(None, title="")
502    jobtoverify: Optional[str] = Field(None, title="")
503    level: Optional[jobLevel] = Field(None, title="Job Level", example="Full")
504    maxconcurrentcopies: Optional[int] = Field(None, title="", gt=1)
505    maxdiffinterval: Optional[bareosTime] = Field(None, title="")
506    maxfullconsolidations: Optional[int] = Field(None, title="", gt=1)
507    maxfullinterval: Optional[bareosTime] = Field(None, title="")
508    maximumbandwidth: Optional[bareosSpeed] = Field(None, title="")
509    maximumconcurrentjobs: Optional[int] = Field(None, title="")
510    maxrunschedtime: Optional[bareosTime] = Field(None, title="")
511    maxruntime: Optional[bareosTime] = Field(None, title="")
512    maxstartdelay: Optional[bareosTime] = Field(None, title="")
513    maxvirtualfullinterval: Optional[bareosTime] = Field(None, title="")
514    maxwaittime: Optional[bareosTime] = Field(None, title="")
515    nextpool: Optional[str] = Field(None, title="")
516    prefermountedvolumes: Optional[bareosBool] = Field(None, title="")
517    prefixlinks: Optional[bareosBool] = Field(None, title="")
518    priority: Optional[int] = Field(None, title="", gt=1)
519    protocol: Optional[str] = Field(None, title="")
520    prunefiles: Optional[bareosBool] = Field(None, title="")
521    prunejobs: Optional[bareosBool] = Field(None, title="")
522    prunevolumes: Optional[bareosBool] = Field(None, title="")
523    purgemigrationjob: Optional[bareosBool] = Field(None, title="")
524    regexwhere: Optional[str] = Field(None, title="")
525    replace: Optional[str] = Field(None, title="")
526    rerunfailedlevels: Optional[bareosBool] = Field(None, title="")
527    rescheduleinterval: Optional[bareosTime] = Field(None, title="")
528    rescheduleonerror: Optional[bareosBool] = Field(None, title="")
529    rescheduletimes: Optional[int] = Field(None, title="", gt=1)
530    runafterfailedjob: Optional[str] = Field(None, title="")
531    runafterjob: Optional[str] = Field(None, title="")
532    runbeforejob: Optional[str] = Field(None, title="")
533    runonincomingconnectinterval: Optional[bareosTime] = Field(None, title="")
534    run: List[str] = Field(None, title="")
535    savefilehistory: Optional[bareosBool] = Field(None, title="")
536    schedule: Optional[str] = Field(None, title="")
537    sdpluginoptions: List[str] = Field(None, title="")
538    selectionpattern: Optional[str] = Field(None, title="")
539    selectiontype: Optional[str] = Field(None, title="", example="OldestVolume")
540    spoolattributes: Optional[bareosBool] = Field(None, title="")
541    spooldata: Optional[bareosBool] = Field(None, title="")
542    spoolsize: Optional[int] = Field(None, title="", gt=1)
543    storage: List[str] = Field(None, title="")
544    stripprefix: Optional[str] = Field(None, title="")
545    virtualfullbackuppool: Optional[str] = Field(None, title="")
546    where: Optional[pathlib.Path] = Field(None, title="")
547    writebootstrap: Optional[pathlib.Path] = Field(None, title="")
548    writeverifylist: Optional[pathlib.Path] = Field(None, title="")
549
550
551class jobDefs(jobResource):
552    jobdefs: Optional[str] = Field(None, title="Jobdefs to use", example="DefaultJob")
553
554
555class clientResource(tlsSettings):
556    name: str
557    address: str
558    password: str
559    description: Optional[str] = Field(None, title="A client description")
560    passive: Optional[bareosBool] = Field(
561        None,
562        title="Passive clients will wait for Director and SD to open any connection",
563    )
564    port: Optional[int] = Field(None, gt=1, le=65535)
565    protocol: Optional[str] = Field(None)
566    authtype: Optional[str] = Field(None)
567    lanaddress: Optional[str] = Field(None)
568    username: Optional[str] = Field(None)
569    catalog: Optional[str] = Field(None)
570    connectionfromdirectortoclient: Optional[bareosBool] = Field(None)
571    connectionfromclienttodirector: Optional[bareosBool] = Field(None)
572    enabled: Optional[bareosBool] = Field(None)
573    hardquota: Optional[int] = Field(None)
574    softquota: Optional[int] = Field(None)
575    softquotagraceperiod: Optional[str] = Field(None)
576    strictquotas: Optional[bareosBool] = Field(None)
577    quotaincludefailedjobs: Optional[bareosBool] = Field(None)
578    fileretention: Optional[str] = Field(None)
579    jobretention: Optional[str] = Field(None)
580    heartbeatinterval: Optional[str] = Field(None)
581    autoprune: Optional[bareosBool] = Field(None)
582    maximumconcurrentjobs: Optional[PositiveInt] = Field(None)
583    maximumbandwidthperjob: Optional[str] = Field(None)
584    ndmploglevel: Optional[PositiveInt] = Field(None)
585    ndmpblocksize: Optional[PositiveInt] = Field(None)
586    ndmpuselmdb: Optional[bareosBool] = Field(None)
587
588
589class deviceResource(tlsSettings):
590    device: str = Field(..., title="")
591    mediatype: str = Field(..., title="")
592    description: Optional[str] = Field(None, title="")
593    protocol: Optional[str] = Field(None, title="")
594    authtype: Optional[str] = Field(None, title="")
595    lanaddress: Optional[str] = Field(None, title="")
596    port: Optional[int] = Field(None, title="", ge=1)
597    username: Optional[str] = Field(None, title="")
598    autochanger: Optional[bareosBool] = Field(None, title="")
599    enabled: Optional[bareosBool] = Field(None, title="")
600    allowcompression: Optional[bareosBool] = Field(None, title="")
601    heartbeatinterval: Optional[bareosTime] = Field(None, title="")
602    cachestatusinterval: Optional[bareosTime] = Field(None, title="")
603    maximumconcurrentjobs: Optional[int] = Field(None, title="", ge=1)
604    maximumconcurrentreadjobs: Optional[int] = Field(None, title="", ge=1)
605    pairedstorage: Optional[str] = Field(None, title="")
606    maximumbandwidthperjob: Optional[bareosSpeed] = Field(None, title="")
607    collectstatistics: Optional[bareosBool] = Field(None, title="")
608    ndmpchangerdevice: Optional[str] = Field(None, title="")
609
610
611class storageResource(deviceResource):
612    name: str = Field(..., title="")
613    address: str = Field(..., title="")
614    password: str = Field(..., title="")
615
616
617class consoleResource(userResource, tlsSettings):
618    password: str = Field(..., title="Console password")
619
620
621class jobQuery(BaseModel):
622    job: Optional[str] = Field(None, title="Job name to query", example="myjob")
623    client: Optional[str] = Field(None, title="Client to query", example="myclient-fd")
624    jobstatus: Optional[jobStatus] = Field(
625        None, title="Job status to query", example="T"
626    )
627    joblevel: Optional[jobLevelChr] = Field(
628        None, title="Job level to query", example="F"
629    )
630    volume: Optional[str] = Field(
631        None, title="Query jobs on the given volume", example="Full-0017"
632    )
633    days: Optional[int] = Field(
634        None, title="Query jobs run max days ago", gt=1, example=7
635    )
636    hours: Optional[int] = Field(
637        None, title="Query jobs run max hours ago", gt=1, example=12
638    )
639