diff --git a/doc/endpoints.md b/doc/endpoints.md index f94f66c7a..d8bd9241e 100644 --- a/doc/endpoints.md +++ b/doc/endpoints.md @@ -19,7 +19,7 @@ VolumeExpand | POST | /volumes/{volname}/expand | [VolExpandReq](https://godoc.o VolumeOptionGet | GET | /volumes/{volname}/options/{optname} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [VolumeOptionGetResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolumeOptionGetResp) VolumeOptionsGet | GET | /volumes/{volname}/options | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [VolumeOptionsGetResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolumeOptionsGetResp) VolumeOptions | POST | /volumes/{volname}/options | [VolOptionReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolOptionReq) | [VolumeOptionResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolumeOptionResp) -VolumeReset | DELETE | /volumes/{volname}/options | [VolOptionResetReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolOptionResetReq) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +VolumeReset | DELETE | /volumes/{volname}/options | [VolOptionResetReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolOptionResetReq) | [VolumeOptionResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolumeOptionResp) OptionGroupList | GET | /volumes/options-group | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [OptionGroupListResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#OptionGroupListResp) OptionGroupCreate | POST | /volumes/options-group | [OptionGroupReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#OptionGroupReq) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) OptionGroupDelete | DELETE | /volumes/options-group/{groupname} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) @@ -35,17 +35,17 @@ VolfilesGenerate | POST | /volfiles | [](https://godoc.org/github.com/gluster/gl VolfilesGet | GET | /volfiles | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) VolfilesGet | GET | /volfiles/{volfileid:.*} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) EditVolume | POST | /volumes/{volname}/edit | [VolEditReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolEditReq) | [VolumeEditResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolumeEditResp) -SnapshotCreate | POST | /snapshots | [SnapCreateReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#SnapCreateReq) | [SnapCreateResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#SnapCreateResp) -SnapshotActivate | POST | /snapshots/{snapname}/activate | [SnapActivateReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#SnapActivateReq) | [SnapActivateResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#SnapActivateResp) -SnapshotDeactivate | POST | /snapshots/{snapname}/deactivate | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [SnapshotDeactivateResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#SnapshotDeactivateResp) -SnapshotClone | POST | /snapshots/{snapname}/clone | [SnapCloneReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#SnapCloneReq) | [VolumeCreateResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#SnapshotCloneReq) -SnapshotRestore | POST | /snapshots/{snapname}/restore | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [VolumeInfo](https://godoc.org/github.com/gluster/glusterd2/pkg/api#VolumeInfo) -SnapshotInfo | GET | /snapshots/{snapname} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [SnapGetResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#SnapGetResp) -SnapshotListAll | GET | /snapshots | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [SnapListResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#SnapListResp) -SnapshotStatus | GET | /snapshots/{snapname}/status | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [SnapGetResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#SnapStatusResp) +SnapshotCreate | POST | /snapshots | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotActivate | POST | /snapshots/{snapname}/activate | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotDeactivate | POST | /snapshots/{snapname}/deactivate | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotClone | POST | /snapshots/{snapname}/clone | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotRestore | POST | /snapshots/{snapname}/restore | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotInfo | GET | /snapshots/{snapname} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotListAll | GET | /snapshots | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotStatus | GET | /snapshots/{snapname}/status | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) SnapshotDelete | DELETE | /snapshots/{snapname} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) SnapshotConfigGet | GET | /snapshots/config | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) -SnapshotConfigSet | POST | /snapshot/config | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +SnapshotConfigSet | POST | /snapshots/config | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) SnapshotConfigReset | DELETE | /snapshots/config | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) GetPeer | GET | /peers/{peerid} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [PeerGetResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#PeerGetResp) GetPeers | GET | /peers | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [PeerListResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#PeerListResp) @@ -54,42 +54,48 @@ AddPeer | POST | /peers | [PeerAddReq](https://godoc.org/github.com/gluster/glus EditPeer | POST | /peers/{peerid} | [PeerEditReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#PeerEditReq) | [PeerEditResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#PeerEditResp) SetGlobalOptions | POST | /cluster/options | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) GetGlobalOptions | GET | /cluster/options | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) -GeoReplicationCreate | POST | /geo-replication/{mastervolid}/{remotevolid} | [GeorepCreateReq](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepCreateReq) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepSession) -GeoReplicationStart | POST | /geo-replication/{mastervolid}/{remotevolid}/start | [GeorepCommandsReq](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepCommandsReq) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepSession) -GeoReplicationStop | POST | /geo-replication/{mastervolid}/{remotevolid}/stop | [GeorepCommandsReq](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepCommandsReq) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepSession) -GeoReplicationDelete | DELETE | /geo-replication/{mastervolid}/{remotevolid} | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#) -GeoReplicationPause | POST | /geo-replication/{mastervolid}/{remotevolid}/pause | [GeorepCommandsReq](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepCommandsReq) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepSession) -GeoReplicationResume | POST | /geo-replication/{mastervolid}/{remotevolid}/resume | [GeorepCommandsReq](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepCommandsReq) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepSession) -GeoReplicationStatus | GET | /geo-replication/{mastervolid}/{remotevolid} | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepSession) -GeoReplicationConfigGet | GET | /geo-replication/{mastervolid}/{remotevolid}/config | [GeorepOption](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepOption) | [GeorepOption](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepOption) -GeoReplicationConfigSet | POST | /geo-replication/{mastervolid}/{remotevolid}/config | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#) -GeoReplicationConfigReset | DELETE | /geo-replication/{mastervolid}/{remotevolid}/config | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#) -GeoReplicationStatusList | GET | /geo-replication | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepSession) -GeoReplicationSshKeyGenerate | POST | /ssh-key/{volname}/generate | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#) | [GeorepSSHPublicKey](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepSSHPublicKey) -GeoReplicationSshKeyPush | POST | /ssh-key/{volname}/push | [GeorepSSHPublicKey](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepSSHPublicKey) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#) -GeoReplicationSshKeyGet | GET | /ssh-key/{volname} | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#) | [GeorepSSHPublicKey](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api/#GeorepSSHPublicKey) -BitrotEnable | POST | /volumes/{volname}/bitrot/enable | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api/#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api/#) -BitrotDisable | POST | /volumes/{volname}/bitrot/disable | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api/#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api/#) -BitrotScrubOndemand | POST | /volumes/{volname}/bitrot/scrubondemand | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api/#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api/#) -BitrotScrubStatus | GET | /volumes/{volname}/bitrot/scrubstatus | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api/#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api/#) -QuotaList | GET | /quota/{volname}/limit | [](https://godoc.org/github.com/gluster/glusterd2/plugins/quota/api/#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/quota/api/#) -QuotaLimit | POST | /quota/{volname}/limit | [](https://godoc.org/github.com/gluster/glusterd2/plugins/quota/api/#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/quota/api/#) -QuotaRemove | DELETE | /quota/{volname}/limit | [](https://godoc.org/github.com/gluster/glusterd2/plugins/quota/api/#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/quota/api/#) -EventsWebhookAdd | POST | /events/webhook | [Webhook](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api/#Webhook) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api/#) -EventsWebhookTest | POST | /events/webhook/test | [Webhook](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api/#Webhook) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api/#) -EventsWebhookDelete | DELETE | /events/webhook | [WebhookDel](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api/#WebhookDel) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api/#) -EventsWebhookList | GET | /events/webhook | [](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api/#) | [WebhookList](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api/#WebhookList) -EventsList | GET | /events | [](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api/#) | [Event](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api/#Event) -SelfHealInfo | GET | /volumes/{volname}/{opts}/heal-info | [](https://godoc.org/github.com/gluster/glusterd2/plugins/glustershd/api/#) | [BrickHealInfo](https://godoc.org/github.com/gluster/glusterd2/plugins/glustershd/api/#BrickHealInfo) -SelfHealInfo2 | GET | /volumes/{volname}/heal-info | [](https://godoc.org/github.com/gluster/glusterd2/plugins/glustershd/api/#) | [BrickHealInfo](https://godoc.org/github.com/gluster/glusterd2/plugins/glustershd/api/#BrickHealInfo) -SelfHeal | POST | /volumes/{volname}/heal | [](https://godoc.org/github.com/gluster/glusterd2/plugins/glustershd/api/#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/glustershd/api/#) -DeviceAdd | POST | /devices/{peerid} | [AddDeviceReq](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api/#AddDeviceReq) | [AddDeviceResp](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api/#AddDeviceResp) -DeviceList | GET | /devices/{peerid} | [](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api/#) | [ListDeviceResp](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api/#ListDeviceResp) -DeviceEdit | POST | /devices/{peerid} | [EditDeviceReq](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api/#EditDeviceReq) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api/#) -DeviceListAll | GET | /devices | [](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api/#) | [ListDeviceResp](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api/#ListDeviceResp) -RebalanceStart | POST | /volumes/{volname}/rebalance/start | [StartReq](https://godoc.org/github.com/gluster/glusterd2/plugins/rebalance/api/#StartReq) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/rebalance/api/#) -RebalanceStop | POST | /volumes/{volname}/rebalance/stop | [](https://godoc.org/github.com/gluster/glusterd2/plugins/rebalance/api/#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/rebalance/api/#) -RebalanceStatus | GET | /volumes/{volname}/rebalance | [](https://godoc.org/github.com/gluster/glusterd2/plugins/rebalance/api/#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/rebalance/api/#) +LabelCreate | POST | /labels | [LabelCreateReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#LabelCreateReq) | [LabelCreateResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#LabelCreateResp) +LabelInfo | GET | /labels/{labelname} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [LabelGetResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#LabelGetResp) +LabelListAll | GET | /labels | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [LabelListResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#LabelListResp) +LabelDelete | DELETE | /labels/{labelname} | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) +LabelConfigSet | POST | /labels/{labelname}/config | [LabelSetReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#LabelSetReq) | [LabelConfigResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#LabelConfigResp) +LabelConfigReset | DELETE | /labels/{labelname}/config | [LabelResetReq](https://godoc.org/github.com/gluster/glusterd2/pkg/api#LabelResetReq) | [LabelConfigResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#LabelConfigResp) +GeoReplicationCreate | POST | /geo-replication/{mastervolid}/{remotevolid} | [GeorepCreateReq](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepCreateReq) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepSession) +GeoReplicationStart | POST | /geo-replication/{mastervolid}/{remotevolid}/start | [GeorepCommandsReq](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepCommandsReq) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepSession) +GeoReplicationStop | POST | /geo-replication/{mastervolid}/{remotevolid}/stop | [GeorepCommandsReq](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepCommandsReq) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepSession) +GeoReplicationDelete | DELETE | /geo-replication/{mastervolid}/{remotevolid} | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#) +GeoReplicationPause | POST | /geo-replication/{mastervolid}/{remotevolid}/pause | [GeorepCommandsReq](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepCommandsReq) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepSession) +GeoReplicationResume | POST | /geo-replication/{mastervolid}/{remotevolid}/resume | [GeorepCommandsReq](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepCommandsReq) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepSession) +GeoReplicationStatus | GET | /geo-replication/{mastervolid}/{remotevolid} | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepSession) +GeoReplicationConfigGet | GET | /geo-replication/{mastervolid}/{remotevolid}/config | [GeorepOption](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepOption) | [GeorepOption](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepOption) +GeoReplicationConfigSet | POST | /geo-replication/{mastervolid}/{remotevolid}/config | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#) +GeoReplicationConfigReset | DELETE | /geo-replication/{mastervolid}/{remotevolid}/config | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#) +GeoReplicationStatusList | GET | /geo-replication | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#) | [GeorepSession](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepSession) +GeoReplicationSshKeyGenerate | POST | /ssh-key/{volname}/generate | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#) | [GeorepSSHPublicKey](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepSSHPublicKey) +GeoReplicationSshKeyPush | POST | /ssh-key/{volname}/push | [GeorepSSHPublicKey](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepSSHPublicKey) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#) +GeoReplicationSshKeyGet | GET | /ssh-key/{volname} | [](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#) | [GeorepSSHPublicKey](https://godoc.org/github.com/gluster/glusterd2/plugins/georeplication/api#GeorepSSHPublicKey) +BitrotEnable | POST | /volumes/{volname}/bitrot/enable | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api#) +BitrotDisable | POST | /volumes/{volname}/bitrot/disable | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api#) +BitrotScrubOndemand | POST | /volumes/{volname}/bitrot/scrubondemand | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api#) +BitrotScrubStatus | GET | /volumes/{volname}/bitrot/scrubstatus | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/bitrot/api#) +QuotaList | GET | /quota/{volname}/limit | [](https://godoc.org/github.com/gluster/glusterd2/plugins/quota/api#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/quota/api#) +QuotaLimit | POST | /quota/{volname}/limit | [](https://godoc.org/github.com/gluster/glusterd2/plugins/quota/api#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/quota/api#) +QuotaRemove | DELETE | /quota/{volname}/limit | [](https://godoc.org/github.com/gluster/glusterd2/plugins/quota/api#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/quota/api#) +EventsWebhookAdd | POST | /events/webhook | [Webhook](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api#Webhook) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api#) +EventsWebhookTest | POST | /events/webhook/test | [Webhook](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api#Webhook) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api#) +EventsWebhookDelete | DELETE | /events/webhook | [WebhookDel](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api#WebhookDel) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api#) +EventsWebhookList | GET | /events/webhook | [](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api#) | [WebhookList](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api#WebhookList) +EventsList | GET | /events | [](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api#) | [Event](https://godoc.org/github.com/gluster/glusterd2/plugins/events/api#Event) +SelfHealInfo | GET | /volumes/{volname}/{opts}/heal-info | [](https://godoc.org/github.com/gluster/glusterd2/plugins/glustershd/api#) | [BrickHealInfo](https://godoc.org/github.com/gluster/glusterd2/plugins/glustershd/api#BrickHealInfo) +SelfHealInfo2 | GET | /volumes/{volname}/heal-info | [](https://godoc.org/github.com/gluster/glusterd2/plugins/glustershd/api#) | [BrickHealInfo](https://godoc.org/github.com/gluster/glusterd2/plugins/glustershd/api#BrickHealInfo) +SelfHeal | POST | /volumes/{volname}/heal | [](https://godoc.org/github.com/gluster/glusterd2/plugins/glustershd/api#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/glustershd/api#) +DeviceAdd | POST | /devices/{peerid} | [AddDeviceReq](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api#AddDeviceReq) | [AddDeviceResp](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api#AddDeviceResp) +DeviceList | GET | /devices/{peerid} | [](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api#) | [ListDeviceResp](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api#ListDeviceResp) +DeviceEdit | POST | /devices/{peerid} | [EditDeviceReq](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api#EditDeviceReq) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api#) +DeviceListAll | GET | /devices | [](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api#) | [ListDeviceResp](https://godoc.org/github.com/gluster/glusterd2/plugins/device/api#ListDeviceResp) +RebalanceStart | POST | /volumes/{volname}/rebalance/start | [StartReq](https://godoc.org/github.com/gluster/glusterd2/plugins/rebalance/api#StartReq) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/rebalance/api#) +RebalanceStop | POST | /volumes/{volname}/rebalance/stop | [](https://godoc.org/github.com/gluster/glusterd2/plugins/rebalance/api#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/rebalance/api#) +RebalanceStatus | GET | /volumes/{volname}/rebalance | [](https://godoc.org/github.com/gluster/glusterd2/plugins/rebalance/api#) | [](https://godoc.org/github.com/gluster/glusterd2/plugins/rebalance/api#) Statedump | GET | /statedump | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) List Endpoints | GET | /endpoints | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [ListEndpointsResp](https://godoc.org/github.com/gluster/glusterd2/pkg/api#ListEndpointsResp) Glusterd2 service status | GET | /ping | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) | [](https://godoc.org/github.com/gluster/glusterd2/pkg/api#) diff --git a/glusterd2/commands/command.go b/glusterd2/commands/command.go index 995d0b7be..7de3e70ec 100644 --- a/glusterd2/commands/command.go +++ b/glusterd2/commands/command.go @@ -3,6 +3,7 @@ package commands import ( "github.com/gluster/glusterd2/glusterd2/commands/global" + "github.com/gluster/glusterd2/glusterd2/commands/labels" "github.com/gluster/glusterd2/glusterd2/commands/peers" "github.com/gluster/glusterd2/glusterd2/commands/snapshot" "github.com/gluster/glusterd2/glusterd2/commands/version" @@ -25,4 +26,5 @@ var Commands = []Command{ &snapshotcommands.Command{}, &peercommands.Command{}, &globalcommands.Command{}, + &labelcommands.Command{}, } diff --git a/glusterd2/commands/labels/commands.go b/glusterd2/commands/labels/commands.go new file mode 100644 index 000000000..182fba387 --- /dev/null +++ b/glusterd2/commands/labels/commands.go @@ -0,0 +1,71 @@ +package labelcommands + +import ( + "github.com/gluster/glusterd2/glusterd2/servers/rest/route" + "github.com/gluster/glusterd2/pkg/api" + "github.com/gluster/glusterd2/pkg/utils" +) + +// Command is a structure which implements GlusterD Command interface +type Command struct { +} + +// Routes returns list of REST API routes to register with Glusterd +func (c *Command) Routes() route.Routes { + return route.Routes{ + route.Route{ + Name: "LabelCreate", + Method: "POST", + Pattern: "/labels", + Version: 1, + RequestType: utils.GetTypeString((*api.LabelCreateReq)(nil)), + ResponseType: utils.GetTypeString((*api.LabelCreateResp)(nil)), + HandlerFunc: labelCreateHandler}, + route.Route{ + Name: "LabelInfo", + Method: "GET", + Pattern: "/labels/{labelname}", + Version: 1, + ResponseType: utils.GetTypeString((*api.LabelGetResp)(nil)), + HandlerFunc: labelInfoHandler}, + route.Route{ + Name: "LabelListAll", + Method: "GET", + Pattern: "/labels", + Version: 1, + ResponseType: utils.GetTypeString((*api.LabelListResp)(nil)), + HandlerFunc: labelListHandler}, + route.Route{ + Name: "LabelDelete", + Method: "DELETE", + Pattern: "/labels/{labelname}", + Version: 1, + HandlerFunc: labelDeleteHandler}, + route.Route{ + Name: "LabelConfigSet", + Method: "POST", + Pattern: "/labels/{labelname}/config", + Version: 1, + RequestType: utils.GetTypeString((*api.LabelSetReq)(nil)), + ResponseType: utils.GetTypeString((*api.LabelConfigResp)(nil)), + HandlerFunc: labelConfigSetHandler}, + route.Route{ + Name: "LabelConfigReset", + Method: "DELETE", + Pattern: "/labels/{labelname}/config", + Version: 1, + RequestType: utils.GetTypeString((*api.LabelResetReq)(nil)), + ResponseType: utils.GetTypeString((*api.LabelConfigResp)(nil)), + HandlerFunc: labelConfigResetHandler}, + } +} + +// RegisterStepFuncs registers transaction step functions with +// Glusterd Transaction framework +func (c *Command) RegisterStepFuncs() { + registerLabelCreateStepFuncs() + registerLabelDeleteStepFuncs() + registerLabelConfigSetStepFuncs() + registerLabelConfigResetStepFuncs() + return +} diff --git a/glusterd2/commands/labels/label-create.go b/glusterd2/commands/labels/label-create.go new file mode 100644 index 000000000..ce7abc766 --- /dev/null +++ b/glusterd2/commands/labels/label-create.go @@ -0,0 +1,131 @@ +package labelcommands + +import ( + "errors" + "fmt" + "net/http" + + "github.com/gluster/glusterd2/glusterd2/gdctx" + "github.com/gluster/glusterd2/glusterd2/label" + restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils" + "github.com/gluster/glusterd2/glusterd2/transaction" + "github.com/gluster/glusterd2/pkg/api" + gderrors "github.com/gluster/glusterd2/pkg/errors" + + "github.com/pborman/uuid" +) + +const maxSnapCount = 256 + +func validateLabel(info *label.Info) error { + + if info.SnapMaxHardLimit > maxSnapCount { + return fmt.Errorf("Snap-max-hard-limit count cannot exceed more than %d", maxSnapCount) + } + if info.SnapMaxSoftLimit > info.SnapMaxHardLimit { + return errors.New("snap-soft-limit cannot exceed more than snap-max-hard-limit") + } + return nil +} + +func newLabelInfo(req *api.LabelCreateReq) *label.Info { + var labelInfo label.Info + + labelInfo.Name = req.Name + labelInfo.SnapMaxHardLimit = req.SnapMaxHardLimit + labelInfo.SnapMaxSoftLimit = req.SnapMaxSoftLimit + labelInfo.ActivateOnCreate = req.ActivateOnCreate + labelInfo.AutoDelete = req.AutoDelete + labelInfo.Description = req.Description + + return &labelInfo +} + +func storeLabel(c transaction.TxnCtx) error { + + var labelInfo label.Info + + if err := c.Get("label", &labelInfo); err != nil { + return err + } + if err := label.AddOrUpdateLabelFunc(&labelInfo); err != nil { + c.Logger().WithError(err).WithField( + "label", labelInfo.Name).Debug("storeLabel: failed to store label info") + return err + } + + return nil +} + +func registerLabelCreateStepFuncs() { + transaction.RegisterStepFunc(storeLabel, "label-create.Store") +} + +func labelCreateHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + logger := gdctx.GetReqLogger(ctx) + var req api.LabelCreateReq + + if err := restutils.UnmarshalRequest(r, &req); err != nil { + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, gderrors.ErrJSONParsingFailed) + return + } + if label.ExistsFunc(req.Name) { + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, gderrors.ErrLabelExists) + return + } + + /* + TODO : label name validation + */ + + labelInfo := newLabelInfo(&req) + if err := validateLabel(labelInfo); err != nil { + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, err) + return + } + + txn, err := transaction.NewTxnWithLocks(ctx, req.Name) + if err != nil { + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) + return + } + defer txn.Done() + + txn.Steps = []*transaction.Step{ + { + DoFunc: "label-create.Store", + Nodes: []uuid.UUID{gdctx.MyUUID}, + }, + } + + if err = txn.Ctx.Set("label", &labelInfo); err != nil { + logger.WithError(err).Error("failed to set request in transaction context") + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) + return + } + + if err = txn.Do(); err != nil { + logger.WithError(err).Error("label create transaction failed") + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) + return + } + + labelInfo, err = label.GetLabel(req.Name) + if err != nil { + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) + return + } + + txn.Ctx.Logger().WithField("LabelName", req.Name).Info("new label created") + + resp := createLabelCreateResp(labelInfo) + restutils.SetLocationHeader(r, w, labelInfo.Name) + restutils.SendHTTPResponse(ctx, w, http.StatusCreated, resp) +} + +func createLabelCreateResp(info *label.Info) *api.LabelCreateResp { + return (*api.LabelCreateResp)(label.CreateLabelInfoResp(info)) +} diff --git a/glusterd2/commands/labels/label-delete.go b/glusterd2/commands/labels/label-delete.go new file mode 100644 index 000000000..36d419d87 --- /dev/null +++ b/glusterd2/commands/labels/label-delete.go @@ -0,0 +1,83 @@ +package labelcommands + +import ( + "fmt" + "net/http" + + "github.com/gluster/glusterd2/glusterd2/gdctx" + "github.com/gluster/glusterd2/glusterd2/label" + restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils" + "github.com/gluster/glusterd2/glusterd2/transaction" + "github.com/gorilla/mux" + "github.com/pborman/uuid" +) + +func registerLabelDeleteStepFuncs() { + transaction.RegisterStepFunc(deleteLabel, "label-delete.Store") +} + +func deleteLabel(c transaction.TxnCtx) error { + + var labelInfo label.Info + if err := c.Get("labelinfo", &labelInfo); err != nil { + return err + } + + err := label.DeleteLabel(&labelInfo) + return err +} + +func labelDeleteHandler(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + logger := gdctx.GetReqLogger(ctx) + + labelname := mux.Vars(r)["labelname"] + labelInfo, err := label.GetLabel(labelname) + if err != nil { + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) + return + } + + txn, err := transaction.NewTxnWithLocks(ctx, labelname) + if err != nil { + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) + return + } + defer txn.Done() + + if labelname == (label.DefaultLabel).Name { + errMsg := "Default label cannot be deleted." + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, errMsg) + return + } + + if len(labelInfo.SnapList) > 0 { + errMsg := fmt.Sprintf("Cannot delete Label %s ,as it has %d snapshots tagged.", labelname, len(labelInfo.SnapList)) + restutils.SendHTTPError(ctx, w, http.StatusFailedDependency, errMsg) + return + } + txn.Steps = []*transaction.Step{ + { + DoFunc: "label-delete.Store", + Nodes: []uuid.UUID{gdctx.MyUUID}, + }, + } + + if err := txn.Ctx.Set("labelinfo", labelInfo); err != nil { + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) + return + } + + if err := txn.Do(); err != nil { + logger.WithError(err).WithField( + "label", labelname).Error("transaction to delete label failed") + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) + return + } + + logger.WithField("label-name", labelname).Info("label deleted") + restutils.SendHTTPResponse(ctx, w, http.StatusNoContent, nil) +} diff --git a/glusterd2/commands/labels/label-info.go b/glusterd2/commands/labels/label-info.go new file mode 100644 index 000000000..203ccacd8 --- /dev/null +++ b/glusterd2/commands/labels/label-info.go @@ -0,0 +1,30 @@ +package labelcommands + +import ( + "net/http" + + "github.com/gluster/glusterd2/glusterd2/label" + restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils" + "github.com/gluster/glusterd2/pkg/api" + "github.com/gorilla/mux" +) + +func labelInfoHandler(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + labelname := mux.Vars(r)["labelname"] + labelInfo, err := label.GetLabel(labelname) + if err != nil { + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) + return + } + + resp := createLabelGetResp(labelInfo) + restutils.SendHTTPResponse(ctx, w, http.StatusOK, resp) +} + +func createLabelGetResp(info *label.Info) *api.LabelGetResp { + return (*api.LabelGetResp)(label.CreateLabelInfoResp(info)) +} diff --git a/glusterd2/commands/labels/label-list.go b/glusterd2/commands/labels/label-list.go new file mode 100644 index 000000000..b43050aa8 --- /dev/null +++ b/glusterd2/commands/labels/label-list.go @@ -0,0 +1,34 @@ +package labelcommands + +import ( + "net/http" + + "github.com/gluster/glusterd2/glusterd2/label" + restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils" + "github.com/gluster/glusterd2/pkg/api" +) + +func labelListHandler(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + labelInfos, err := label.GetLabels() + if err != nil { + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) + return + } + + resp := createLabelListResp(labelInfos) + restutils.SendHTTPResponse(ctx, w, http.StatusOK, resp) +} + +func createLabelListResp(infos []*label.Info) *api.LabelListResp { + var resp = make(api.LabelListResp, len(infos)) + + for index, v := range infos { + resp[index] = *(createLabelGetResp(v)) + } + + return &resp +} diff --git a/glusterd2/commands/labels/label-reset.go b/glusterd2/commands/labels/label-reset.go new file mode 100644 index 000000000..398acae59 --- /dev/null +++ b/glusterd2/commands/labels/label-reset.go @@ -0,0 +1,112 @@ +package labelcommands + +import ( + "fmt" + "net/http" + + "github.com/gluster/glusterd2/glusterd2/gdctx" + "github.com/gluster/glusterd2/glusterd2/label" + restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils" + "github.com/gluster/glusterd2/glusterd2/transaction" + "github.com/gluster/glusterd2/pkg/api" + gderrors "github.com/gluster/glusterd2/pkg/errors" + "github.com/gorilla/mux" + + "github.com/pborman/uuid" +) + +func updateResetLabel(labelInfo *label.Info, req *api.LabelResetReq) (*label.Info, error) { + + for _, v := range req.Configurations { + switch label.Options(v) { + case label.SnapMaxHardLimitKey: + labelInfo.SnapMaxHardLimit = label.DefaultLabel.SnapMaxHardLimit + case label.SnapMaxSoftLimitKey: + labelInfo.SnapMaxSoftLimit = label.DefaultLabel.SnapMaxSoftLimit + case label.ActivateOnCreateKey: + labelInfo.ActivateOnCreate = label.DefaultLabel.ActivateOnCreate + case label.AutoDeleteKey: + labelInfo.AutoDelete = label.DefaultLabel.AutoDelete + default: + return labelInfo, fmt.Errorf("%s is not a comptable ioption", v) + + } + + } + return labelInfo, nil +} + +func registerLabelConfigResetStepFuncs() { + transaction.RegisterStepFunc(storeLabel, "label-config.Store") +} + +func labelConfigResetHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + logger := gdctx.GetReqLogger(ctx) + var req api.LabelResetReq + + if err := restutils.UnmarshalRequest(r, &req); err != nil { + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, gderrors.ErrJSONParsingFailed) + return + } + + labelname := mux.Vars(r)["labelname"] + + txn, err := transaction.NewTxnWithLocks(ctx, labelname) + if err != nil { + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) + return + } + defer txn.Done() + + labelInfo, err := label.GetLabel(labelname) + if err != nil { + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) + return + } + + labelInfo, err = updateResetLabel(labelInfo, &req) + if err != nil { + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, err) + return + } + + if err := validateLabel(labelInfo); err != nil { + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, err) + return + } + + txn.Steps = []*transaction.Step{ + { + DoFunc: "label-config.Store", + Nodes: []uuid.UUID{gdctx.MyUUID}, + }, + } + + if err = txn.Ctx.Set("label", &labelInfo); err != nil { + logger.WithError(err).Error("failed to set request in transaction context") + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) + return + } + + if err = txn.Do(); err != nil { + logger.WithError(err).Error("label config transaction failed") + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) + return + } + + labelInfo, err = label.GetLabel(labelname) + if err != nil { + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) + return + } + + txn.Ctx.Logger().WithField("LabelName", labelname).Info("label modfied") + + resp := createLabelConfigResp(labelInfo) + restutils.SetLocationHeader(r, w, labelInfo.Name) + restutils.SendHTTPResponse(ctx, w, http.StatusCreated, resp) +} diff --git a/glusterd2/commands/labels/label-set.go b/glusterd2/commands/labels/label-set.go new file mode 100644 index 000000000..0579e1a17 --- /dev/null +++ b/glusterd2/commands/labels/label-set.go @@ -0,0 +1,139 @@ +package labelcommands + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gluster/glusterd2/glusterd2/gdctx" + "github.com/gluster/glusterd2/glusterd2/label" + restutils "github.com/gluster/glusterd2/glusterd2/servers/rest/utils" + "github.com/gluster/glusterd2/glusterd2/transaction" + "github.com/gluster/glusterd2/pkg/api" + gderrors "github.com/gluster/glusterd2/pkg/errors" + "github.com/gorilla/mux" + + "github.com/pborman/uuid" +) + +func updateSetLabel(labelInfo *label.Info, req *api.LabelSetReq) (*label.Info, error) { + + for k, v := range req.Configurations { + switch label.Options(k) { + case label.SnapMaxHardLimitKey: + value, err := strconv.ParseUint(v, 10, 64) + if err != nil { + return labelInfo, fmt.Errorf("%s is not a comptable value for option %s", v, k) + } + labelInfo.SnapMaxHardLimit = value + case label.SnapMaxSoftLimitKey: + value, err := strconv.ParseUint(v, 10, 64) + if err != nil { + return labelInfo, fmt.Errorf("%s is not a comptable value for option %s", v, k) + } + labelInfo.SnapMaxSoftLimit = value + case label.ActivateOnCreateKey: + value, err := strconv.ParseBool(v) + if err != nil { + return labelInfo, fmt.Errorf("%s is not a comptable value for option %s", v, k) + } + labelInfo.ActivateOnCreate = value + case label.AutoDeleteKey: + value, err := strconv.ParseBool(v) + if err != nil { + return labelInfo, fmt.Errorf("%s is not a comptable value for option %s", v, k) + } + labelInfo.AutoDelete = value + default: + return labelInfo, fmt.Errorf("%s is not a comptable option %s", k) + + } + + } + return labelInfo, nil +} + +func registerLabelConfigSetStepFuncs() { + transaction.RegisterStepFunc(storeLabel, "label-config.Store") +} + +func labelConfigSetHandler(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + logger := gdctx.GetReqLogger(ctx) + var req api.LabelSetReq + + if err := restutils.UnmarshalRequest(r, &req); err != nil { + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, gderrors.ErrJSONParsingFailed) + return + } + + labelname := mux.Vars(r)["labelname"] + + txn, err := transaction.NewTxnWithLocks(ctx, labelname) + if err != nil { + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) + return + } + defer txn.Done() + + if labelname == (label.DefaultLabel).Name { + errMsg := "Default label cannot be edited." + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, errMsg) + return + } + + labelInfo, err := label.GetLabel(labelname) + if err != nil { + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) + return + } + + labelInfo, err = updateSetLabel(labelInfo, &req) + if err != nil { + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, err) + return + } + + if err := validateLabel(labelInfo); err != nil { + restutils.SendHTTPError(ctx, w, http.StatusBadRequest, err) + return + } + + txn.Steps = []*transaction.Step{ + { + DoFunc: "label-config.Store", + Nodes: []uuid.UUID{gdctx.MyUUID}, + }, + } + + if err = txn.Ctx.Set("label", labelInfo); err != nil { + logger.WithError(err).Error("failed to set request in transaction context") + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) + return + } + + if err = txn.Do(); err != nil { + logger.WithError(err).Error("label config transaction failed") + status, err := restutils.ErrToStatusCode(err) + restutils.SendHTTPError(ctx, w, status, err) + return + } + + labelInfo, err = label.GetLabel(labelname) + if err != nil { + restutils.SendHTTPError(ctx, w, http.StatusInternalServerError, err) + return + } + + txn.Ctx.Logger().WithField("LabelName", labelname).Info("label modfied") + + resp := createLabelConfigResp(labelInfo) + restutils.SetLocationHeader(r, w, labelInfo.Name) + restutils.SendHTTPResponse(ctx, w, http.StatusOK, resp) +} + +func createLabelConfigResp(info *label.Info) *api.LabelConfigResp { + return (*api.LabelConfigResp)(label.CreateLabelInfoResp(info)) +} diff --git a/glusterd2/label/store-utils.go b/glusterd2/label/store-utils.go new file mode 100644 index 000000000..1b8c100a6 --- /dev/null +++ b/glusterd2/label/store-utils.go @@ -0,0 +1,125 @@ +package label + +import ( + "context" + "encoding/json" + + gdstore "github.com/gluster/glusterd2/glusterd2/store" + gderror "github.com/gluster/glusterd2/pkg/errors" + + "github.com/coreos/etcd/clientv3" + log "github.com/sirupsen/logrus" +) + +const ( + labelPrefix string = "labels/" +) + +var ( + //ExistsFunc check whether a given label exist or not + ExistsFunc = Exists + // AddOrUpdateLabelFunc marshals to label object and passes to store to add/update + AddOrUpdateLabelFunc = AddOrUpdateLabel +) + +//Exists check whether a given label exist or not +func Exists(name string) bool { + if name == DefaultLabel.Name { + return true + } + + resp, e := gdstore.Get(context.TODO(), labelPrefix+name) + if e != nil { + return false + } + + return resp.Count == 1 +} + +//GetLabels retrives the json objects from the store and converts them into +//respective Info objects +func GetLabels() ([]*Info, error) { + resp, e := gdstore.Get(context.TODO(), labelPrefix, clientv3.WithPrefix()) + if e != nil { + return nil, e + } + + labels := make([]*Info, len(resp.Kvs)+1) + labels[0] = &DefaultLabel + + for i, kv := range resp.Kvs { + var label Info + + if err := json.Unmarshal(kv.Value, &label); err != nil { + log.WithError(err).WithField("Label", string(kv.Key)).Error("Failed to unmarshal label") + continue + } + + labels[i+1] = &label + } + + return labels, nil +} + +// AddOrUpdateLabel marshals to Label object and passes to store to add/update +func AddOrUpdateLabel(labelInfo *Info) error { + json, e := json.Marshal(labelInfo) + if e != nil { + log.WithError(e).Error("Failed to marshal the labelinfo object") + return e + } + + _, e = gdstore.Put(context.TODO(), GetStorePath(labelInfo), string(json)) + if e != nil { + log.WithError(e).Error("Couldn't add label to store") + return e + } + return nil +} + +// GetLabel fetches the json object from the store and unmarshalls it into +// Info object +func GetLabel(name string) (*Info, error) { + var labelinfo Info + + if name == DefaultLabel.Name { + labelinfo = DefaultLabel + return &labelinfo, nil + } + + resp, e := gdstore.Get(context.TODO(), labelPrefix+name) + if e != nil { + log.WithError(e).Error("Couldn't retrive volume from store") + return nil, e + } + + if resp.Count != 1 { + log.WithField("label", name).Error("label not found") + return nil, gderror.ErrLabelNotFound + } + + if e = json.Unmarshal(resp.Kvs[0].Value, &labelinfo); e != nil { + log.WithError(e).Error("Failed to unmarshal the data into labelinfo object") + return nil, e + } + return &labelinfo, nil +} + +//DeleteLabel passes the label path to store to delete the label object +func DeleteLabel(labelInfo *Info) error { + _, e := gdstore.Delete(context.TODO(), GetStorePath(labelInfo)) + if e != nil { + return e + } + + /* + TODO + Delete all object tagged to this label + */ + return e +} + +//GetStorePath return label path for etcd store +func GetStorePath(labelInfo *Info) string { + return labelPrefix + labelInfo.Name +} diff --git a/glusterd2/label/structs.go b/glusterd2/label/structs.go new file mode 100644 index 000000000..5e9bbd3c1 --- /dev/null +++ b/glusterd2/label/structs.go @@ -0,0 +1,37 @@ +//Package label that contains struct for label +package label + +//Options is used as key to set Label info values +type Options string + +const ( + //SnapMaxHardLimitKey is used to set the value SnapMaxHardLimit + SnapMaxHardLimitKey Options = "snap-max-hard-limit" + //SnapMaxSoftLimitKey is used to set the value SnapMaxSoftLimit + SnapMaxSoftLimitKey Options = "snap-max-soft-limit" + //ActivateOnCreateKey is used to set the value ActivateOnCreate + ActivateOnCreateKey Options = "activate-on-create" + //AutoDeleteKey is used to set the value AutoDelete + AutoDeleteKey Options = "auto-delete" +) + +//Info is used to represent a label +type Info struct { + Name string + SnapMaxHardLimit uint64 + SnapMaxSoftLimit uint64 + ActivateOnCreate bool + AutoDelete bool + Description string + SnapList []string +} + +//DefaultLabel contains default values for a label +var DefaultLabel = Info{ + ActivateOnCreate: false, + AutoDelete: false, + Description: "This is a default label", + Name: "defaultLabel", + SnapMaxHardLimit: 256, + SnapMaxSoftLimit: 230, +} diff --git a/glusterd2/label/utils.go b/glusterd2/label/utils.go new file mode 100644 index 000000000..6a1cc019f --- /dev/null +++ b/glusterd2/label/utils.go @@ -0,0 +1,20 @@ +package label + +import ( + "github.com/gluster/glusterd2/pkg/api" +) + +//CreateLabelInfoResp parses volume information for response +func CreateLabelInfoResp(info *Info) *api.LabelInfo { + + resp := &api.LabelInfo{ + Name: info.Name, + SnapMaxHardLimit: info.SnapMaxHardLimit, + SnapMaxSoftLimit: info.SnapMaxSoftLimit, + ActivateOnCreate: info.ActivateOnCreate, + AutoDelete: info.AutoDelete, + Description: info.Description, + SnapList: info.SnapList, + } + return resp +} diff --git a/glusterd2/servers/rest/utils/utils.go b/glusterd2/servers/rest/utils/utils.go index 8eea0e697..1100db675 100644 --- a/glusterd2/servers/rest/utils/utils.go +++ b/glusterd2/servers/rest/utils/utils.go @@ -100,6 +100,8 @@ func ErrToStatusCode(err error) (int, error) { statuscode = http.StatusNotFound case gderrors.ErrSnapNotFound: statuscode = http.StatusNotFound + case gderrors.ErrLabelNotFound: + statuscode = http.StatusNotFound case transaction.ErrLockTimeout: statuscode = http.StatusConflict default: diff --git a/pkg/api/labels_req.go b/pkg/api/labels_req.go new file mode 100644 index 000000000..7df355392 --- /dev/null +++ b/pkg/api/labels_req.go @@ -0,0 +1,21 @@ +package api + +// LabelCreateReq represents a lebel Create Request +type LabelCreateReq struct { + Name string `json:"labelname"` + SnapMaxHardLimit uint64 `json:"snap-max-hard-limit"` + SnapMaxSoftLimit uint64 `json:"snap-max-soft-limit"` + ActivateOnCreate bool `json:"activate-on-create,omitempty"` + AutoDelete bool `json:"auto-delete,omitempty"` + Description string `json:"description,omitempty"` +} + +// LabelSetReq represents a lebel Create Request +type LabelSetReq struct { + Configurations map[string]string `json:"configurations"` +} + +// LabelResetReq represents a lebel Create Request +type LabelResetReq struct { + Configurations []string `json:"configurations"` +} diff --git a/pkg/api/labels_resp.go b/pkg/api/labels_resp.go new file mode 100644 index 000000000..232433f48 --- /dev/null +++ b/pkg/api/labels_resp.go @@ -0,0 +1,24 @@ +package api + +// LabelInfo contains static information of a label +type LabelInfo struct { + Name string `json:"labelname"` + SnapMaxHardLimit uint64 `json:"snap-max-hard-limit"` + SnapMaxSoftLimit uint64 `json:"snap-max-soft-limit"` + ActivateOnCreate bool `json:"activate-on-create"` + AutoDelete bool `json:"auto-delete"` + Description string `json:"description"` + SnapList []string `json:"snap-list"` +} + +//LabelCreateResp is the response sent for a label get request. +type LabelCreateResp LabelInfo + +//LabelGetResp is the response sent for a label get request. +type LabelGetResp LabelInfo + +//LabelListResp is the response sent for a label list request. +type LabelListResp []LabelGetResp + +//LabelConfigResp is the response sent for a label config request. +type LabelConfigResp LabelInfo diff --git a/pkg/errors/error.go b/pkg/errors/error.go index 013084f1b..6c4d1a2bd 100644 --- a/pkg/errors/error.go +++ b/pkg/errors/error.go @@ -54,4 +54,6 @@ var ( ErrFetchingVolfileContent = errors.New("unable to fetch volfile content") ErrPidFileNotFound = errors.New("pid file not found") ErrInvalidSnapName = errors.New("invalid snapshot name") + ErrLabelNotFound = errors.New("label not found") + ErrLabelExists = errors.New("label already exists") )