-
Notifications
You must be signed in to change notification settings - Fork 115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Origo] Adds support to mark storage-node/distrubtion-node under maintenance #4793
base: master
Are you sure you want to change the base?
Changes from 19 commits
8a10f93
bb0b5f5
407cdeb
ca8a495
e53f696
21bc807
a27f656
33997c4
b07bbec
d133ffb
ba24cfe
4860658
6ff4531
fc04793
b95ae04
4dd076f
b6329f7
172bcb7
16aaa48
73dc634
971aaae
0537ee7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
declare module 'inquirer-datepicker' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { | ||
INodeOperationalStatusMetadata, | ||
ISetNodeOperationalStatus, | ||
NodeOperationalStatusMetadata, | ||
SetNodeOperationalStatus, | ||
} from '@joystream/metadata-protobuf' | ||
import AccountsCommandBase from '../../command-base/accounts' | ||
import DefaultCommandBase, { flags } from '../../command-base/default' | ||
import { NODE_OPERATIONAL_STATUS_OPTIONS, NodeOperationalStatus } from '../../types/metadata' | ||
|
||
export default class LeadSetNodeOperationalStatus extends AccountsCommandBase { | ||
static description = `Set/update distribution node operational status. Requires distribution working group leader permissions.` | ||
|
||
static flags = { | ||
bucketId: flags.bucketId({ | ||
required: true, | ||
}), | ||
workerId: flags.integer({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggested that worker id is not needed in metadata. If we agree on that, then this workerId can be dropped. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please see #4793 (comment) |
||
char: 'w', | ||
description: 'ID of the operator (distribution group worker)', | ||
required: true, | ||
}), | ||
operationalStatus: flags.enum<NodeOperationalStatus>({ | ||
char: 'o', | ||
options: [...NODE_OPERATIONAL_STATUS_OPTIONS], | ||
required: false, | ||
description: 'Operational status of the operator', | ||
}), | ||
...DefaultCommandBase.flags, | ||
} | ||
|
||
async run(): Promise<void> { | ||
const { bucketId, workerId, operationalStatus: statusType } = this.parse(LeadSetNodeOperationalStatus).flags | ||
const leadKey = await this.getDistributorLeadKey() | ||
|
||
let operationalStatus: INodeOperationalStatusMetadata = {} | ||
switch (statusType) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It makes more sense to make it required, the command name doesn't imply what the default value should be. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Done |
||
case 'Normal': { | ||
operationalStatus = { status: NodeOperationalStatusMetadata.OperationalStatus.NORMAL } | ||
break | ||
} | ||
case 'NoService': { | ||
operationalStatus = { status: NodeOperationalStatusMetadata.OperationalStatus.NO_SERVICE } | ||
break | ||
} | ||
case 'NoServiceFrom': { | ||
operationalStatus = { | ||
status: NodeOperationalStatusMetadata.OperationalStatus.NO_SERVICE, | ||
noServiceFrom: (await this.datePrompt({ message: 'Enter No Service period start date' })).toISOString(), | ||
} | ||
break | ||
} | ||
case 'NoServiceDuring': { | ||
operationalStatus = { | ||
status: NodeOperationalStatusMetadata.OperationalStatus.NO_SERVICE, | ||
noServiceFrom: (await this.datePrompt({ message: 'Enter No Service period start date' })).toISOString(), | ||
noServiceTo: (await this.datePrompt({ message: 'Enter No Service period end date' })).toISOString(), | ||
} | ||
} | ||
} | ||
|
||
this.log(`Setting node operational status...`, { | ||
bucketId: bucketId.toHuman(), | ||
workerId, | ||
operationalStatus, | ||
}) | ||
|
||
const metadata: ISetNodeOperationalStatus = { | ||
workerId: workerId.toString(), | ||
bucketId: `${bucketId.distributionBucketFamilyId}:${bucketId.distributionBucketIndex}`, | ||
operationalStatus, | ||
} | ||
await this.sendAndFollowTx( | ||
await this.getDecodedPair(leadKey), | ||
this.api.tx.distributionWorkingGroup.leadRemark( | ||
'0x' + Buffer.from(SetNodeOperationalStatus.encode(metadata).finish()).toString('hex') | ||
) | ||
) | ||
this.log('Bucket operator metadata successfully set/updated!') | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,14 @@ | ||
import { | ||
DistributionBucketOperatorMetadata, | ||
IDistributionBucketOperatorMetadata, | ||
INodeOperationalStatusMetadata, | ||
NodeOperationalStatusMetadata, | ||
} from '@joystream/metadata-protobuf' | ||
import fs from 'fs' | ||
import AccountsCommandBase from '../../command-base/accounts' | ||
import DefaultCommandBase, { flags } from '../../command-base/default' | ||
import { ValidationService } from '../../services/validation/ValidationService' | ||
import { DistributionBucketOperatorMetadata, IDistributionBucketOperatorMetadata } from '@joystream/metadata-protobuf' | ||
import { NODE_OPERATIONAL_STATUS_OPTIONS, NodeOperationalStatus } from '../../types/metadata' | ||
|
||
export default class OperatorSetMetadata extends AccountsCommandBase { | ||
static description = `Set/update distribution bucket operator metadata. | ||
|
@@ -22,6 +28,12 @@ export default class OperatorSetMetadata extends AccountsCommandBase { | |
description: 'Root distribution node endpoint', | ||
exclusive: ['input'], | ||
}), | ||
operationalStatus: flags.enum<NodeOperationalStatus>({ | ||
char: 'o', | ||
options: [...NODE_OPERATIONAL_STATUS_OPTIONS], | ||
required: false, | ||
description: 'Operational status of the operator', | ||
}), | ||
input: flags.string({ | ||
char: 'i', | ||
description: 'Path to JSON metadata file', | ||
|
@@ -31,18 +43,60 @@ export default class OperatorSetMetadata extends AccountsCommandBase { | |
} | ||
|
||
async run(): Promise<void> { | ||
const { bucketId, workerId, input, endpoint } = this.parse(OperatorSetMetadata).flags | ||
const { bucketId, workerId, input, endpoint, operationalStatus: statusType } = this.parse(OperatorSetMetadata).flags | ||
const workerKey = await this.getDistributorWorkerRoleKey(workerId) | ||
|
||
let operationalStatus: INodeOperationalStatusMetadata = {} | ||
switch (statusType) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same question about default status here |
||
case 'Normal': { | ||
operationalStatus = { status: NodeOperationalStatusMetadata.OperationalStatus.NORMAL } | ||
break | ||
} | ||
case 'NoService': { | ||
operationalStatus = { status: NodeOperationalStatusMetadata.OperationalStatus.NO_SERVICE } | ||
break | ||
} | ||
case 'NoServiceFrom': { | ||
operationalStatus = { | ||
status: NodeOperationalStatusMetadata.OperationalStatus.NO_SERVICE, | ||
noServiceFrom: (await this.datePrompt({ message: 'Enter No Service period start date' })).toISOString(), | ||
} | ||
break | ||
} | ||
case 'NoServiceDuring': { | ||
operationalStatus = { | ||
status: NodeOperationalStatusMetadata.OperationalStatus.NO_SERVICE, | ||
noServiceFrom: (await this.datePrompt({ message: 'Enter No Service period start date' })).toISOString(), | ||
noServiceTo: (await this.datePrompt({ message: 'Enter No Service period end date' })).toISOString(), | ||
} | ||
} | ||
} | ||
|
||
const validation = new ValidationService() | ||
const metadata: IDistributionBucketOperatorMetadata = input | ||
? validation.validate('OperatorMetadata', JSON.parse(fs.readFileSync(input).toString())) | ||
: { endpoint } | ||
let metadata: IDistributionBucketOperatorMetadata | ||
if (input) { | ||
const params = validation.validate('OperatorMetadata', JSON.parse(fs.readFileSync(input).toString())) | ||
metadata = { | ||
...params, | ||
operationalStatus: params.operationalStatus | ||
? { | ||
...params.operationalStatus, | ||
status: | ||
params.operationalStatus?.status === 'Normal' | ||
? NodeOperationalStatusMetadata.OperationalStatus.NORMAL | ||
: NodeOperationalStatusMetadata.OperationalStatus.NO_SERVICE, | ||
} | ||
: {}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would this override the current status? Or skip the update? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should skip the update but previously it was overriding, I have fixed it |
||
} | ||
} else { | ||
metadata = { endpoint, operationalStatus } | ||
} | ||
|
||
this.log(`Setting bucket operator metadata...`, { | ||
bucketId: bucketId.toHuman(), | ||
workerId, | ||
metadata, | ||
operationalStatus, | ||
}) | ||
await this.sendAndFollowTx( | ||
await this.getDecodedPair(workerKey), | ||
|
@@ -52,6 +106,6 @@ export default class OperatorSetMetadata extends AccountsCommandBase { | |
'0x' + Buffer.from(DistributionBucketOperatorMetadata.encode(metadata).finish()).toString('hex') | ||
) | ||
) | ||
this.log('Bucket operator metadata succesfully set/updated!') | ||
this.log('Bucket operator metadata successfully set/updated!') | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -93,7 +93,7 @@ query getDistributionBucketsWithBagsByIds($ids: [String!]) { | |
} | ||
} | ||
|
||
query getDistributionBucketsWithBagsByWorkerId($workerId: Int!) { | ||
query getDistributionBucketsWithBagsByWorkerId($workerId: BigInt!) { | ||
distributionBuckets(where: { operators_some: { workerId_eq: $workerId, status_eq: ACTIVE } }) { | ||
...DistributionBucketWithBags | ||
} | ||
|
@@ -107,7 +107,17 @@ fragment StorageBucketOperatorFields on StorageBucket { | |
} | ||
|
||
query getActiveStorageBucketOperatorsData { | ||
storageBuckets(where: { operatorStatus: { isTypeOf_eq: "StorageBucketOperatorStatusActive" } }) { | ||
storageBuckets( | ||
where: { | ||
operatorStatus: { isTypeOf_eq: "StorageBucketOperatorStatusActive" } | ||
operatorMetadata: { | ||
OR: [ | ||
{ nodeOperationalStatus_isNull: true } | ||
{ nodeOperationalStatus: { isTypeOf_eq: "NodeOperationalStatusNormal" } } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This filter would skip any nodes with future maintenance as well. We probably should get all the operators and later only filter those that are under maintenance currently There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in 0537ee7 |
||
] | ||
} | ||
} | ||
) { | ||
...StorageBucketOperatorFields | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried the date picker, works really nicely in the terminal!
Perhaps a more reasonable default would be the current date
new Date().toISOString()
, so less fiddling with inital year and month for the user.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done