Skip to content

Commit

Permalink
Issue #3814 - MultiNamespace: Agent should utilize IS_NAMESPACE_SCOPE…
Browse files Browse the repository at this point in the history
…D environment variable to indicate its scope when deploy the service

Signed-off-by: Le Zhang <zhangl@us.ibm.com>
  • Loading branch information
LiilyZhang committed Jun 26, 2023
1 parent 55abaa5 commit 8324a58
Show file tree
Hide file tree
Showing 17 changed files with 235 additions and 121 deletions.
2 changes: 1 addition & 1 deletion agreementbot/agreementworker.go
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ func (b *BaseAgreementWorker) InitiateNewAgreement(cph ConsumerProtocolHandler,
// for cluster type and check for namespace compatibility
consumerNamespace := ""
if nodeType == persistence.DEVICE_TYPE_CLUSTER {
t_comp, consumerNamespace, t_reason = compcheck.CheckClusterNamespaceCompatibility(nodeType, exchangeDev.ClusterNamespace, wi.ConsumerPolicy.ClusterNamespace, topSvcDef.GetClusterDeployment(), false, msgPrinter)
t_comp, consumerNamespace, t_reason = compcheck.CheckClusterNamespaceCompatibility(nodeType, exchangeDev.ClusterNamespace, exchangeDev.IsNamespaceScoped, wi.ConsumerPolicy.ClusterNamespace, topSvcDef.GetClusterDeployment(), wi.ConsumerPolicy.PatternId, false, msgPrinter)
if !t_comp {
glog.Warningf(BAWlogstring(workerId, fmt.Sprintf("cannot make agreement with node %v for service %v/%v %v. %v", wi.Device.Id, workload.Org, workload.WorkloadURL, workload.Version, t_reason)))
return
Expand Down
11 changes: 10 additions & 1 deletion api/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type HorizonDevice struct {
Name *string `json:"name,omitempty"`
NodeType *string `json:"nodeType,omitempty"`
ClusterNamespace *string `json:"clusterNamespace"`
NamespaceScoped *bool `json:"NamespaceScoped,omitempty"`
Token *string `json:"token,omitempty"`
TokenLastValidTime *uint64 `json:"token_last_valid_time,omitempty"`
TokenValid *bool `json:"token_valid,omitempty"`
Expand Down Expand Up @@ -69,6 +70,11 @@ func (h HorizonDevice) String() string {
clusterNs = *h.ClusterNamespace
}

isNS := false
if h.NamespaceScoped != nil {
isNS = *h.NamespaceScoped
}

ha_group := ""
if h.HAGroup != nil {
ha_group = *h.HAGroup
Expand All @@ -89,7 +95,7 @@ func (h HorizonDevice) String() string {
tv = *h.TokenValid
}

return fmt.Sprintf("Id: %v, Org: %v, Pattern: %v, Name: %v, NodeType: %v, ClusterNamespace: %v, HAGroup: %v, Token: [%v], TokenLastValidTime: %v, TokenValid: %v, %v", id, org, pat, name, nodeType, clusterNs, ha_group, cred, tlvt, tv, h.Config)
return fmt.Sprintf("Id: %v, Org: %v, Pattern: %v, Name: %v, NodeType: %v, ClusterNamespace: %v, NamespaceScoped: %v, HAGroup: %v, Token: [%v], TokenLastValidTime: %v, TokenValid: %v, %v", id, org, pat, name, nodeType, clusterNs, isNS, ha_group, cred, tlvt, tv, h.Config)
}

// This is a type conversion function but note that the token field within the persistent
Expand Down Expand Up @@ -121,6 +127,9 @@ func ConvertFromPersistentHorizonDevice(pDevice *persistence.ExchangeDevice) *Ho
if pDevice.NodeType == persistence.DEVICE_TYPE_CLUSTER {
ns := cutil.GetClusterNamespace()
hDevice.ClusterNamespace = &ns

isNS := cutil.IsNamespaceScoped()
hDevice.NamespaceScoped = &isNS
}

return &hDevice
Expand Down
8 changes: 8 additions & 0 deletions api/path_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,14 @@ func CreateHorizonDevice(device *HorizonDevice,
if err := patchDeviceHandler(deviceId, *device.Token, &pdr); err != nil {
return errorhandler(NewSystemError(fmt.Sprintf("error updating cluster namespace for the exchange node. %v", err))), nil, nil
}

pdr = exchange.PatchDeviceRequest{}
isNS := cutil.IsNamespaceScoped()
pdr.IsNamespaceScoped = &isNS
if err := patchDeviceHandler(deviceId, *device.Token, &pdr); err != nil {
return errorhandler(NewSystemError(fmt.Sprintf("error updating cluster agent scope for the exchange node. %v", err))), nil, nil
}

}

// Return 2 device objects, the first is the fully populated newly created device object. The second is a device
Expand Down
28 changes: 15 additions & 13 deletions api/path_node_configstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/open-horizon/anax/persistence"
"github.com/open-horizon/anax/policy"
"github.com/open-horizon/anax/semanticversion"
"os"
"strings"
)

Expand Down Expand Up @@ -358,17 +357,20 @@ func getSpecRefsForPattern(nodeType string, patName string,

glog.V(5).Infof(apiLogString(fmt.Sprintf("working with pattern definition %v", patternDef)))

nodeNamespace := os.Getenv("AGENT_NAMESPACE")
if nodeType == persistence.DEVICE_TYPE_CLUSTER {
if nodeNamespace == "" {
nodeNamespace = externalpolicy.DEFAULT_NODE_K8S_NAMESPACE
}
if nodeNamespace != externalpolicy.DEFAULT_NODE_K8S_NAMESPACE {
if patternDef.ClusterNamespace != "" && patternDef.ClusterNamespace != nodeNamespace {
return nil, nil, NewSystemError(fmt.Sprintf("Pattern cluster namespace is different from agent namespace. Cluster namespace in pattern is %v, agent namespace is %v", patternDef.ClusterNamespace, nodeNamespace))
}
}
}
// Uncomment this section after exchange add "isNamespaceScoped" field
// nodeNamespace := cutil.GetClusterNamespace()
// isNamespaceScoped := cutil.IsNamespaceScoped()

// if nodeType == persistence.DEVICE_TYPE_CLUSTER {
// if nodeNamespace == "" {
// nodeNamespace = externalpolicy.DEFAULT_NODE_K8S_NAMESPACE
// }
// if isNamespaceScoped {
// if patternDef.ClusterNamespace != "" && patternDef.ClusterNamespace != nodeNamespace {
// return nil, nil, NewSystemError(fmt.Sprintf("Pattern cluster namespace is different from agent namespace. Cluster namespace in pattern is %v, agent namespace is %v", patternDef.ClusterNamespace, nodeNamespace))
// }
// }
// }

// For each workload/top-level service in the pattern, resolve it to a list of required services.
// A pattern can have references to workloads or to services, but not a mixture of both.
Expand Down Expand Up @@ -416,7 +418,7 @@ func getSpecRefsForPattern(nodeType string, patName string,

if nodeType == persistence.DEVICE_TYPE_CLUSTER {
// Ignore service that has namespace conflict
if compatible, _, reason := compcheck.CheckClusterNamespaceCompatibility(nodeType, nodeNamespace, patternDef.ClusterNamespace, serviceDef.ClusterDeployment, true, nil); !compatible {
if compatible, _, reason := compcheck.CheckClusterNamespaceCompatibility(nodeType, cutil.GetClusterNamespace(), cutil.IsNamespaceScoped(), patternDef.ClusterNamespace, serviceDef.ClusterDeployment, patId, true, nil); !compatible {
// warning
glog.Infof(apiLogString(fmt.Sprintf("skipping service %v/%v because %v", service.ServiceOrg, service.ServiceURL, reason)))
continue
Expand Down
20 changes: 16 additions & 4 deletions cli/deploycheck/allcomp.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
)

// check if the policies are compatible
func AllCompatible(org string, userPw string, nodeIds []string, haGroupName string, nodeArch string, nodeType string, nodeNamespace string, nodeOrg string,
func AllCompatible(org string, userPw string, nodeIds []string, haGroupName string, nodeArch string, nodeType string, nodeNamespace string, nodeIsNamespaceScoped bool, nodeOrg string,
nodePolFile string, nodeUIFile string, businessPolId string, businessPolFile string,
patternId string, patternFile string, servicePolFile string, svcDefFiles []string,
checkAllSvcs bool, showDetail bool) {
Expand Down Expand Up @@ -59,6 +59,7 @@ func AllCompatible(org string, userPw string, nodeIds []string, haGroupName stri
compCheckInput.NodeArch = nodeArch
compCheckInput.NodeType = nodeType
compCheckInput.NodeClusterNS = nodeNamespace
compCheckInput.NodeNamespaceScoped = nodeIsNamespaceScoped
compCheckInput.NodeOrg = nodeOrg
compCheckInput.BusinessPolicy = bp
compCheckInput.PatternId = patternId
Expand Down Expand Up @@ -119,7 +120,7 @@ func AllCompatible(org string, userPw string, nodeIds []string, haGroupName stri

if bUseLocalNodeForPolicy || bUseLocalNodeForUI {
// get id from local node, check arch
compCheckInput.NodeId, compCheckInput.NodeArch, compCheckInput.NodeType, compCheckInput.NodeClusterNS, compCheckInput.NodeOrg = getLocalNodeInfo(nodeArch, nodeType, nodeNamespace, nodeOrg)
compCheckInput.NodeId, compCheckInput.NodeArch, compCheckInput.NodeType, compCheckInput.NodeClusterNS, compCheckInput.NodeNamespaceScoped, compCheckInput.NodeOrg = getLocalNodeInfo(nodeArch, nodeType, nodeNamespace, nodeIsNamespaceScoped, nodeOrg)
}

if nodeType == "" && compCheckInput.NodeId != "" {
Expand Down Expand Up @@ -325,7 +326,7 @@ func verifyCompCheckParameters(org string, userPw string,
}

// get node info and check node arch and org against the input arch
func getLocalNodeInfo(inputArch string, inputType string, inputNamespace string, inputOrg string) (string, string, string, string, string) {
func getLocalNodeInfo(inputArch string, inputType string, inputNamespace string, inputIsNamespaceScoped bool, inputOrg string) (string, string, string, string, bool, string) {
// get message printer
msgPrinter := i18n.GetMessagePrinter()

Expand All @@ -334,6 +335,7 @@ func getLocalNodeInfo(inputArch string, inputType string, inputNamespace string,
nodeOrg := ""
arch := cutil.ArchString()
namespace := ""
isNamespaceScoped := false

horDevice := api.HorizonDevice{}
cliutils.HorizonGet("node", []int{200}, &horDevice, false)
Expand All @@ -359,9 +361,14 @@ func getLocalNodeInfo(inputArch string, inputType string, inputNamespace string,
}

if nodeType == persistence.DEVICE_TYPE_CLUSTER && namespace == "" {
// should inspect the namespace by k8s library?
namespace = externalpolicy.DEFAULT_NODE_K8S_NAMESPACE
}

if horDevice.NamespaceScoped != nil {
isNamespaceScoped = *horDevice.NamespaceScoped
}

// check node architecture
if inputArch != "" && inputArch != arch {
cliutils.Fatal(cliutils.CLI_INPUT_ERROR, msgPrinter.Sprintf("The node architecture %v specified by -a does not match the architecture of the local node %v.", inputArch, arch))
Expand All @@ -377,12 +384,17 @@ func getLocalNodeInfo(inputArch string, inputType string, inputNamespace string,
cliutils.Fatal(cliutils.CLI_INPUT_ERROR, msgPrinter.Sprintf("The node cluster namespace %v specified by -s does not match the cluster namespace of the local node %v.", inputNamespace, namespace))
}

// check cluster agent scope
if inputIsNamespaceScoped != isNamespaceScoped {
cliutils.Fatal(cliutils.CLI_INPUT_ERROR, msgPrinter.Sprintf("The node is-namespace-scoped %v specified by --is-namespace-scoped does not match the agent scope of local node %v.", inputIsNamespaceScoped, isNamespaceScoped))
}

// check node organization
if inputOrg != "" && nodeOrg != "" && inputOrg != nodeOrg {
cliutils.Fatal(cliutils.CLI_INPUT_ERROR, msgPrinter.Sprintf("The node organization %v specified by -O does not match the organization of the local node %v.", inputType, nodeOrg))
}

return id, arch, nodeType, namespace, nodeOrg
return id, arch, nodeType, namespace, isNamespaceScoped, nodeOrg
}

// get business policy from exchange or from file.
Expand Down
5 changes: 3 additions & 2 deletions cli/deploycheck/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func readServicePolicyFile(filePath string, inputFileStruct *exchangecommon.Serv
}

// check if the policies are compatible
func PolicyCompatible(org string, userPw string, nodeIds []string, haGroupName string, nodeArch string, nodeType string, nodeNamespace string, nodePolFile string, businessPolId string, businessPolFile string, servicePolFile string, svcDefFiles []string, checkAllSvcs bool, showDetail bool) {
func PolicyCompatible(org string, userPw string, nodeIds []string, haGroupName string, nodeArch string, nodeType string, nodeNamespace string, nodeIsNamespaceScoped bool, nodePolFile string, businessPolId string, businessPolFile string, servicePolFile string, svcDefFiles []string, checkAllSvcs bool, showDetail bool) {

msgPrinter := i18n.GetMessagePrinter()

Expand Down Expand Up @@ -73,6 +73,7 @@ func PolicyCompatible(org string, userPw string, nodeIds []string, haGroupName s
policyCheckInput.NodeArch = nodeArch
policyCheckInput.NodeType = nodeType
policyCheckInput.NodeClusterNS = nodeNamespace
policyCheckInput.NodeNamespaceScoped = nodeIsNamespaceScoped
policyCheckInput.BusinessPolicy = bp

// formalize node id or get node policy
Expand All @@ -94,7 +95,7 @@ func PolicyCompatible(org string, userPw string, nodeIds []string, haGroupName s

if bUseLocalNode {
// get id from local node, check arch
policyCheckInput.NodeId, policyCheckInput.NodeArch, policyCheckInput.NodeType, policyCheckInput.NodeClusterNS, _ = getLocalNodeInfo(nodeArch, nodeType, nodeNamespace, "")
policyCheckInput.NodeId, policyCheckInput.NodeArch, policyCheckInput.NodeType, policyCheckInput.NodeClusterNS, policyCheckInput.NodeNamespaceScoped, _ = getLocalNodeInfo(nodeArch, nodeType, nodeNamespace, nodeIsNamespaceScoped, "")

// get node policy from local node
var np exchangecommon.NodePolicy
Expand Down
2 changes: 1 addition & 1 deletion cli/deploycheck/secretbinding.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func SecretBindingCompatible(org string, userPw string, nodeId string, nodeArch
msgPrinter.Println()

// get id from local node, check arch
sbCheckInput.NodeId, sbCheckInput.NodeArch, sbCheckInput.NodeType, _, sbCheckInput.NodeOrg = getLocalNodeInfo(nodeArch, nodeType, "", nodeOrg)
sbCheckInput.NodeId, sbCheckInput.NodeArch, sbCheckInput.NodeType, _, _, sbCheckInput.NodeOrg = getLocalNodeInfo(nodeArch, nodeType, "", false, nodeOrg)
}

// put the given service defs into the sbCheckInput
Expand Down
2 changes: 1 addition & 1 deletion cli/deploycheck/userinput.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func UserInputCompatible(org string, userPw string, nodeId string, nodeArch stri

if bUseLocalNode {
// get id from local node, check arch
uiCheckInput.NodeId, uiCheckInput.NodeArch, uiCheckInput.NodeType, _, _ = getLocalNodeInfo(nodeArch, nodeType, "", "")
uiCheckInput.NodeId, uiCheckInput.NodeArch, uiCheckInput.NodeType, _, _, _ = getLocalNodeInfo(nodeArch, nodeType, "", false, "")

// get node user input from local node
var node_ui []policy.UserInput
Expand Down
6 changes: 4 additions & 2 deletions cli/hzn.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ Environment Variables:
allCompNodeArch := allCompCmd.Flag("arch", msgPrinter.Sprintf("The architecture of the node. It is required when -n is not specified. If omitted, the service of all the architectures referenced in the deployment policy or pattern will be checked for compatibility.")).Short('a').String()
allCompNodeType := allCompCmd.Flag("node-type", msgPrinter.Sprintf("The node type. The valid values are 'device' and 'cluster'. The default value is the type of the node provided by -n or current registered device, if omitted.")).Short('t').String()
allCompNodeNs := allCompCmd.Flag("cluster-namespace", msgPrinter.Sprintf("The Kubernetes cluster namespace for the node if the node type is 'cluster'. The default value is 'openhorizon-agent', if omitted. The value is ignored when the node type is 'device'")).Short('s').String()
allCompNodIsNamespaceScoped := allCompCmd.Flag("is-namespace-scoped", msgPrinter.Sprintf("The cluster scope for the node is namespace scoped if the node type is 'cluster'. The default value is false, if omitted. The value is ignored when the node type is 'device'")).Bool()
allCompNodeOrg := allCompCmd.Flag("node-org", msgPrinter.Sprintf("The organization of the node. The default value is the organization of the node provided by -n or current registered device, if omitted.")).Short('O').String()
allCompNodeId := allCompCmd.Flag("node-id", msgPrinter.Sprintf("The Horizon exchange node ID. Mutually exclusive with --ha-group, --node-pol and --node-ui. If omitted, the node ID that the current device is registered with will be used. This flag can be repeated to specify more than one nodes. If you don't prepend a node id with the organization id, it will automatically be prepended with the -o value.")).Short('n').Strings()
allCompHAGroup := allCompCmd.Flag("ha-group", msgPrinter.Sprintf("The name of an HA group. The deployment check will be performed on all the nodes within the given HA group. Mutually exclusive with -n, --node-pol and --node-ui.")).String()
Expand All @@ -207,6 +208,7 @@ Environment Variables:
policyCompNodeArch := policyCompCmd.Flag("arch", msgPrinter.Sprintf("The architecture of the node. It is required when -n is not specified. If omitted, the service of all the architectures referenced in the deployment policy will be checked for compatibility.")).Short('a').String()
policyCompNodeType := policyCompCmd.Flag("node-type", msgPrinter.Sprintf("The node type. The valid values are 'device' and 'cluster'. The default value is the type of the node provided by -n or current registered device, if omitted.")).Short('t').String()
policyCompNodeNs := policyCompCmd.Flag("cluster-namespace", msgPrinter.Sprintf("The Kubernetes cluster namespace for the node if the node type is 'cluster'. The default value is 'openhorizon-agent', if omitted. The value is ignored when the node type is 'device'")).Short('s').String()
policyCompNodeIsNamespaceScoped := policyCompCmd.Flag("is-namespace-scoped", msgPrinter.Sprintf("The cluster scope for the node is namespace scoped if the node type is 'cluster'. The default value is false, if omitted. The value is ignored when the node type is 'device'")).Bool()
policyCompNodeId := policyCompCmd.Flag("node-id", msgPrinter.Sprintf("The Horizon exchange node ID. Mutually exclusive with --ha-group and --node-pol. If omitted, the node ID that the current device is registered with will be used. This flag can be repeated to specify more than one nodes. If you don't prepend a node id with the organization id, it will automatically be prepended with the -o value.")).Short('n').Strings()
policyCompHAGroup := policyCompCmd.Flag("ha-group", msgPrinter.Sprintf("The name of an HA group. The deployment check will be performed on all the nodes within the given HA group. Mutually exclusive with -n and --node-pol.")).String()
policyCompNodePolFile := policyCompCmd.Flag("node-pol", msgPrinter.Sprintf("The JSON input file name containing the node policy. Mutually exclusive with -n, --ha-group.")).String()
Expand Down Expand Up @@ -1353,13 +1355,13 @@ Environment Variables:
case policyRemoveCmd.FullCommand():
policy.Remove(*policyRemoveForce)
case policyCompCmd.FullCommand():
deploycheck.PolicyCompatible(*deploycheckOrg, *deploycheckUserPw, *policyCompNodeId, *policyCompHAGroup, *policyCompNodeArch, *policyCompNodeType, *policyCompNodeNs, *policyCompNodePolFile, *policyCompBPolId, *policyCompBPolFile, *policyCompSPolFile, *policyCompSvcFile, *deploycheckCheckAll, *deploycheckLong)
deploycheck.PolicyCompatible(*deploycheckOrg, *deploycheckUserPw, *policyCompNodeId, *policyCompHAGroup, *policyCompNodeArch, *policyCompNodeType, *policyCompNodeNs, *policyCompNodeIsNamespaceScoped, *policyCompNodePolFile, *policyCompBPolId, *policyCompBPolFile, *policyCompSPolFile, *policyCompSvcFile, *deploycheckCheckAll, *deploycheckLong)
case userinputCompCmd.FullCommand():
deploycheck.UserInputCompatible(*deploycheckOrg, *deploycheckUserPw, *userinputCompNodeId, *userinputCompNodeArch, *userinputCompNodeType, *userinputCompNodeUIFile, *userinputCompBPolId, *userinputCompBPolFile, *userinputCompPatternId, *userinputCompPatternFile, *userinputCompSvcFile, *deploycheckCheckAll, *deploycheckLong)
case secretCompCmd.FullCommand():
deploycheck.SecretBindingCompatible(*deploycheckOrg, *deploycheckUserPw, *secretCompNodeId, *secretCompNodeArch, *secretCompNodeType, *secretCompNodeOrg, *secretCompDepPolId, *secretCompDepPolFile, *secretCompPatternId, *secretCompPatternFile, *secretCompSvcFile, *deploycheckCheckAll, *deploycheckLong)
case allCompCmd.FullCommand():
deploycheck.AllCompatible(*deploycheckOrg, *deploycheckUserPw, *allCompNodeId, *allCompHAGroup, *allCompNodeArch, *allCompNodeType, *allCompNodeNs, *allCompNodeOrg, *allCompNodePolFile, *allCompNodeUIFile, *allCompBPolId, *allCompBPolFile, *allCompPatternId, *allCompPatternFile, *allCompSPolFile, *allCompSvcFile, *deploycheckCheckAll, *deploycheckLong)
deploycheck.AllCompatible(*deploycheckOrg, *deploycheckUserPw, *allCompNodeId, *allCompHAGroup, *allCompNodeArch, *allCompNodeType, *allCompNodeNs, *allCompNodIsNamespaceScoped, *allCompNodeOrg, *allCompNodePolFile, *allCompNodeUIFile, *allCompBPolId, *allCompBPolFile, *allCompPatternId, *allCompPatternFile, *allCompSPolFile, *allCompSvcFile, *deploycheckCheckAll, *deploycheckLong)
case agreementListCmd.FullCommand():
agreement.List(*listArchivedAgreements, *listAgreementId)
case agreementCancelCmd.FullCommand():
Expand Down
2 changes: 1 addition & 1 deletion cli/register/servicewait.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ func WaitForService(org string, waitService string, waitTimeout int, pattern str
msgPrinter.Println()
msgPrinter.Printf("Command output:")
msgPrinter.Println()
deploycheck.AllCompatible(userOrg, userPw, []string{}, "", nodeArch, nodeType, "", nodeOrg, "", "",
deploycheck.AllCompatible(userOrg, userPw, []string{}, "", nodeArch, nodeType, "", false, nodeOrg, "", "",
"", "", pattern, "", "", []string{}, false, false)
} else {
msgPrinter.Printf("Using the 'hzn deploycheck userinput -p' command to verify that node, service configuration and pattern are compatible.")
Expand Down
Loading

0 comments on commit 8324a58

Please sign in to comment.