Skip to content

Commit

Permalink
chore(bors): merge pull request openebs#706
Browse files Browse the repository at this point in the history
706: Add/Remove label to/from node node r=sinhaashish a=sinhaashish

This PR will be used for the command
 1. `kubectl mayastor label node <nodeId> A=B` 
2.  `kubectl mayastor label node <nodeId> A-`

Co-authored-by: sinhaashish <[email protected]>
  • Loading branch information
mayastor-bors and sinhaashish committed Jan 26, 2024
2 parents b2ea4e1 + 3bef31a commit 4fd87bc
Show file tree
Hide file tree
Showing 22 changed files with 783 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::controller::{registry::Registry, resources::OperationGuardArc};
use agents::errors::SvcError;
use std::collections::HashMap;
use stor_port::types::v0::store::volume::VolumeSpec;

/// Resource Cordon Operations.
Expand All @@ -22,6 +23,27 @@ pub(crate) trait ResourceCordon {
) -> Result<Self::UncordonOutput, SvcError>;
}

/// Resource Label Operations.
#[async_trait::async_trait]
pub(crate) trait ResourceLabel {
type LabelOutput: Sync + Send + Sized;
type UnlabelOutput: Sync + Send + Sized;

/// Label the resource.
async fn label(
&mut self,
registry: &Registry,
label: HashMap<String, String>,
overwrite: bool,
) -> Result<Self::LabelOutput, SvcError>;
/// Remove label from the resource.
async fn unlabel(
&mut self,
registry: &Registry,
label: String,
) -> Result<Self::UnlabelOutput, SvcError>;
}

