Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / OpCodes.hs @ 66af5ec5

History | View | Annotate | Download (16.7 kB)

1
{-# LANGUAGE TemplateHaskell #-}
2

    
3
{-| Implementation of the opcodes.
4

    
5
-}
6

    
7
{-
8

    
9
Copyright (C) 2009, 2010, 2011, 2012, 2013 Google Inc.
10

    
11
This program is free software; you can redistribute it and/or modify
12
it under the terms of the GNU General Public License as published by
13
the Free Software Foundation; either version 2 of the License, or
14
(at your option) any later version.
15

    
16
This program is distributed in the hope that it will be useful, but
17
WITHOUT ANY WARRANTY; without even the implied warranty of
18
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19
General Public License for more details.
20

    
21
You should have received a copy of the GNU General Public License
22
along with this program; if not, write to the Free Software
23
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24
02110-1301, USA.
25

    
26
-}
27

    
28
module Ganeti.OpCodes
29
  ( OpCode(..)
30
  , TagObject(..)
31
  , tagObjectFrom
32
  , encodeTagObject
33
  , decodeTagObject
34
  , ReplaceDisksMode(..)
35
  , DiskIndex
36
  , mkDiskIndex
37
  , unDiskIndex
38
  , opID
39
  , allOpIDs
40
  , allOpFields
41
  , opSummary
42
  , CommonOpParams(..)
43
  , defOpParams
44
  , MetaOpCode(..)
45
  , wrapOpCode
46
  , setOpComment
47
  , setOpPriority
48
  ) where
49

    
50
import Data.Maybe (fromMaybe)
51
import Text.JSON (readJSON, showJSON, JSON, JSValue, makeObj)
52
import qualified Text.JSON
53

    
54
import Ganeti.THH
55

    
56
import Ganeti.OpParams
57
import Ganeti.Types (OpSubmitPriority(..), fromNonEmpty)
58
import Ganeti.Query.Language (queryTypeOpToRaw)
59

    
60
-- | OpCode representation.
61
--
62
-- We only implement a subset of Ganeti opcodes: those which are actually used
63
-- in the htools codebase.
64
$(genOpCode "OpCode"
65
  [ ("OpTestDelay",
66
     [ pDelayDuration
67
     , pDelayOnMaster
68
     , pDelayOnNodes
69
     , pDelayRepeat
70
     ])
71
  , ("OpInstanceReplaceDisks",
72
     [ pInstanceName
73
     , pEarlyRelease
74
     , pIgnoreIpolicy
75
     , pReplaceDisksMode
76
     , pReplaceDisksList
77
     , pRemoteNode
78
     , pIallocator
79
     ])
80
  , ("OpInstanceFailover",
81
     [ pInstanceName
82
     , pShutdownTimeout
83
     , pIgnoreConsistency
84
     , pMigrationTargetNode
85
     , pIgnoreIpolicy
86
     , pIallocator
87
     ])
88
  , ("OpInstanceMigrate",
89
     [ pInstanceName
90
     , pMigrationMode
91
     , pMigrationLive
92
     , pMigrationTargetNode
93
     , pAllowRuntimeChgs
94
     , pIgnoreIpolicy
95
     , pMigrationCleanup
96
     , pIallocator
97
     , pAllowFailover
98
     ])
99
  , ("OpTagsGet",
100
     [ pTagsObject
101
     , pUseLocking
102
     ])
103
  , ("OpTagsSearch",
104
     [ pTagSearchPattern ])
105
  , ("OpTagsSet",
106
     [ pTagsObject
107
     , pTagsList
108
     ])
109
  , ("OpTagsDel",
110
     [ pTagsObject
111
     , pTagsList
112
     ])
113
  , ("OpClusterPostInit", [])
114
  , ("OpClusterDestroy", [])
115
  , ("OpClusterQuery", [])
116
  , ("OpClusterVerify",
117
     [ pDebugSimulateErrors
118
     , pErrorCodes
119
     , pSkipChecks
120
     , pIgnoreErrors
121
     , pVerbose
122
     , pOptGroupName
123
     ])
124
  , ("OpClusterVerifyConfig",
125
     [ pDebugSimulateErrors
126
     , pErrorCodes
127
     , pIgnoreErrors
128
     , pVerbose
129
     ])
130
  , ("OpClusterVerifyGroup",
131
     [ pGroupName
132
     , pDebugSimulateErrors
133
     , pErrorCodes
134
     , pSkipChecks
135
     , pIgnoreErrors
136
     , pVerbose
137
     ])
138
  , ("OpClusterVerifyDisks", [])
139
  , ("OpGroupVerifyDisks",
140
     [ pGroupName
141
     ])
142
  , ("OpClusterRepairDiskSizes",
143
     [ pInstances
144
     ])
145
  , ("OpClusterConfigQuery",
146
     [ pOutputFields
147
     ])
148
  , ("OpClusterRename",
149
     [ pName
150
     ])
151
  , ("OpClusterSetParams",
152
     [ pHvState
153
     , pDiskState
154
     , pVgName
155
     , pEnabledHypervisors
156
     , pClusterHvParams
157
     , pClusterBeParams
158
     , pOsHvp
159
     , pClusterOsParams
160
     , pDiskParams
161
     , pCandidatePoolSize
162
     , pUidPool
163
     , pAddUids
164
     , pRemoveUids
165
     , pMaintainNodeHealth
166
     , pPreallocWipeDisks
167
     , pNicParams
168
     , pNdParams
169
     , pIpolicy
170
     , pDrbdHelper
171
     , pDefaultIAllocator
172
     , pMasterNetdev
173
     , pMasterNetmask
174
     , pReservedLvs
175
     , pHiddenOs
176
     , pBlacklistedOs
177
     , pUseExternalMipScript
178
     -- FIXME: Remove once enabled disk templates are fully implemented.
179
     , pEnabledStorageTypes
180
     , pEnabledDiskTemplates
181
     ])
182
  , ("OpClusterRedistConf", [])
183
  , ("OpClusterActivateMasterIp", [])
184
  , ("OpClusterDeactivateMasterIp", [])
185
  , ("OpQuery",
186
     [ pQueryWhat
187
     , pUseLocking
188
     , pQueryFields
189
     , pQueryFilter
190
     ])
191
  , ("OpQueryFields",
192
     [ pQueryWhat
193
     , pQueryFields
194
     ])
195
  , ("OpOobCommand",
196
     [ pNodeNames
197
     , pOobCommand
198
     , pOobTimeout
199
     , pIgnoreStatus
200
     , pPowerDelay
201
     ])
202
  , ("OpNodeRemove", [ pNodeName ])
203
  , ("OpNodeAdd",
204
     [ pNodeName
205
     , pHvState
206
     , pDiskState
207
     , pPrimaryIp
208
     , pSecondaryIp
209
     , pReadd
210
     , pNodeGroup
211
     , pMasterCapable
212
     , pVmCapable
213
     , pNdParams
214
    ])
215
  , ("OpNodeQuery", dOldQuery)
216
  , ("OpNodeQueryvols",
217
     [ pOutputFields
218
     , pNodes
219
     ])
220
  , ("OpNodeQueryStorage",
221
     [ pOutputFields
222
     , pStorageType
223
     , pNodes
224
     , pStorageName
225
     ])
226
  , ("OpNodeModifyStorage",
227
     [ pNodeName
228
     , pStorageType
229
     , pStorageName
230
     , pStorageChanges
231
     ])
232
  , ("OpRepairNodeStorage",
233
     [ pNodeName
234
     , pStorageType
235
     , pStorageName
236
     , pIgnoreConsistency
237
     ])
238
  , ("OpNodeSetParams",
239
     [ pNodeName
240
     , pForce
241
     , pHvState
242
     , pDiskState
243
     , pMasterCandidate
244
     , pOffline
245
     , pDrained
246
     , pAutoPromote
247
     , pMasterCapable
248
     , pVmCapable
249
     , pSecondaryIp
250
     , pNdParams
251
     , pPowered
252
     ])
253
  , ("OpNodePowercycle",
254
     [ pNodeName
255
     , pForce
256
     ])
257
  , ("OpNodeMigrate",
258
     [ pNodeName
259
     , pMigrationMode
260
     , pMigrationLive
261
     , pMigrationTargetNode
262
     , pAllowRuntimeChgs
263
     , pIgnoreIpolicy
264
     , pIallocator
265
     ])
266
  , ("OpNodeEvacuate",
267
     [ pEarlyRelease
268
     , pNodeName
269
     , pRemoteNode
270
     , pIallocator
271
     , pEvacMode
272
     ])
273
  , ("OpInstanceCreate",
274
     [ pInstanceName
275
     , pForceVariant
276
     , pWaitForSync
277
     , pNameCheck
278
     , pIgnoreIpolicy
279
     , pInstBeParams
280
     , pInstDisks
281
     , pDiskTemplate
282
     , pFileDriver
283
     , pFileStorageDir
284
     , pInstHvParams
285
     , pHypervisor
286
     , pIallocator
287
     , pResetDefaults
288
     , pIpCheck
289
     , pIpConflictsCheck
290
     , pInstCreateMode
291
     , pInstNics
292
     , pNoInstall
293
     , pInstOsParams
294
     , pInstOs
295
     , pPrimaryNode
296
     , pSecondaryNode
297
     , pSourceHandshake
298
     , pSourceInstance
299
     , pSourceShutdownTimeout
300
     , pSourceX509Ca
301
     , pSrcNode
302
     , pSrcPath
303
     , pStartInstance
304
     , pOpportunisticLocking
305
     , pInstTags
306
     ])
307
  , ("OpInstanceMultiAlloc",
308
     [ pIallocator
309
     , pMultiAllocInstances
310
     , pOpportunisticLocking
311
     ])
312
  , ("OpInstanceReinstall",
313
     [ pInstanceName
314
     , pForceVariant
315
     , pInstOs
316
     , pTempOsParams
317
     ])
318
  , ("OpInstanceRemove",
319
     [ pInstanceName
320
     , pShutdownTimeout
321
     , pIgnoreFailures
322
     ])
323
  , ("OpInstanceRename",
324
     [ pInstanceName
325
     , pNewName
326
     , pNameCheck
327
     , pIpCheck
328
     ])
329
  , ("OpInstanceStartup",
330
     [ pInstanceName
331
     , pForce
332
     , pIgnoreOfflineNodes
333
     , pTempHvParams
334
     , pTempBeParams
335
     , pNoRemember
336
     , pStartupPaused
337
     ])
338
  , ("OpInstanceShutdown",
339
     [ pInstanceName
340
     , pForce
341
     , pIgnoreOfflineNodes
342
     , pShutdownTimeout'
343
     , pNoRemember
344
     ])
345
  , ("OpInstanceReboot",
346
     [ pInstanceName
347
     , pShutdownTimeout
348
     , pIgnoreSecondaries
349
     , pRebootType
350
     , pReason
351
     ])
352
  , ("OpInstanceMove",
353
     [ pInstanceName
354
     , pShutdownTimeout
355
     , pIgnoreIpolicy
356
     , pMoveTargetNode
357
     , pIgnoreConsistency
358
     ])
359
  , ("OpInstanceConsole",
360
     [ pInstanceName ])
361
  , ("OpInstanceActivateDisks",
362
     [ pInstanceName
363
     , pIgnoreDiskSize
364
     , pWaitForSyncFalse
365
     ])
366
  , ("OpInstanceDeactivateDisks",
367
     [ pInstanceName
368
     , pForce
369
     ])
370
  , ("OpInstanceRecreateDisks",
371
     [ pInstanceName
372
     , pRecreateDisksInfo
373
     , pNodes
374
     , pIallocator
375
     ])
376
  , ("OpInstanceQuery", dOldQuery)
377
  , ("OpInstanceQueryData",
378
     [ pUseLocking
379
     , pInstances
380
     , pStatic
381
     ])
382
  , ("OpInstanceSetParams",
383
     [ pInstanceName
384
     , pForce
385
     , pForceVariant
386
     , pIgnoreIpolicy
387
     , pInstParamsNicChanges
388
     , pInstParamsDiskChanges
389
     , pInstBeParams
390
     , pRuntimeMem
391
     , pInstHvParams
392
     , pOptDiskTemplate
393
     , pPrimaryNode
394
     , pRemoteNode
395
     , pOsNameChange
396
     , pInstOsParams
397
     , pWaitForSync
398
     , pOffline
399
     , pIpConflictsCheck
400
     ])
401
  , ("OpInstanceGrowDisk",
402
     [ pInstanceName
403
     , pWaitForSync
404
     , pDiskIndex
405
     , pDiskChgAmount
406
     , pDiskChgAbsolute
407
     ])
408
  , ("OpInstanceChangeGroup",
409
     [ pInstanceName
410
     , pEarlyRelease
411
     , pIallocator
412
     , pTargetGroups
413
     ])
414
  , ("OpGroupAdd",
415
     [ pGroupName
416
     , pNodeGroupAllocPolicy
417
     , pGroupNodeParams
418
     , pDiskParams
419
     , pHvState
420
     , pDiskState
421
     , pIpolicy
422
     ])
423
  , ("OpGroupAssignNodes",
424
     [ pGroupName
425
     , pForce
426
     , pRequiredNodes
427
     ])
428
  , ("OpGroupQuery", dOldQueryNoLocking)
429
  , ("OpGroupSetParams",
430
     [ pGroupName
431
     , pNodeGroupAllocPolicy
432
     , pGroupNodeParams
433
     , pDiskParams
434
     , pHvState
435
     , pDiskState
436
     , pIpolicy
437
     ])
438
  , ("OpGroupRemove",
439
     [ pGroupName ])
440
  , ("OpGroupRename",
441
     [ pGroupName
442
     , pNewName
443
     ])
444
  , ("OpGroupEvacuate",
445
     [ pGroupName
446
     , pEarlyRelease
447
     , pIallocator
448
     , pTargetGroups
449
     ])
450
  , ("OpOsDiagnose",
451
     [ pOutputFields
452
     , pNames ])
453
  , ("OpExtStorageDiagnose",
454
     [ pOutputFields
455
     , pNames ])
456
  , ("OpBackupQuery",
457
     [ pUseLocking
458
     , pNodes
459
     ])
460
  , ("OpBackupPrepare",
461
     [ pInstanceName
462
     , pExportMode
463
     ])
464
  , ("OpBackupExport",
465
     [ pInstanceName
466
     , pShutdownTimeout
467
     , pExportTargetNode
468
     , pShutdownInstance
469
     , pRemoveInstance
470
     , pIgnoreRemoveFailures
471
     , pExportMode
472
     , pX509KeyName
473
     , pX509DestCA
474
     ])
475
  , ("OpBackupRemove",
476
     [ pInstanceName ])
477
  , ("OpTestAllocator",
478
     [ pIAllocatorDirection
479
     , pIAllocatorMode
480
     , pIAllocatorReqName
481
     , pIAllocatorNics
482
     , pIAllocatorDisks
483
     , pHypervisor
484
     , pIallocator
485
     , pInstTags
486
     , pIAllocatorMemory
487
     , pIAllocatorVCpus
488
     , pIAllocatorOs
489
     , pDiskTemplate
490
     , pIAllocatorInstances
491
     , pIAllocatorEvacMode
492
     , pTargetGroups
493
     , pIAllocatorSpindleUse
494
     , pIAllocatorCount
495
     ])
496
  , ("OpTestJqueue",
497
     [ pJQueueNotifyWaitLock
498
     , pJQueueNotifyExec
499
     , pJQueueLogMessages
500
     , pJQueueFail
501
     ])
502
  , ("OpTestDummy",
503
     [ pTestDummyResult
504
     , pTestDummyMessages
505
     , pTestDummyFail
506
     , pTestDummySubmitJobs
507
     ])
508
  , ("OpNetworkAdd",
509
     [ pNetworkName
510
     , pNetworkAddress4
511
     , pNetworkGateway4
512
     , pNetworkAddress6
513
     , pNetworkGateway6
514
     , pNetworkMacPrefix
515
     , pNetworkAddRsvdIps
516
     , pIpConflictsCheck
517
     , pInstTags
518
     ])
519
  , ("OpNetworkRemove",
520
     [ pNetworkName
521
     , pForce
522
     ])
523
  , ("OpNetworkSetParams",
524
     [ pNetworkName
525
     , pNetworkGateway4
526
     , pNetworkAddress6
527
     , pNetworkGateway6
528
     , pNetworkMacPrefix
529
     , pNetworkAddRsvdIps
530
     , pNetworkRemoveRsvdIps
531
     ])
532
  , ("OpNetworkConnect",
533
     [ pGroupName
534
     , pNetworkName
535
     , pNetworkMode
536
     , pNetworkLink
537
     , pIpConflictsCheck
538
     ])
539
  , ("OpNetworkDisconnect",
540
     [ pGroupName
541
     , pNetworkName
542
     ])
543
  , ("OpNetworkQuery", dOldQuery)
544
  , ("OpRestrictedCommand",
545
     [ pUseLocking
546
     , pRequiredNodes
547
     , pRestrictedCommand
548
     ])
549
  ])
550

    
551
-- | Returns the OP_ID for a given opcode value.
552
$(genOpID ''OpCode "opID")
553

    
554
-- | A list of all defined/supported opcode IDs.
555
$(genAllOpIDs ''OpCode "allOpIDs")
556

    
557
instance JSON OpCode where
558
  readJSON = loadOpCode
559
  showJSON = saveOpCode
560

    
561
-- | Generates the summary value for an opcode.
562
opSummaryVal :: OpCode -> Maybe String
563
opSummaryVal OpClusterVerifyGroup { opGroupName = s } = Just (fromNonEmpty s)
564
opSummaryVal OpGroupVerifyDisks { opGroupName = s } = Just (fromNonEmpty s)
565
opSummaryVal OpClusterRename { opName = s } = Just (fromNonEmpty s)
566
opSummaryVal OpQuery { opWhat = s } = Just (queryTypeOpToRaw s)
567
opSummaryVal OpQueryFields { opWhat = s } = Just (queryTypeOpToRaw s)
568
opSummaryVal OpNodeRemove { opNodeName = s } = Just (fromNonEmpty s)
569
opSummaryVal OpNodeAdd { opNodeName = s } = Just (fromNonEmpty s)
570
opSummaryVal OpNodeModifyStorage { opNodeName = s } = Just (fromNonEmpty s)
571
opSummaryVal OpRepairNodeStorage  { opNodeName = s } = Just (fromNonEmpty s)
572
opSummaryVal OpNodeSetParams { opNodeName = s } = Just (fromNonEmpty s)
573
opSummaryVal OpNodePowercycle { opNodeName = s } = Just (fromNonEmpty s)
574
opSummaryVal OpNodeMigrate { opNodeName = s } = Just (fromNonEmpty s)
575
opSummaryVal OpNodeEvacuate { opNodeName = s } = Just (fromNonEmpty s)
576
opSummaryVal OpInstanceCreate { opInstanceName = s } = Just s
577
opSummaryVal OpInstanceReinstall { opInstanceName = s } = Just s
578
opSummaryVal OpInstanceRemove { opInstanceName = s } = Just s
579
-- FIXME: instance rename should show both names; currently it shows none
580
-- opSummaryVal OpInstanceRename { opInstanceName = s } = Just s
581
opSummaryVal OpInstanceStartup { opInstanceName = s } = Just s
582
opSummaryVal OpInstanceShutdown { opInstanceName = s } = Just s
583
opSummaryVal OpInstanceReboot { opInstanceName = s } = Just s
584
opSummaryVal OpInstanceReplaceDisks { opInstanceName = s } = Just s
585
opSummaryVal OpInstanceFailover { opInstanceName = s } = Just s
586
opSummaryVal OpInstanceMigrate { opInstanceName = s } = Just s
587
opSummaryVal OpInstanceMove { opInstanceName = s } = Just s
588
opSummaryVal OpInstanceConsole { opInstanceName = s } = Just s
589
opSummaryVal OpInstanceActivateDisks { opInstanceName = s } = Just s
590
opSummaryVal OpInstanceDeactivateDisks { opInstanceName = s } = Just s
591
opSummaryVal OpInstanceRecreateDisks { opInstanceName = s } = Just s
592
opSummaryVal OpInstanceSetParams { opInstanceName = s } = Just s
593
opSummaryVal OpInstanceGrowDisk { opInstanceName = s } = Just s
594
opSummaryVal OpInstanceChangeGroup { opInstanceName = s } = Just s
595
opSummaryVal OpGroupAdd { opGroupName = s } = Just (fromNonEmpty s)
596
opSummaryVal OpGroupAssignNodes { opGroupName = s } = Just (fromNonEmpty s)
597
opSummaryVal OpGroupSetParams { opGroupName = s } = Just (fromNonEmpty s)
598
opSummaryVal OpGroupRemove { opGroupName = s } = Just (fromNonEmpty s)
599
opSummaryVal OpGroupEvacuate { opGroupName = s } = Just (fromNonEmpty s)
600
opSummaryVal OpBackupPrepare { opInstanceName = s } = Just s
601
opSummaryVal OpBackupExport { opInstanceName = s } = Just s
602
opSummaryVal OpBackupRemove { opInstanceName = s } = Just s
603
opSummaryVal OpTagsGet { opKind = k } =
604
  Just . fromMaybe "None" $ tagNameOf k
605
opSummaryVal OpTagsSearch { opTagSearchPattern = s } = Just (fromNonEmpty s)
606
opSummaryVal OpTestDelay { opDelayDuration = d } = Just (show d)
607
opSummaryVal OpTestAllocator { opIallocator = s } =
608
  -- FIXME: Python doesn't handle None fields well, so we have behave the same
609
  Just $ maybe "None" fromNonEmpty s
610
opSummaryVal OpNetworkAdd { opNetworkName = s} = Just (fromNonEmpty s)
611
opSummaryVal OpNetworkRemove { opNetworkName = s} = Just (fromNonEmpty s)
612
opSummaryVal OpNetworkSetParams { opNetworkName = s} = Just (fromNonEmpty s)
613
opSummaryVal OpNetworkConnect { opNetworkName = s} = Just (fromNonEmpty s)
614
opSummaryVal OpNetworkDisconnect { opNetworkName = s} = Just (fromNonEmpty s)
615
opSummaryVal _ = Nothing
616

    
617
-- | Computes the summary of the opcode.
618
opSummary :: OpCode -> String
619
opSummary op =
620
  case opSummaryVal op of
621
    Nothing -> op_suffix
622
    Just s -> op_suffix ++ "(" ++ s ++ ")"
623
  where op_suffix = drop 3 $ opID op
624

    
625
-- | Generic\/common opcode parameters.
626
$(buildObject "CommonOpParams" "op"
627
  [ pDryRun
628
  , pDebugLevel
629
  , pOpPriority
630
  , pDependencies
631
  , pComment
632
  ])
633

    
634
-- | Default common parameter values.
635
defOpParams :: CommonOpParams
636
defOpParams =
637
  CommonOpParams { opDryRun     = Nothing
638
                 , opDebugLevel = Nothing
639
                 , opPriority   = OpPrioNormal
640
                 , opDepends    = Nothing
641
                 , opComment    = Nothing
642
                 }
643

    
644
-- | The top-level opcode type.
645
data MetaOpCode = MetaOpCode { metaParams :: CommonOpParams
646
                             , metaOpCode :: OpCode
647
                             } deriving (Show, Eq)
648

    
649
-- | JSON serialisation for 'MetaOpCode'.
650
showMeta :: MetaOpCode -> JSValue
651
showMeta (MetaOpCode params op) =
652
  let objparams = toDictCommonOpParams params
653
      objop = toDictOpCode op
654
  in makeObj (objparams ++ objop)
655

    
656
-- | JSON deserialisation for 'MetaOpCode'
657
readMeta :: JSValue -> Text.JSON.Result MetaOpCode
658
readMeta v = do
659
  meta <- readJSON v
660
  op <- readJSON v
661
  return $ MetaOpCode meta op
662

    
663
instance JSON MetaOpCode where
664
  showJSON = showMeta
665
  readJSON = readMeta
666

    
667
-- | Wraps an 'OpCode' with the default parameters to build a
668
-- 'MetaOpCode'.
669
wrapOpCode :: OpCode -> MetaOpCode
670
wrapOpCode = MetaOpCode defOpParams
671

    
672
-- | Sets the comment on a meta opcode.
673
setOpComment :: String -> MetaOpCode -> MetaOpCode
674
setOpComment comment (MetaOpCode common op) =
675
  MetaOpCode (common { opComment = Just comment}) op
676

    
677
-- | Sets the priority on a meta opcode.
678
setOpPriority :: OpSubmitPriority -> MetaOpCode -> MetaOpCode
679
setOpPriority prio (MetaOpCode common op) =
680
  MetaOpCode (common { opPriority = prio }) op