From a5ff9cfeeced3c396a86ec57d9467eae379a162e Mon Sep 17 00:00:00 2001 From: daniceexi Date: Tue, 18 Mar 2014 10:22:17 -0400 Subject: [PATCH] add the mechanism to auto make document for restapi --- xCAT-server/xCAT-wsapi/genrestapidoc.pm | 128 ++++++++++++++++++++++++ xCAT-server/xCAT-wsapi/restapi.pl | 50 +++++++-- 2 files changed, 172 insertions(+), 6 deletions(-) create mode 100755 xCAT-server/xCAT-wsapi/genrestapidoc.pm diff --git a/xCAT-server/xCAT-wsapi/genrestapidoc.pm b/xCAT-server/xCAT-wsapi/genrestapidoc.pm new file mode 100755 index 000000000..fde1f379e --- /dev/null +++ b/xCAT-server/xCAT-wsapi/genrestapidoc.pm @@ -0,0 +1,128 @@ +#! /usr/bin/perl + +package genrestapidoc; + +my @apigroups = ( + { + groupname => 'node', + resources => ['allnode', 'nodeallattr'] + }, + + { + groupname => 'network', + resources => ['network', 'network_allattr', 'network_attr'] + }, +); + +my %formathdl = ( + text => \&outtext, +); + +sub outtext { + my $def = shift; + my $opt = shift; + my $head = shift; + + if ($head) { + print "\n$head\n"; + } + + my $postfix = "?userName=xxx&password=xxx&pretty=1"; + + if (defined ($def->{desc})) { + print " $opt - $def->{desc}\n"; + } + + if (defined ($def->{usage})) { + my @parts = split ('\|', $def->{usage}); + if ($parts[1]) { + print " Parameters: $parts[2]\n"; + } + if ($parts[2]) { + print " Returns: $parts[2]\n"; + } + } + + if (defined ($def->{example})) { + my @parts = split ('\|', $def->{example}); + print " Example:\n"; + + if ($parts[1]) { + print " $parts[1]\n"; + } + + if ($parts[2] && $parts[3] && $parts[4]) { + my ($uri, $data); + if ($part[3] =~ /\s+/) { + ($uri, $data) = split(/ /, $part[3]); + print " #curl $parts[2] -k \'https://myserver/xcatws$uri$postfix\' -H Content-Type:application/json --data \'$data\'\n"; + } else { + print " #curl $parts[2] -k \'https://myserver/xcatws$parts[3]$postfix\'\n"; + } + $parts[4] =~ s/\n/\n /g; + print " $parts[4]\n"; + } + + } +} + +sub gendoc { + my $URIdef = shift; + my $format = shift; + + unless ($format) { + $format = "text"; + } + + my @errmsg; + +foreach my $group (@apigroups) { + my $groupname = $group->{'groupname'}; + if (defined ($URIdef->{$groupname})) { + foreach my $res (@{$group->{'resources'}}) { + if (defined ($URIdef->{$groupname}->{$res})) { + if (defined ($URIdef->{$groupname}->{$res}->{GET})) { + $formathdl{$format}->($URIdef->{$groupname}->{$res}->{GET}, "GET", $URIdef->{$groupname}->{$res}->{desc}); + } + if (defined ($URIdef->{$groupname}->{$res}->{PUT})) { + $formathdl{$format}->($URIdef->{$groupname}->{$res}->{PUT}, "PUT"); + } + if (defined ($URIdef->{$groupname}->{$res}->{POST})) { + $formathdl{$format}->($URIdef->{$groupname}->{$res}->{POST}, "POST"); + } + if (defined ($URIdef->{$groupname}->{$res}->{DELETE})) { + $formathdl{$format}->($URIdef->{$groupname}->{$res}->{DELETE}, "DELETE"); + } + } else { + push @errmsg, "Cannot find the definition for resource [$res]\n"; + } + } + } else { + push @errmsg, "Cannot find the definition for resource group [$groupname]\n"; + } +} + + print @errmsg; +} +sub displayUsage { + foreach my $group (keys %URIdef) { + print "Resource Group: $group\n"; + foreach my $res (keys %{$URIdef{$group}}) { + print " Resource: $res\n"; + print " $URIdef{$group}->{$res}->{desc}\n"; + if (defined ($URIdef{$group}->{$res}->{GET})) { + print " GET: $URIdef{$group}->{$res}->{GET}->{desc}\n"; + } + if (defined ($URIdef{$group}->{$res}->{PUT})) { + print " PUT: $URIdef{$group}->{$res}->{PUT}->{desc}\n"; + } + if (defined ($URIdef{$group}->{$res}->{POST})) { + print " POST: $URIdef{$group}->{$res}->{POST}->{desc}\n"; + } + if (defined ($URIdef{$group}->{$res}->{DELETE})) { + print " DELETE: $URIdef{$group}->{$res}->{DELETE}->{desc}\n"; + } + } + } +} + diff --git a/xCAT-server/xCAT-wsapi/restapi.pl b/xCAT-server/xCAT-wsapi/restapi.pl index 9487f5054..d2cc39360 100755 --- a/xCAT-server/xCAT-wsapi/restapi.pl +++ b/xCAT-server/xCAT-wsapi/restapi.pl @@ -24,6 +24,8 @@ my %URIdef = ( matcher => '^\/node$', GET => { desc => "Get all the nodes in xCAT.", + usage => "||An array of node names.|", + example => "|Get all the node names from xCAT database.|GET|/node|[\n all,\n node1,\n node2,\n node3,\n]|", cmd => "lsdef", fhandler => \&defhdl, outhdler => \&defout_remove_appended_type, @@ -34,24 +36,35 @@ my %URIdef = ( matcher => '^\/node\/[^\/]*$', GET => { desc => "Get all the attibutes for the node {nodename}.", + usage => "||An array of node objects.|", + example => "|Get all the attibutes for node \'node1\'.|GET|/node/node1|[\n {\n netboot:xnba,\n mgt:1,\n groups:22,\n name:node1,\n postbootscripts:otherpkgs,\n postscripts:syslog,remoteshell,syncfiles\n }\n]|", cmd => "lsdef", fhandler => \&defhdl, outhdler => \&defout, }, PUT => { desc => "Change the attibutes for the node {nodename}.", + usage => "||An array of node objects.|", + example => "|Change the attributes mgt=dfm and netboot=yaboot.|PUT|/node/node1 {mgt:dfm,netboot:yaboot}|{\n \"info\":[\n \"1 object definitions have been created or modified.\"\n ]\n}|", cmd => "chdef", fhandler => \&defhdl, + outhdler => \&infoout, }, POST => { desc => "Create the node {nodename}. DataBody: {attr1:v1,att2:v2...}.", + usage => "||An array of node objects.|", + example => "|Create a node with attributes groups=all, mgt=dfm and netboot=yaboot|POST|/node/node1 {groups:all,mgt:dfm,netboot:yaboot}|{\n \"info\":[\n \"1 object definitions have been created or modified.\"\n ]\n}|", cmd => "mkdef", fhandler => \&defhdl, + outhdler => \&infoout, }, DELETE => { desc => "Remove the node {nodename}.", + usage => "||An array of node objects.|", + example => "|Delete the node node1|DELETE|/node/node1|{\n \"info\":[\n \"1 object definitions have been removed.\"\n ]\n}|", cmd => "rmdef", fhandler => \&defhdl, + outhdler => \&infoout, }, }, nodeattr => { @@ -631,6 +644,7 @@ my $pageContent = ''; # global var containing the ouptut back to the rest my $request = {clienttype => 'ws'}; # global var that holds the request to send to xcatd my $format = 'json'; my $pretty; +my $xmlinstalled; # Handle the command parameter for debugging and generating doc my $dbgdata; @@ -639,6 +653,10 @@ sub dbgusage { print "Usage:\n $0 -h\n $0 -d\n $0 {GET|PUT|POST|DELETE} if ($ARGV[0] eq "-h") { dbgusage(); exit 0; +} elsif ($ARGV[0] eq "-g") { + require genrestapidoc; + genrestapidoc::gendoc(\%URIdef); + exit 0; } elsif ($ARGV[0] eq "-d") { displayUsage(); exit 0; @@ -709,11 +727,7 @@ if ($format eq 'json') { # require XML dynamically and let them know if it is not installed # we need XML all the time to send request to xcat, even if thats not the return format requested by the user -my $xmlinstalled = eval { require XML::Simple; }; -unless ($xmlinstalled) { - 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); -} -$XML::Simple::PREFERRED_PARSER = 'XML::Parser'; +loadXML(); # Match the first layer of resource URI my $uriLayer1; @@ -888,6 +902,20 @@ sub defout_remove_appended_type { } } +sub infoout { + my $data = shift; + + my $json; + foreach my $d (@$data) { + if (defined ($d->{info})) { + push @{$json->{info}}, @{$d->{info}}; + } + } + if ($json) { + addPageContent($JSON->encode($json)); + } +} + sub actionout { my $data = shift; my $param =shift; @@ -1130,7 +1158,6 @@ sub displayUsage { } - # This handles and removes serverdone and error tags in the perl data structure that is from the xml that xcatd returned #bmp: is there a way to avoid make a copy of the whole response? For big output that could be time consuming. # For the error tag, you don't have to bother copying the response, because you are going to exit anyway. @@ -1484,6 +1511,17 @@ sub fetchParameters { return ($genparms, $phash); } +# Load the XML::Simple module +sub loadXML { + if ($xmlinstalled) { return; } + + $xmlinstalled = eval { require XML::Simple; }; + unless ($xmlinstalled) { + 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); + } + $XML::Simple::PREFERRED_PARSER = 'XML::Parser'; +} + # Load the JSON perl module, if not already loaded. Sets the $JSON global var. sub loadJSON { if ($JSON) { return; } # already loaded