/// Resource Drain Operations.
#[async_trait::async_trait]
pub(crate) trait ResourceDrain {
Expand Down
45 changes: 44 additions & 1 deletion control-plane/agents/src/bin/core/node/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ use stor_port::types::v0::store::node::{DrainingVolumes, NodeOperation, NodeSpec
use crate::controller::{
registry::Registry,
resources::{
operations::{ResourceCordon, ResourceDrain},
operations::{ResourceCordon, ResourceDrain, ResourceLabel},
operations_helper::GuardedOperationsHelper,
OperationGuardArc,
},
};
use std::collections::HashMap;

/// Resource Cordon Operations.
#[async_trait::async_trait]
Expand Down Expand Up @@ -48,6 +49,48 @@ impl ResourceCordon for OperationGuardArc<NodeSpec> {
}
}

/// Resource Label Operations.
#[async_trait::async_trait]
impl ResourceLabel for OperationGuardArc<NodeSpec> {
type LabelOutput = NodeSpec;
type UnlabelOutput = NodeSpec;

/// Label a node via operation guard functions.
async fn label(
&mut self,
registry: &Registry,
label: HashMap<String, String>,
overwrite: bool,
) -> Result<Self::LabelOutput, SvcError> {
let cloned_node_spec = self.lock().clone();
let spec_clone = self
.start_update(
registry,
&cloned_node_spec,
NodeOperation::Label(label, overwrite),
)
.await?;

self.complete_update(registry, Ok(()), spec_clone).await?;
Ok(self.as_ref().clone())
}

/// Unlabel a node via operation guard functions.
async fn unlabel(
&mut self,
registry: &Registry,
label: String,
) -> Result<Self::UnlabelOutput, SvcError> {
let cloned_node_spec = self.lock().clone();
let spec_clone = self
.start_update(registry, &cloned_node_spec, NodeOperation::Unlabel(label))
.await?;

self.complete_update(registry, Ok(()), spec_clone).await?;
Ok(self.as_ref().clone())
}
}

/// Resource Drain Operations.
#[async_trait::async_trait]
impl ResourceDrain for OperationGuardArc<NodeSpec> {
Expand Down
46 changes: 45 additions & 1 deletion control-plane/agents/src/bin/core/node/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::controller::{
reconciler::PollTriggerEvent,
registry::Registry,
resources::{
operations::{ResourceCordon, ResourceDrain},
operations::{ResourceCordon, ResourceDrain, ResourceLabel},
operations_helper::ResourceSpecsLocked,
},
wrapper::NodeWrapper,
Expand Down Expand Up @@ -119,6 +119,29 @@ impl NodeOperations for Service {
let node = self.drain(id, label).await?;
Ok(node)
}

/// Apply the label to node.
async fn label(
&self,
id: NodeId,
label: HashMap<String, String>,
overwrite: bool,
) -> Result<Node, ReplyError> {
let node = self.label(id, label, overwrite).await?;
Ok(node)
}
/// Remove the specified label from the node.
async fn unlabel(&self, id: NodeId, label: String) -> Result<Node, ReplyError> {
if label.is_empty() {
return Err(SvcError::InvalidLabel {
labels: label,
resource_kind: ResourceKind::Node,
}
.into());
}
let node = self.unlabel(id, label).await?;
Ok(node)
}
}

#[tonic::async_trait]
Expand Down Expand Up @@ -375,4 +398,25 @@ impl Service {

Ok(Node::new(id, Some(spec), state))
}

/// Label the specified node.
async fn label(
&self,
id: NodeId,
label: HashMap<String, String>,
overwrite: bool,
) -> Result<Node, SvcError> {
let mut guarded_node = self.specs().guarded_node(&id).await?;
let spec = guarded_node.label(&self.registry, label, overwrite).await?;
let state = self.registry.node_state(&id).await.ok();
Ok(Node::new(id, Some(spec), state))
}

/// Remove the specified label from the specified node.
async fn unlabel(&self, id: NodeId, label: String) -> Result<Node, SvcError> {
let mut guarded_node = self.specs().guarded_node(&id).await?;
let spec = guarded_node.unlabel(&self.registry, label).await?;
let state = self.registry.node_state(&id).await.ok();
Ok(Node::new(id, Some(spec), state))
}
}
28 changes: 28 additions & 0 deletions control-plane/agents/src/bin/core/node/specs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,34 @@ impl SpecOperationsHelper for NodeSpec {
Ok(())
}
}
NodeOperation::Label(label, overwrite) => {
// Check that the label is present.
if !overwrite && self.has_labels_key(label.keys().collect()) {
Err(SvcError::LabelExists {
node_id: self.id().to_string(),
label: label
.into_iter()
.map(|(key, value)| format!("{key}: {value}"))
.collect::<Vec<String>>()
.join(", "),
})
} else {
self.start_op(op);
Ok(())
}
}
NodeOperation::Unlabel(label) => {
// Check that the label is present.
if !self.has_labels_key(vec![&label]) {
Err(SvcError::LabelNotFound {
node_id: self.id().to_string(),
label,
})
} else {
self.start_op(op);
Ok(())
}
}
_ => {
self.start_op(op);
Ok(())
Expand Down
29 changes: 29 additions & 0 deletions control-plane/agents/src/common/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ pub enum SvcError {
NoNodes {},
#[snafu(display("Node {} is cordoned", node_id))]
CordonedNode { node_id: String },
#[snafu(display("Node {} is already labelled with label '{}'", node_id, label))]
LabelExists { node_id: String, label: String },
#[snafu(display("Node {} doesn't have the label '{}'", node_id, label))]
LabelNotFound { node_id: String, label: String },
#[snafu(display("Node {} is already cordoned with label '{}'", node_id, label))]
CordonLabel { node_id: String, label: String },
#[snafu(display("Node {} does not have a cordon label '{}'", node_id, label))]
Expand Down Expand Up @@ -181,6 +185,11 @@ pub enum SvcError {
Internal { details: String },
#[snafu(display("Invalid Arguments"))]
InvalidArguments {},
#[snafu(display("Invalid {}, labels: {} ", resource_kind, labels))]
InvalidLabel {
labels: String,
resource_kind: ResourceKind,
},
#[snafu(display("Multiple nexuses not supported"))]
MultipleNexuses {},
#[snafu(display("Storage Error: {}", source))]
Expand Down Expand Up @@ -545,6 +554,20 @@ impl From<SvcError> for ReplyError {
extra,
},

SvcError::LabelExists { .. } => ReplyError {
kind: ReplyErrorKind::AlreadyExists,
resource: ResourceKind::Node,
source,
extra,
},

SvcError::LabelNotFound { .. } => ReplyError {
kind: ReplyErrorKind::NotFound,
resource: ResourceKind::Node,
source,
extra,
},

SvcError::UncordonLabel { .. } => ReplyError {
kind: ReplyErrorKind::FailedPrecondition,
resource: ResourceKind::Node,
Expand Down Expand Up @@ -717,6 +740,12 @@ impl From<SvcError> for ReplyError {
source,
extra,
},
SvcError::InvalidLabel { resource_kind, .. } => ReplyError {
kind: ReplyErrorKind::InvalidArgument,
resource: resource_kind,
source,
extra,
},
SvcError::MultipleNexuses { .. } => ReplyError {
kind: ReplyErrorKind::InvalidArgument,
resource: ResourceKind::Unknown,
Expand Down
32 changes: 32 additions & 0 deletions control-plane/grpc/proto/v1/node/target_node.proto
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,43 @@ message DrainState {
repeated string drain_labels = 2;
}

message LabelNodeRequest {
// Node identification
string node_id = 1;
// Node label map
common.StringMapValue label = 2;
// Overwrite an existing key
bool overwrite = 3;
}

message LabelNodeReply {
oneof reply {
Node node = 1;
common.ReplyError error = 2;
}
}

message UnlabelNodeRequest {
// Node identification
string node_id = 1;
// Node cordon label
string label = 2;
}

message UnlabelNodeReply {
oneof reply {
Node node = 1;
common.ReplyError error = 2;
}
}

service NodeGrpc {
rpc GetNodes (GetNodesRequest) returns (GetNodesReply) {}
rpc GetBlockDevices (blockdevice.GetBlockDevicesRequest) returns (blockdevice.GetBlockDevicesReply) {}
rpc Probe (ProbeRequest) returns (ProbeResponse) {}
rpc CordonNode (CordonNodeRequest) returns (CordonNodeReply) {}
rpc UncordonNode (UncordonNodeRequest) returns (UncordonNodeReply) {}
rpc DrainNode (DrainNodeRequest) returns (DrainNodeReply) {}
rpc LabelNode (LabelNodeRequest) returns (LabelNodeReply) {}
rpc UnlabelNode (UnlabelNodeRequest) returns (UnlabelNodeReply) {}
}
47 changes: 43 additions & 4 deletions control-plane/grpc/src/operations/node/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ use crate::{
common::NodeFilter,
context::{Client, Context, TracedChannel},
node::{
cordon_node_reply, drain_node_reply, get_nodes_reply, get_nodes_request,
node_grpc_client::NodeGrpcClient, uncordon_node_reply, CordonNodeRequest, DrainNodeRequest,
GetNodesRequest, ProbeRequest, UncordonNodeRequest,
cordon_node_reply, drain_node_reply, get_nodes_reply, get_nodes_request, label_node_reply,
node_grpc_client::NodeGrpcClient, uncordon_node_reply, unlabel_node_reply,
CordonNodeRequest, DrainNodeRequest, GetNodesRequest, LabelNodeRequest, ProbeRequest,
UncordonNodeRequest, UnlabelNodeRequest,
},
operations::node::traits::{GetBlockDeviceInfo, NodeOperations},
};
use std::{convert::TryFrom, ops::Deref};
use std::{collections::HashMap, convert::TryFrom, ops::Deref};
use stor_port::{
transport_api::{
v0::{BlockDevices, Nodes},
Expand Down Expand Up @@ -141,4 +142,42 @@ impl NodeOperations for NodeClient {
None => Err(ReplyError::invalid_response(ResourceKind::Node)),
}
}

#[tracing::instrument(name = "NodeClient::label", level = "debug", skip(self), err)]
async fn label(
&self,
id: NodeId,
label: HashMap<String, String>,
overwrite: bool,
) -> Result<Node, ReplyError> {
let req = LabelNodeRequest {
node_id: id.to_string(),
label: Some(crate::common::StringMapValue { value: label }),
overwrite,
};
let response = self.client().label_node(req).await?.into_inner();
match response.reply {
Some(label_node_reply) => match label_node_reply {
label_node_reply::Reply::Node(node) => Ok(Node::try_from(node)?),
label_node_reply::Reply::Error(err) => Err(err.into()),
},
None => Err(ReplyError::invalid_response(ResourceKind::Node)),
}
}

#[tracing::instrument(name = "NodeClient::unlabel", level = "debug", skip(self), err)]
async fn unlabel(&self, id: NodeId, label: String) -> Result<Node, ReplyError> {
let req = UnlabelNodeRequest {
node_id: id.to_string(),
label,
};
let response = self.client().unlabel_node(req).await?.into_inner();
match response.reply {
Some(unlabel_node_reply) => match unlabel_node_reply {
unlabel_node_reply::Reply::Node(node) => Ok(Node::try_from(node)?),
unlabel_node_reply::Reply::Error(err) => Err(err.into()),
},
None => Err(ReplyError::invalid_response(ResourceKind::Node)),
}
}
}
Loading

0 comments on commit 4fd87bc

Please sign in to comment.