# The hash %URIdef defines all the xCAT resources which can be access from Web Service.
# This script will be called when a https request with the URI started with /xcatws/ is sent to xCAT Web Service
# Inside this script:
# 1. The main body parses the URI and parameters
# 2. Base on the URI, go through the %URIdef to find the matched resource by the 'matcher' which is defined for each resource
# 3. Call the 'fhandler' which is defined in the resource to communicate with xcatd and get the xml response
# 3.1 The 'fhandler' generates the xml request base on the resource, parameters and http method 'GET|PUT|POST|DELETE', sends to xcatd and then get the xml response
# 4. Call the 'outhdler' which is defined in the resource to parse the xml response and translate it to JSON format
# 5. Output the http response to STDOUT
#
# Refer to the $URIdef{node}->{allnode} and $URIdef{node}->{nodeallattr} for your new created resource definition.
#
# |--node - Resource Group
# | `--allnode - Resource Name
# | `--desc - Description for the Resource
# | `--desc[1..10] - Additional description for the Resource
# | `--matcher - The matcher which is used to match the URI to the Resource
# | `--GET - The info is used to handle the GET request
# | `--desc - Description for the GET operation
# | `--desc[1..10] - Additional description for the GET operation
# | `--usage - Usage message. The format must be '|Parameters for the GET request|Returns for the GET request|'. The message in the '|' can be black, but the delimiter '|' must be kept.
# | `--example - Example message. The format must be '|Description|GET|URI PUT/POST_data|Return Msg|'. The messages in the four sections must be completed.
# | `--cmd - The xCAT command line coammnd which will be used to complete the request. It's not a must have attribute.
# | `--fhandler - The call back subroutine which is used to handle the GET request. Generally, it parses the parameters from request and then call xCAT command. This subroutine can be exclusive or shared.
# | `--outhdler - The call back subroutine which is used to handle the GET request. Generally, it parses the xml output from the 'fhandler' and then format the output to JSON. This subroutine can be exclusive or shared.
# | `--PUT - The info is used to handle the PUT request
# | `--POST - The info is used to handle the POST request
# | `--DELETE - The info is used to handle the DELETE request
# The common messages which can be used in the %URIdef
my %usagemsg = (
objreturn => "Json format: An object which includes multiple \'<name> : {att:value, attr:value ...}\' pairs.",
objchparam => "Json format: An object which includes multiple \'att:value\' pairs.",
non_getreturn => "No output when execution is successfull. Otherwise output the error information in the Standard Error Format: {error:[msg1,msg2...],errocode:errornum}."
);
my %URIdef = (
#### definition for node resources
nodes => {
allnode => {
desc => "[URI:/nodes] - The node list resource.",
desc1 => "This resource can be used to display all the nodes which have been defined in the xCAT database.",
matcher => '^/nodes$',
GET => {
desc => "Get all the nodes in xCAT.",
desc1 => "The attributes details for the node will not be displayed.",
usage => "||Json format: An array of node names.|",
example => "|Get all the node names from xCAT database.|GET|/nodes|[\n \"node1\",\n \"node2\",\n \"node3\",\n]|",
cmd => "lsdef",
fhandler => \&defhdl,
outhdler => \&defout_remove_appended_type,
}
},
nodeallattr => {
desc => "[URI:/nodes/{noderange}] - The node resource",
matcher => '^/nodes/[^/]*$',
GET => {
desc => "Get all the attibutes for the node {noderange}.",
example => "|Get all the attibutes for node \'node1\'.|GET|/nodes/node1|{\n \"node1\":{\n \"profile\":\"compute\",\n \"netboot\":\"xnba\",\n \"arch\":\"x86_64\",\n \"mgt\":\"ipmi\",\n \"groups\":\"all\",\n ...\n }\n}|",
cmd => "lsdef",
fhandler => \&defhdl,
outhdler => \&defout,
},
PUT => {
desc => "Change the attibutes for the node {noderange}.",
example => "|Create a node with attributes groups=all, mgt=dfm and netboot=yaboot|POST|/nodes/node1 {\"groups\":\"all\",\"mgt\":\"dfm\",\"netboot\":\"yaboot\"}||",
cmd => "mkdef",
fhandler => \&defhdl,
outhdler => \&noout,
},
DELETE => {
desc => "Remove the node {noderange}.",
usage => "||$usagemsg{non_getreturn}|",
example => "|Delete the node node1|DELETE|/nodes/node1||",
cmd => "rmdef",
fhandler => \&defhdl,
outhdler => \&noout,
},
},
nodeattr => {
desc => "[URI:/nodes/{noderange}/attrs/{attr1,attr2,attr3 ...}] - The attributes resource for the node {noderange}",
matcher => '^/nodes/[^/]*/attrs/\S+$',
GET => {
desc => "Get the specific attributes for the node {noderange}.",
example => "|Get the attributes {groups,mgt,netboot} for node node1|GET|/nodes/node1/attrs/groups,mgt,netboot|{\n \"node1\":{\n \"netboot\":\"xnba\",\n \"mgt\":\"ipmi\",\n \"groups\":\"all\"\n }\n}|",
cmd => "lsdef",
fhandler => \&defhdl,
outhdler => \&defout,
},
PUT_backup => {
desc => "Change attributes for the node {noderange}. DataBody: {attr1:v1,att2:v2,att3:v3 ...}.",
usage => "||An array of node objects.|",
example => "|Get the attributes {groups,mgt,netboot} for node node1|GET|/nodes/node1/attrs/groups;mgt;netboot||",
cmd => "chdef",
fhandler => \&defhdl,
outhdler => \&noout,
}
},
nodestat => {
desc => "[URI:/nodes/{noderange}/nodestat}] - The attributes resource for the node {noderange}",
matcher => '^/nodes/[^/]*/nodestat$',
GET => {
desc => "Get the running status for the node {noderange}.",
example => "|Change the power status to on|PUT|/nodes/node1/power {\"action\":\"on\"}||",
cmd => "rpower",
fhandler => \&actionhdl,
outhdler => \&noout,
}
},
energy => {
desc => "[URI:/nodes/{noderange}/energy] - The energy resource for the node {noderange}",
matcher => '^/nodes/[^/]*/energy$',
GET => {
desc => "Get all the energy status for the node {noderange}.",
usage => "||$usagemsg{objreturn}|",
example => "|Get all the energy attributes.|GET|/nodes/node1/energy|{\n \"node1\":{\n \"cappingmin\":\"272.3 W\",\n \"cappingmax\":\"354.0 W\"\n ...\n }\n}|",
cmd => "renergy",
fhandler => \&actionhdl,
outhdler => \&actionout,
},
PUT => {
desc => "Change energy attributes for the node {noderange}.",
example => "|Turn on the cappingstatus to [on]|PUT|/nodes/node1/energy {\"cappingstatus\":\"on\"}||",
cmd => "renergy",
fhandler => \&actionhdl,
outhdler => \&noout,
}
},
energyattr => {
disable => 1,
desc => "[URI:/nodes/{noderange}/energy/{cappingmaxmin,cappingstatus,cappingvalue ...}] - The specific energy attributes resource for the node {noderange}",
matcher => '^/nodes/[^/]*/energy/\S+$',
GET => {
desc => "Get the specific energy attributes cappingmaxmin,cappingstatus,cappingvalue ... for the node {noderange}.",
usage => "||$usagemsg{objreturn}|",
example => "|Get the energy attributes which are specified in the URI.|GET|/nodes/node1/energy/cappingmaxmin,cappingstatus|{\n \"node1\":{\n \"cappingmin\":\"272.3 W\",\n \"cappingmax\":\"354.0 W\"\n }\n}|",
cmd => "renergy",
fhandler => \&actionhdl,
outhdler => \&actionout,
},
PUT_backup => {
desc => "Change energy attributes for the node {noderange}. ",
example => "|Turn on the cappingstatus to [on]|PUT|/nodes/node1/energy {\"cappingstatus\":\"on\"}||",
cmd => "renergy",
fhandler => \&actionhdl,
outhdler => \&noout,
}
},
serviceprocessor => {
disable => 1,
desc => "[URI:/nodes/{noderange}/sp/{community|ip|netmask|...}] - The attribute resource of service processor for the node {noderange}",
matcher => '^/nodes/[^/]*/sp/\S+$',
GET => {
desc => "Get the specific attributes for service processor resource.",
usage => "||$usagemsg{objreturn}|",
example => "|Get the snmp community for the service processor of node1.|GET|/nodes/node1/sp/community|{\n \"node1\":{\n \"SP SNMP Community\":\"public\"\n }\n}|",
cmd => "rspconfig",
fhandler => \&actionhdl,
outhdler => \&actionout,
},
PUT => {
desc => "Change the specific attributes for the service processor resource. ",
example => "|Set the snmp community to [mycommunity].|PUT|/nodes/node1/sp/community {\"value\":\"mycommunity\"}||",
cmd => "rspconfig",
fhandler => \&actionhdl,
outhdler => \&noout,
}
},
macaddress => {
disable => 1,
desc => "[URI:/nodes/{noderange}/mac] - The mac address resource for the node {noderange}",
matcher => '^/nodes/[^/]*/mac$',
GET => {
desc => "Get the mac address for the node {noderange}. Generally, it also updates the mac attribute of the node.",
cmd => "getmacs",
fhandler => \&common,
},
},
nextboot => {
desc => "[URI:/nodes/{noderange}/nextboot] - The temporary bootorder resource in next boot for the node {noderange}",
matcher => '^/nodes/[^/]*/nextboot$',
GET => {
desc => "Get the next bootorder.",
usage => "||$usagemsg{objreturn}|",
example => "|Get the bootorder for the next boot. (It's only valid after setting.)|GET|/nodes/node1/nextboot|{\n \"node1\":{\n \"nextboot\":\"Network\"\n }\n}|",
desc => "[URI:/nodes/{noderange}/inventory/{pci|model...}] - The specific inventory attributes for the node {noderange}",
matcher => '^/nodes/[^/]*/inventory/\S+$',
GET => {
desc => "Get the specific inventory attibutes.",
usage => "||$usagemsg{objreturn}|",
example => "|Get the \'model\' inventory attribute for node1.|GET|/nodes/node1/inventory/model|{\n \"node1\":{\n \"System Description\":\"System x3650 M4\",\n \"System Model/MTM\":\"7915C2A\"\n }\n}|",
cmd => "rinv",
fhandler => \&actionhdl,
outhdler => \&actionout,
},
},
eventlog => {
desc => "[URI:/nodes/{noderange}/eventlog] - The eventlog resource for the node {noderange}",
matcher => '^/nodes/[^/]*/eventlog$',
GET => {
desc => "Get all the eventlog for the node {noderange}.",
usage => "||$usagemsg{objreturn}|",
example => "|Get all the eventlog for node1.|GET|/nodes/node1/eventlog|{\n \"node1\":{\n \"eventlog\":[\n \"03/19/2014 15:17:58 Event Logging Disabled, Log Area Reset/Cleared (SEL Fullness)\"\n ]\n }\n}|",
cmd => "reventlog",
fhandler => \&actionhdl,
outhdler => \&actionout,
},
DELETE => {
desc => "Clean up the event log for the node {noderange}.",
usage => "||$usagemsg{non_getreturn}|",
example => "|Delete all the event log for node1.|DELETE|/nodes/node1/eventlog|[\n {\n \"eventlog\":[\n \"SEL cleared\"\n ],\n \"name\":\"node1\"\n }\n]|",
cmd => "reventlog",
fhandler => \&actionhdl,
outhdler => \&noout,
},
},
beacon => {
desc => "[URI:/nodes/{noderange}/beacon] - The beacon resource for the node {noderange}",
matcher => '^/nodes/[^/]*/beacon$',
GET_backup => {
desc => "Get the beacon status for the node {noderange}.",
cmd => "rbeacon",
fhandler => \&common,
},
PUT => {
desc => "Change the beacon status for the node {noderange}.",
desc => "Change the configuration for the virtual machine {noderange}.",
usage => "|$usagemsg{objchparam} DataBody: \n Set memory size - {\"memorysize\":\"sizeofmemory(MB)\"}\n Add new disk - {\"adddisk\":\"sizeofdisk1(GB),sizeofdisk2(GB)\"}\n Purge disk - {\"purgedisk\":\"scsi_id1,scsi_id2\"}|$usagemsg{non_getreturn}|",
example => "|Set memory to 3000MB.|PUT|/nodes/node1/vm {\"memorysize\":\"3000\"}||",
example1 => "|Add a new 20G disk.|PUT|/nodes/node1/vm {\"adddisk\":\"20G\"}||",
example2 => "|Purge the disk \'hdb\'.|PUT|/nodes/node1/vm {\"purgedisk\":\"hdb\"}||",
cmd => "chvm",
fhandler => \&actionhdl,
outhdler => \&noout,
},
POST => {
desc => "Create the vm node {noderange}.",
usage => "|$usagemsg{objchparam} DataBody: \n Set CPU count - {\"cpucount\":\"numberofcpu\"}\n Set memory size - {\"memorysize\":\"sizeofmemory(MB)\"}\n Set disk size - {\"disksize\":\"sizeofdisk\"}\n Do it by force - {\"force\":\"yes\"}|$usagemsg{non_getreturn}|",
example => "|Create the vm node1 with a 30G disk, 2048M memory and 2 cpus.|POST|/nodes/node1/vm {\"disksize\":\"30G\",\"memorysize\":\"2048\",\"cpucount\":\"2\"}||",
desc => "[URI:/nodes/{noderange}/vmclone] - The clone resource for the virtual node {noderange}.",
desc1 => "The node should be a virtual machine of kvm, esxi ...",
matcher => '^/nodes/[^/]*/vmclone$',
POST => {
desc => "Create a clone master from node {noderange}. Or clone the node {noderange} from a clone master.",
usage => "|$usagemsg{objchparam} DataBody: \n Clone a master named \"mastername\" - {\"tomaster\":\"mastername\"}\n Clone a node from master \"mastername\" - {\"frommaster\":\"mastername\"}\n Use Detach mode - {\"detach\":\"yes\"}\n Do it by force - {\"force\":\"yes\"}|The messages of creating Clone target.|",
example1 => "|Create a clone master named \"vmmaster\" from the node1.|POST|/nodes/node1/vmclone {\"tomaster\":\"vmmaster\",\"detach\":\"yes\"}|{\n \"node1\":{\n \"vmclone\":\"Cloning of node1.hda.qcow2 complete (clone uses 9633.19921875 for a disk size of 30720MB)\"\n }\n}|",
example2 => "|Clone the node1 from the clone master named \"vmmaster\".|POST|/nodes/node1/vmclone {\"frommaster\":\"vmmaster\"}||",
cmd => "clonevm",
fhandler => \&actionhdl,
outhdler => \&actionout,
},
},
vmmigrate => {
desc => "[URI:/nodes/{noderange}/vmmigrate] - The virtualization resource for migration.",
desc1 => "The node should be a virtual machine of kvm, esxi ...",
desc => "[URI:/nodes/{noderange}/updating] - The updating resource for the node {noderange}",
matcher => '^/nodes/[^/]*/updating$',
POST => {
desc => "Update the node with file syncing, software maintenance and rerun postscripts.",
usage => "||An array of messages for performing the node updating.|",
example => "|Initiate an updatenode process.|POST|/nodes/node2/updating|[\n \"There were no syncfiles defined to process. File synchronization has completed.\",\n \"Performing software maintenance operations. This could take a while, if there are packages to install.\n\",\n \"node2: Wed Mar 20 15:01:43 CST 2013 Running postscript: ospkgs\",\n \"node2: Running of postscripts has completed.\"\n]|",
cmd => "updatenode",
fhandler => \&actionhdl,
outhdler => \&infoout,
},
},
filesyncing => {
desc => "[URI:/nodes/{noderange}/filesyncing] - The filesyncing resource for the node {noderange}",
matcher => '^/nodes/[^/]*/filesyncing$',
POST => {
desc => "Sync files for the node {noderange}.",
usage => "||An array of messages for performing the file syncing for the node.|",
example => "|Initiate an file syncing process.|POST|/nodes/node2/filesyncing|[\n \"There were no syncfiles defined to process. File synchronization has completed.\"\n]|",
cmd => "updatenode",
fhandler => \&actionhdl,
outhdler => \&infoout,
},
},
software_maintenance => {
desc => "[URI:/nodes/{noderange}/sw] - The software maintenance for the node {noderange}",
matcher => '^/nodes/[^/]*/sw$',
POST => {
desc => "Perform the software maintenance process for the node {noderange}.",
usage => "||$usagemsg{objreturn}|",
example => "|Initiate an software maintenance process.|POST|/nodes/node2/sw|{\n \"node2\":[\n \" Wed Apr 3 09:05:42 CST 2013 Running postscript: ospkgs\",\n \" Unable to read consumer identity\",\n \" Postscript: ospkgs exited with code 0\",\n \" Wed Apr 3 09:05:44 CST 2013 Running postscript: otherpkgs\",\n \" ./otherpkgs: no extra rpms to install\",\n \" Postscript: otherpkgs exited with code 0\",\n \" Running of Software Maintenance has completed.\"\n ]\n}|",
cmd => "updatenode",
fhandler => \&actionhdl,
outhdler => \&infoout,
},
},
postscript => {
desc => "[URI:/nodes/{noderange}/postscript] - The postscript resource for the node {noderange}",
matcher => '^/nodes/[^/]*/postscript$',
POST => {
desc => "Run the postscripts for the node {noderange}.",
example => "|Copy files /tmp/f1 and /tmp/f2 from xCAT MN to the node2:/tmp.|POST|/nodes/node2/nodecopy {\"src\":[\"/tmp/f1\",\"/tmp/f2\"],\"target\":\"/tmp\"}|no output for succeeded copy.|",
cmd => "xdcp",
fhandler => \&actionhdl,
outhdler => \&infoout,
},
},
subnodes => {
desc => "[URI:/nodes/{noderange}/subnodes] - The sub-nodes resources for the node {noderange}",
matcher => '^/nodes/[^/]*/subnodes$',
GET => {
desc => "Return the Children nodes for the node {noderange}.",
usage => "||$usagemsg{objreturn}|",
example => "|Get all the children nodes for node \'node1\'.|GET|/nodes/node1/subnodes|{\n \"cmm01node09\":{\n \"mpa\":\"ngpcmm01\",\n \"parent\":\"ngpcmm01\",\n \"serial\":\"1035CDB\",\n \"mtm\":\"789523X\",\n \"cons\":\"fsp\",\n \"hwtype\":\"blade\",\n \"objtype\":\"node\",\n \"groups\":\"blade,all,p260\",\n \"mgt\":\"fsp\",\n \"nodetype\":\"ppc,osi\",\n \"slotid\":\"9\",\n \"hcp\":\"10.1.9.9\",\n \"id\":\"1\"\n },\n ...\n}|",
cmd => "rscan",
fhandler => \&actionhdl,
outhdler => \&defout,
},
# the put should be implemented by customer that using GET to get all the resources and define it with PUT /nodes/<node name>
PUT_bak => {
desc => "Update the Children node for the node {noderange}.",
cmd => "rscan",
fhandler => \&common,
},
},
bootstate => {
desc => "[URI:/nodes/{noderange}/bootstate] - The boot state resource for node {noderange}.",
matcher => '^/nodes/[^/]*/bootstate$',
GET => {
desc => "Get boot state.",
usage => "||$usagemsg{objreturn}|",
example => "|Get the next boot state for the node1.|GET|/nodes/node1/bootstate|{\n \"node1\":{\n \"bootstat\":\"boot\"\n }\n}|",
example => "|Change the attributes mgt=dfm and netboot=yaboot.|PUT|/groups/all {\"mgt\":\"dfm\",\"netboot\":\"yaboot\"}||",
cmd => "chdef",
fhandler => \&defhdl,
outhdler => \&noout,
},
},
group_attr => {
desc => "[URI:/groups/{groupname}/attrs/{attr1,attr2,attr3 ...}] - The attributes resource for the group {groupname}",
matcher => '^/groups/[^/]*/attrs/\S+$',
GET => {
desc => "Get the specific attributes for the group {groupname}.",
usage => "||$usagemsg{objreturn}|",
example => "|Get the attributes {mgt,netboot} for group all|GET|/groups/all/attrs/mgt,netboot|{\n \"all\":{\n \"netboot\":\"yaboot\",\n \"mgt\":\"dfm\"\n }\n}|",
cmd => "lsdef",
fhandler => \&defhdl,
outhdler => \&defout,
},
},
},
#### definition for services resources: dns, dhcp, hostname
services => {
host => {
desc => "[URI:/services/host] - The hostname resource.",
matcher => '^/services/host$',
POST => {
desc => "Create the ip/hostname records for all the nodes to /etc/hosts.",
usage => "||$usagemsg{non_getreturn}|",
example => "|Create the ip/hostname records for all the nodes to /etc/hosts.|POST|/services/host||",
cmd => "makehosts",
fhandler => \&nonobjhdl,
outhdler => \&noout,
}
},
dns => {
desc => "[URI:/services/dns] - The dns service resource.",
matcher => '^/services/dns$',
POST => {
desc => "Initialize the dns service.",
usage => "||$usagemsg{non_getreturn}|",
example => "|Initialize the dns service.|POST|/services/dns||",
cmd => "makedns",
fhandler => \&nonobjhdl,
outhdler => \&noout,
}
},
dhcp => {
desc => "[URI:/services/dhcp] - The dhcp service resource.",
matcher => '^/services/dhcp$',
POST => {
desc => "Create the dhcpd.conf for all the networks which are defined in the xCAT Management Node.",
usage => "||$usagemsg{non_getreturn}|",
example => "|Create the dhcpd.conf and restart the dhcpd.|POST|/services/dhcp||",
cmd => "makedhcp",
fhandler => \&nonobjhdl,
outhdler => \&noout,
}
},
# todo: for slpnode, we need use the query attribute to specify the network parameter for lsslp command
slpnodes => {
desc => "[URI:/services/slpnodes] - The nodes which support SLP in the xCAT cluster",
matcher => '^/services/slpnodes',
GET => {
desc => "Get all the nodes which support slp protocol in the network.",
usage => "||$usagemsg{objreturn}|",
example => "|Get all the nodes which support slp in the network.|GET|/services/slpnodes|{\n \"ngpcmm01\":{\n \"mpa\":\"ngpcmm01\",\n \"otherinterfaces\":\"10.1.9.101\",\n \"serial\":\"100037A\",\n \"mtm\":\"789392X\",\n \"hwtype\":\"cmm\",\n \"side\":\"2\",\n \"objtype\":\"node\",\n \"nodetype\":\"mp\",\n \"groups\":\"cmm,all,cmm-zet\",\n \"mgt\":\"blade\",\n \"hidden\":\"0\",\n \"mac\":\"5c:f3:fc:25:da:99\"\n },\n ...\n}|",
cmd => "lsslp",
fhandler => \&nonobjhdl,
outhdler => \&defout,
},
PUT_bakcup => {
desc => "Update the discovered nodes to database.",
cmd => "lsslp",
fhandler => \&common,
},
},
specific_slpnodes => {
desc => "[URI:/services/slpnodes/{CEC|FRAME|MM|IVM|RSA|HMC|CMM|IMM2|FSP...}] - The slp nodes with specific service type in the xCAT cluster",
matcher => '^/services/slpnodes/[^/]*$',
GET => {
desc => "Get all the nodes with specific slp service type in the network.",
usage => "||$usagemsg{objreturn}|",
example => "|Get all the CMM nodes which support slp in the network.|GET|/services/slpnodes/CMM|{\n \"ngpcmm01\":{\n \"mpa\":\"ngpcmm01\",\n \"otherinterfaces\":\"10.1.9.101\",\n \"serial\":\"100037A\",\n \"mtm\":\"789392X\",\n \"hwtype\":\"cmm\",\n \"side\":\"2\",\n \"objtype\":\"node\",\n \"nodetype\":\"mp\",\n \"groups\":\"cmm,all,cmm-zet\",\n \"mgt\":\"blade\",\n \"hidden\":\"0\",\n \"mac\":\"5c:f3:fc:25:da:99\"\n },\n \"Server--SNY014BG27A01K\":{\n \"mpa\":\"Server--SNY014BG27A01K\",\n \"otherinterfaces\":\"10.1.9.106\",\n \"serial\":\"100CF0A\",\n \"mtm\":\"789392X\",\n \"hwtype\":\"cmm\",\n \"side\":\"1\",\n \"objtype\":\"node\",\n \"nodetype\":\"mp\",\n \"groups\":\"cmm,all,cmm-zet\",\n \"mgt\":\"blade\",\n \"hidden\":\"0\",\n \"mac\":\"34:40:b5:df:0a:be\"\n }\n}|",
cmd => "lsslp",
fhandler => \&nonobjhdl,
outhdler => \&defout,
},
PUT_backup => {
desc => "Update the discovered nodes to database.",
cmd => "lsslp",
fhandler => \&common,
},
},
},
#### definition for network resources
networks => {
allnetwork => {
desc => "[URI:/networks] - The network list resource.",
desc1 => "This resource can be used to display all the networks which have been defined in the xCAT database.",
matcher => '^\/networks$',
GET => {
desc => "Get all the networks in xCAT.",
desc1 => "The attributes details for the networks will not be displayed.",
usage => "||Json format: An array of networks names.|",
example => "|Get all the networks names from xCAT database.|GET|/networks|[\n \"network1\",\n \"network2\",\n \"network3\",\n]|",
cmd => "lsdef",
fhandler => \&defhdl,
outhdler => \&defout_remove_appended_type,
},
POST => {
desc => "Create the networks resources base on the network configuration on xCAT MN.",
example => "|Get all the attibutes for network \'network1\'.|GET|/networks/network1|{\n \"network1\":{\n \"gateway\":\"<xcatmaster>\",\n \"mask\":\"255.255.255.0\",\n \"mgtifname\":\"eth2\",\n \"net\":\"10.0.0.0\",\n \"tftpserver\":\"10.0.0.119\",\n ...\n }\n}|",
cmd => "lsdef",
fhandler => \&defhdl,
outhdler => \&defout,
},
PUT => {
desc => "Change the attibutes for the network {netname}.",
example => "|Create a network with attributes gateway=10.1.0.1, mask=255.255.0.0 |POST|/networks/network1 {\"gateway\":\"10.1.0.1\",\"mask\":\"255.255.0.0\"}||",
cmd => "mkdef",
fhandler => \&defhdl,
outhdler => \&noout,
},
DELETE => {
desc => "Remove the network {netname}.",
usage => "||$usagemsg{non_getreturn}|",
example => "|Delete the network network1|DELETE|/networks/network1||",
cmd => "rmdef",
fhandler => \&defhdl,
outhdler => \&noout
},
},
network_attr => {
desc => "[URI:/networks/{netname}/attrs/attr1,attr2,...] - The attributes resource for the network {netname}",
matcher => '^\/networks\/[^\/]*/attrs/\S+$',
GET => {
desc => "Get the specific attributes for the network {netname}.",
example => "|Get the attributes {groups,mgt,netboot} for network network1|GET|/networks/network1/attrs/gateway,mask,mgtifname,net,tftpserver|{\n \"network1\":{\n \"gateway\":\"9.114.34.254\",\n \"mask\":\"255.255.255.0\",\n }\n}|",
cmd => "lsdef",
fhandler => \&defhdl,
outhdler => \&defout,
},
PUT__backup => {
desc => "Change attributes for the network {netname}. DataBody: {attr1:v1,att2:v2,att3:v3 ...}.",
usage => "||An array of network objects.|",
example => "|Get the attributes {gateway,mask,mgtifname,net,tftpserver} for networks network1|GET|/networks/network1/attrs/gateway;mask;net||",
cmd => "chdef",
fhandler => \&noout,
}
},
},
#### definition for osimage resources
osimages => {
osimage => {
desc => "[URI:/osimages] - The osimage resource.",
matcher => '^\/osimages$',
GET => {
desc => "Get all the osimage in xCAT.",
usage => "||Json format: An array of osimage names.|",
example => "|Get all the osimage names.|GET|/osimages|[\n \"sles11.2-x86_64-install-compute\",\n \"sles11.2-x86_64-install-iscsi\",\n \"sles11.2-x86_64-install-iscsiibft\",\n \"sles11.2-x86_64-install-service\"\n]|",
cmd => "lsdef",
fhandler => \&defhdl,
outhdler => \&defout_remove_appended_type,
},
POST => {
desc => "Create the osimage resources base on the parameters specified in the Data body.",
example1 => "|Create osimage resources based on the ISO specified|POST|/osimages {\"iso\":\"/iso/RHEL6.4-20130130.0-Server-ppc64-DVD1.iso\"}||",
example2 => "|Create osimage resources based on an xCAT image or configuration file|POST|/osimages {\"file\":\"/tmp/sles11.2-x86_64-install-compute.tgz\"}||",
# TD: the imgcapture need to be moved to nodes/.*/osimages
# example3 => "|Create a image based on the specified Linux diskful node|POST|/osimages {\"node\":\"rhcn1\"}||",
cmd => "copycds",
fhandler => \&imgophdl,
outhdler => \&noout,
},
},
osimage_allattr => {
desc => "[URI:/osimages/{imgname}] - The osimage resource",
matcher => '^\/osimages\/[^\/]*$',
GET => {
desc => "Get all the attibutes for the osimage {imgname}.",
example => "|Create a osimage obj with the specified parameters.|POST|/osimages/sles11.3-ppc64-install-compute {\"osvers\":\"sles11.3\",\"osarch\":\"ppc64\",\"osname\":\"Linux\",\"provmethod\":\"install\",\"profile\":\"compute\"}||",
cmd => "mkdef",
fhandler => \&defhdl,
outhdler => \&noout,
},
PUT => {
desc => "Change the attibutes for the osimage {imgname}.",
example => "|Change the 'osvers' and 'osarch' attributes for the osiamge.|PUT|/osimages/sles11.2-ppc64-install-compute/ {\"osvers\":\"sles11.3\",\"osarch\":\"x86_64\"}||",
cmd => "chdef",
fhandler => \&defhdl,
outhdler => \&noout,
},
DELETE => {
desc => "Remove the osimage {imgname}.",
usage => "||$usagemsg{non_getreturn}|",
example => "|Delete the specified osimage.|DELETE|/osimages/sles11.3-ppc64-install-compute||",
cmd => "rmdef",
fhandler => \&defhdl,
outhdler => \&noout,
},
},
osimage_attr => {
desc => "[URI:/osimages/{imgname}/attrs/attr1,attr2,attr3 ...] - The attributes resource for the osimage {imgname}",
matcher => '^\/osimages\/[^\/]*/attrs/\S+$',
GET => {
desc => "Get the specific attributes for the osimage {imgname}.",
example => "|Change the 'osvers' and 'osarch' attributes for the osiamge.|PUT|/osimages/sles11.2-ppc64-install-compute/attrs/osvers;osarch {\"osvers\":\"sles11.3\",\"osarch\":\"x86_64\"}||",
cmd => "chdef",
fhandler => \&defhdl,
outhdler => \&noout,
},
},
osimage_op => {
desc => "[URI:/osimages/{imgname}/instance] - The instance for the osimage {imgname}",
matcher => '^\/osimages\/[^\/]*/instance$',
POST => {
desc => "Operate the instance of the osimage {imgname}.",
example1 => "|Generates a stateless image based on the specified osimage|POST|/osimages/sles11.2-x86_64-install-compute/instance {\"action\":\"gen\"}||",
example2 => "|Packs the stateless image from the chroot file system based on the specified osimage|POST|/osimages/sles11.2-x86_64-install-compute/instance {\"action\":\"pack\"}||",
example3 => "|Exports an xCAT image based on the specified osimage|POST|/osimages/sles11.2-x86_64-install-compute/instance {\"action\":\"export\"}||",
cmd => "",
fhandler => \&imgophdl,
},
DELETE => {
desc => "Delete the stateless or statelite image instance for the osimage {imgname} from the file system",
usage => "||$usagemsg{non_getreturn}",
example => "|Delete the stateless image for the specified osimage|DELETE|/osimages/sles11.2-x86_64-install-compute/instance||",
example => "|Get the name and rule attributes for policy 1.|GET|/policy/1/attrs/name,rule|{\n \"1\":{\n \"name\":\"root\",\n \"rule\":\"allow\"\n }\n}|",
cmd => "lsdef",
fhandler => \&defhdl,
outhdler => \&defout,
},
},
},
#### definition for global setting resources
globalconf => {
all_site => {
desc => "[URI:/globalconf] - The global configuration resource.",
desc1 => "This resource can be used to display all the global configuration which have been defined in the xCAT database.",
matcher => '^\/globalconf$',
GET => {
desc => "Get all the xCAT global configuration.",
desc1=> "It will display all the global attributes.",
usage => "||$usagemsg{objreturn}|",
example => "|Get all the global configuration|GET|/globalconf|{\n \"clustersite\":{\n \"xcatconfdir\":\"/etc/xcat\",\n \"tftpdir\":\"/tftpboot\",\n ...\n }\n}|",
cmd => "lsdef",
fhandler => \&sitehdl,
outhdler => \&defout,
},
POST_backup => {
desc => "Add the site attributes. DataBody: {attr1:v1,att2:v2...}.",
desc1 => "One or more global attributes could be added/modified.",
example => "|Add one or more attributes to xCAT database|POST|/globalconf {\"domain\":\"cluster.com\",\"mydomain\":\"mycluster.com\"}||",
cmd => "chdef",
fhandler => \&sitehdl,
},
},
site => {
desc => "[URI:/globalconf/attrs/{attr1,attr2 ...}] - The specific global configuration resource.",
matcher => '^\/globalconf/attrs/\S+$',
GET => {
desc => "Get the specific configuration in global.",
desc1 => "It will display one or more global attributes.",
usage => "||$usagemsg{objreturn}|",
example => "|Get the \'master\' and \'domain\' configuration.|GET|/globalconf/attrs/master,domain|{\n \"clustersite\":{\n \"domain\":\"cluster.com\",\n \"master\":\"192.168.1.15\"\n }\n}|",
cmd => "lsdef",
fhandler => \&sitehdl,
outhdler => \&defout,
},
PUT => {
desc => "Change the global attributes.",
desc1 => "It can be used for changing/adding global attributes.",
example => "|Change/Add the domain attribute.|PUT|/globalconf/attrs/domain {\"domain\":\"cluster.com\"}||",
cmd => "chdef",
fhandler => \&sitehdl,
outhdler => \&noout,
},
POST_backup => {
desc => "Create the global configuration entry. DataBody: {name:value}.",
usage => "||$usagemsg{non_getreturn}|",
example => "|Create the domain attribute|POST|/globalconf/attrs/domain {\"domain\":\"cluster.com\"}|?|",
cmd => "chdef",
fhandler => \&sitehdl,
outhdler => \&noout,
},
DELETE => {
desc => "Remove the site attributes.",
desc1 => "Used for femove one or more global attributes.",
usage => "||$usagemsg{non_getreturn}|",
example => "|Remove the domain configure.|DELETE|/globalconf/attrs/domain||",
cmd => "chdef",
fhandler => \&sitehdl,
outhdler => \&noout,
},
},
},
#### definition for database/table resources
tables => {
table_nodes => {
desc => "[URI:/tables/{tablelist}/nodes/{noderange}] - The node table resource",
desc1 => "For a large number of nodes, this API call can be faster than using the corresponding nodes resource. The disadvantage is that you need to know the table names the attributes are stored in.",
matcher => '^/tables/[^/]+/nodes/[^/]+$',
GET => {
desc => "Get attibutes of tables for a noderange.",
usage => "||An object containing each table. Within each table object is an array of node objects containing the attributes.|",
example1 => qq(|Get all the columns from table nodetype for node1 and node2.|GET|/tables/nodetype/nodes/node1,node2|{\n \"nodetype\":[\n {\n \"provmethod\":\"rhels6.4-x86_64-install-compute\",\n \"profile\":\"compute\",\n \"arch\":\"x86_64\",\n \"name\":\"node1\",\n \"os\":\"rhels6.4\"\n },\n {\n \"provmethod\":\"rhels6.3-x86_64-install-compute\",\n \"profile\":\"compute\",\n \"arch\":\"x86_64\",\n \"name\":\"node2\",\n \"os\":\"rhels6.3\"\n }\n ]\n}|),
example2 => qq(|Get all the columns from tables nodetype and noderes for node1 and node2.|GET|/tables/nodetype,noderes/nodes/node1,node2|{\n \"noderes\":[\n {\n \"installnic\":\"mac\",\n \"netboot\":\"xnba\",\n \"name\":\"node1\",\n \"nfsserver\":\"192.168.1.15\"\n },\n {\n \"installnic\":\"mac\",\n \"netboot\":\"pxe\",\n \"name\":\"node2\",\n \"proxydhcp\":\"no\"\n }\n ],\n \"nodetype\":[\n {\n \"provmethod\":\"rhels6.4-x86_64-install-compute\",\n \"profile\":\"compute\",\n \"arch\":\"x86_64\",\n \"name\":\"node1\",\n \"os\":\"rhels6.4\"\n },\n {\n \"provmethod\":\"rhels6.3-x86_64-install-compute\",\n \"profile\":\"compute\",\n \"arch\":\"x86_64\",\n \"name\":\"node2\",\n \"os\":\"rhels6.3\"\n }\n ]\n}|),
fhandler => \&tablenodehdl,
outhdler => \&tableout,
},
PUT => {
desc => "Change the node table attibutes for {noderange}.",
usage => "|A hash of table names and attribute objects. DataBody: {table1:{attr1:v1,att2:v2,...}}.|$usagemsg{non_getreturn}|",
example => '|Change the nodetype.arch and noderes.netboot attributes for nodes node1,node2.|PUT|/tables/nodetype,noderes/nodes/node1,node2 {"nodetype":{"arch":"x86_64"},"noderes":{"netboot":"xnba"}}||',
fhandler => \&tablenodeputhdl,
outhdler => \&noout,
},
},
table_nodes_attrs => {
desc => "[URI:/tables/{tablelist}/nodes/nodes/{noderange}/{attrlist}] - The node table attributes resource",
desc1 => "For a large number of nodes, this API call can be faster than using the corresponding nodes resource. The disadvantage is that you need to know the table names the attributes are stored in.",
matcher => '^/tables/[^/]+/nodes/[^/]+/[^/]+$',
GET => {
desc => "Get table attibutes for a noderange.",
usage => "||An object containing each table. Within each table object is an array of node objects containing the attributes.|",
example => qq(|Get OS and ARCH attributes from nodetype table for node1 and node2.|GET|/tables/nodetype/nodes/node1,node2/os,arch|{\n \"nodetype\":[\n {\n \"arch\":\"x86_64\",\n \"name\":\"node1\",\n \"os\":\"rhels6.4\"\n },\n {\n \"arch\":\"x86_64\",\n \"name\":\"node2\",\n \"os\":\"rhels6.3\"\n }\n ]\n}|),
fhandler => \&tablenodehdl,
outhdler => \&tableout,
},
PUT_backup => {
desc => "[URI:/tables/nodes/{noderange}] - Change the node table attibutes for the {noderange}.",
usage => "|A hash of table names and attribute objects. DataBody: {table1:{attr1:v1,att2:v2,...}}.|$usagemsg{non_getreturn}|",
example => '|Change the nodehm.mgmt and noderes.netboot attributes for nodes node1-node5.|PUT|/tables/nodes/node1-node5 {"nodehm":{"mgmt":"ipmi"},"noderes":{"netboot":"xnba"}}||',
fhandler => \&tablenodeputhdl,
outhdler => \&noout,
},
},
table_all_rows => {
desc => "[URI:/tables/{tablelist}/rows] - The non-node table resource",
desc1 => "Use this for tables that don't have node name as the key of the table, for example: passwd, site, networks, polciy, etc.",
matcher => '^/tables/[^/]+/rows$',
GET => {
desc => "Get all rows from non-node tables.",
usage => "||An object containing each table. Within each table object is an array of row objects containing the attributes.|",
example => qq(|Get all rows from networks table.|GET|/tables/networks/rows|{\n \"networks\":[\n {\n \"netname\":\"192_168_13_0-255_255_255_0\",\n \"gateway\":\"192.168.13.254\",\n \"staticrangeincrement\":\"1\",\n \"net\":\"192.168.13.0\",\n \"mask\":\"255.255.255.0\"\n },\n {\n \"netname\":\"192_168_12_0-255_255_255_0\",\n \"gateway\":\"192.168.12.254\",\n \"staticrangeincrement\":\"1\",\n \"net\":\"192.168.12.0\",\n \"mask\":\"255.255.255.0\"\n },\n ]\n}|),
fhandler => \&tablerowhdl,
outhdler => \&tableout,
},
},
table_rows => {
desc => "[URI:/tables/{tablelist}/rows/{keys}] - The non-node table rows resource",
desc1 => "Use this for tables that don't have node name as the key of the table, for example: passwd, site, networks, polciy, etc.",
desc2 => "{keys} should be the name=value pairs which are used to search table. e.g. {keys} should be [net=192.168.1.0,mask=255.255.255.0] for networks table query since the net and mask are the keys of networks table.",
matcher => '^/tables/[^/]+/rows/[^/]+$',
GET => {
desc => "Get attibutes for rows from non-node tables.",
usage => "||An object containing each table. Within each table object is an array of row objects containing the attributes.|",
example => qq(|Get row which net=192.168.1.0,mask=255.255.255.0 from networks table.|GET|/tables/networks/rows/net=192.168.1.0,mask=255.255.255.0|{\n \"networks\":[\n {\n \"mgtifname\":\"eth0\",\n \"netname\":\"192_168_1_0-255_255_255_0\",\n \"tftpserver\":\"192.168.1.15\",\n \"gateway\":\"192.168.1.100\",\n \"staticrangeincrement\":\"1\",\n \"net\":\"192.168.1.0\",\n \"mask\":\"255.255.255.0\"\n }\n ]\n}|),
fhandler => \&tablerowhdl,
outhdler => \&tableout,
},
PUT => {
desc => "Change the non-node table attibutes for the row that matches the {keys}.",
usage => "|A hash of attribute names and values. DataBody: {attr1:v1,att2:v2,...}.|$usagemsg{non_getreturn}|",
example => '|Create a route row in the routes table.|PUT|/tables/routes/rows/routename=privnet {"net":"10.0.1.0","mask":"255.255.255.0","gateway":"10.0.1.254","ifname":"eth1"}||',
fhandler => \&tablerowputhdl,
outhdler => \&noout,
},
DELETE => {
desc => "Delete rows from a non-node table that have the attribute values specified in {keys}.",
usage => "||$usagemsg{non_getreturn}|",
example => '|Delete a route row which routename=privnet in the routes table.|DELETE|/tables/routes/rows/routename=privnet||',
fhandler => \&tablerowdelhdl,
outhdler => \&noout,
},
},
table_rows_attrs => {
desc => "[URI:/tables/{tablelist}/rows/{keys}/{attrlist}] - The non-node table attributes resource",
desc1 => "Use this for tables that don't have node name as the key of the table, for example: passwd, site, networks, polciy, etc.",
matcher => '^/tables/[^/]+/rows/[^/]+/[^/]+$',
GET => {
desc => "Get specific attibutes for rows from non-node tables.",
usage => "||An object containing each table. Within each table object is an array of row objects containing the attributes.|",
example => qq(|Get attributes mgtifname and tftpserver which net=192.168.1.0,mask=255.255.255.0 from networks table.|GET|/tables/networks/rows/net=192.168.1.0,mask=255.255.255.0/mgtifname,tftpserver|{\n \"networks\":[\n {\n \"mgtifname\":\"eth0\",\n \"tftpserver\":\"192.168.1.15\"\n }\n ]\n}|),
fhandler => \&tablerowhdl,
outhdler => \&tableout,
},
},
},
#### definition for tokens resources
tokens => {
tokens => {
desc => "[URI:/tokens] - The authentication token resource.",
matcher => '^\/tokens',
POST => {
desc => "Create a token.",
usage => "||An array of all the global configuration list.|",
example => "|Aquire a token for user \'root\'.|POST|/tokens {\"userName\":\"root\",\"password\":\"cluster\"}|{\n \"token\":{\n \"id\":\"a6e89b59-2b23-429a-b3fe-d16807dd19eb\",\n \"expire\":\"2014-3-8 14:55:0\"\n }\n}|",
fhandler => \&nonobjhdl,
outhdler => \&tokenout,
},
POST_backup => {
desc => "Add the site attributes. DataBody: {attr1:v1,att2:v2...}.",
usage => "|?|?|",
example => "|?|?|?|?|",
cmd => "chdef",
fhandler => \&sitehdl,
},
},
},
);
# supported formats
my %formatters = (
'json' => \&wrapJson,
#'html' => \&wrapHtml,
#'xml' => \&wrapXml
);
# error status codes
my $STATUS_BAD_REQUEST = "400 Bad Request";
my $STATUS_UNAUTH = "401 Unauthorized";
my $STATUS_FORBIDDEN = "403 Forbidden";
my $STATUS_NOT_FOUND = "404 Not Found";
my $STATUS_NOT_ALLOWED = "405 Method Not Allowed";
my $STATUS_NOT_ACCEPTABLE = "406 Not Acceptable";
my $STATUS_TIMEOUT = "408 Request Timeout";
my $STATUS_EXPECT_FAILED = "417 Expectation Failed";
my $STATUS_TEAPOT = "418 I'm a teapot";
my $STATUS_SERVICE_UNAVAILABLE = "503 Service Unavailable";
addPageContent(qq(\n\n\n=======================================================\nDebug: Following message is just for debugging. It will be removed in the GAed version.\n));
my $json;
if ($data) {
addPageContent($JSON->encode($data));
}
addPageContent(qq(["Debug: the operation has been done successfully"]));
# desc => "[URI:/tables/nodes/{noderange}] - Change the table attibutes for the {noderange}.",
# usage => "|An array of table objects. Each table object contains the table name and an object of attribute values. DataBody: {table1:{attr1:v1,att2:v2,...}}.|$usagemsg{non_getreturn}|",
# example => '|Change the nodehm.mgmt and noderes.netboot attributes for nodes node1-node5.|PUT|/tables/nodes/node1-node5 {"nodehm":{"mgmt":"ipmi"},"noderes":{"netboot":"xnba"}}||',
my @args;
my @urilayers = @{$params->{'layers'}};
# the array elements for @urilayers are:
# 0 - 'table'
# 1 - <tablelist>
# 2 - 'nodes'
# 3 - <noderange>
# set the command name
$request->{command} = 'setNodesAttribs';
$request->{noderange} = $urilayers[3];
# For setNodesAttribs, the rest of the request strucutre looks like this:
# arg => {
# table => [
# {
# name => nodehm,
# attr => {
# mgmt => ipmi
# }
# },
# {
# name => noderes,
# attr => {
# netboot => xnba
# }
# }
# ]
# }
# Get table list in the URI
my @uritbs = split(/,/, $urilayers[1]);
# Go thru the list of tables (which are the top level keys in paramhash)
my $tables = [];
$request->{arg}->{table} = $tables;
foreach my $k (keys(%$paramhash)) {
my $intable = $k;
# Check the validity of tables
if (! grep(/^$intable$/, @uritbs)) {
error("The table $intable is NOT in the URI.", $STATUS_BAD_REQUEST);
}
my $attrhash = $paramhash->{$k};
my $outtable = { name=>$intable, attr=>$attrhash };
push @$tables, $outtable;
}
my $req = genRequest();
# disabling the KeyAttr option is important in this case, so xmlin doesn't pull the name attribute
# desc => "[URI:/tables/{table}/rows/{keys}] - Change the non-node table attibutes for the row that matches the {keys}.",
# usage => "|A hash of attribute names and values. DataBody: {attr1:v1,att2:v2,...}.|$usagemsg{non_getreturn}|",
# example => '|Creat a route row in the routes table.|PUT|/tables/routes/rows/routename=privnet {"net":"10.0.1.0","mask":"255.255.255.0","gateway":"10.0.1.254","ifname":"eth1"}||',
# For delEntries, the rest of the xml request strucutre looks like this:
# <table>
# <name>nodelist</name>
# <attr>
# <groups>compute1,lissa</groups>
# <status>down</status>
# </attr>
# </table>
# set the table name and attr/vals
my $table = {}; # will hold the name and attr/vals
$request->{table}->[0] = $table; #todo: the xcat delEntries cmd supports multiple tables in 1 request. We could support this if the attr names were table.attr
error('The XML::Simple perl module is missing. Install perl-XML-Simple before using the xCAT REST web services API with this format."}',$STATUS_SERVICE_UNAVAILABLE);