Catalyst, run "auto" action from special controller in other - perl

for example, I have a controller with "auto":
package Controller::User;
sub auto :Private {
my ($self, $c) = #_;
$c->log->debug('Hello!');
return 1;
}
I want to use this auto method automatically in another controllers (but not in all). Let say, in Controller::My, Controller::Dashboard etc.
And also I have different controllers I don't need to use this "auto" action.
Is it possible to "inherit" this action from special controller inside another one?

I would assume you can put your auto method in a base controller and inherit from there in the controllers you want to have the method:
https://metacpan.org/pod/Catalyst::Manual::ExtendingCatalyst#Controllers
You might also be able to use a controller role that just contains your auto method and apply it to any of the controllers you want to:
http://www.catalystframework.org/calendar/2011/10

Since Catalyst uses Moose, and Catalyst::Controller objects are Moose objects, you can use Moose roles with them.
package Hello::DebugRole;
use Moose::Role;
use MooseX::MethodAttributes::Role;
sub auto :Private {
my ($self, $c) = #_;
$c->log->debug('Hello!');
return 1;
}
1;
We need MooseX::MethodAttributes::Role to enable the CODE attributes. Without that, it dies at execution time, and if we ommit the :Private, Catalyst does not see it as an action, but as a local method instead.
This approach makes sense because you can have your auto action defined in one place, which is nicely DRY, and you completely reuse that code in all places where you want it.
Now you can use that in all the controllers you want. Just put it in the BEGIN block.
package Hello::Controller::User;
use Moose;
use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller'; with 'Hello::DebugRole'; }
If I navigate to that controller, the log will look like this:
[debug] Path is "user"
[debug] "GET" request for "user/" from "127.0.0.1"
[debug] Hello!
[debug] Response Code: 200; Content-Type: text/html; charset=utf-8; Content-Length: unknown
[info] Request took 0.010909s (91.667/s)
.------------------------------------------------------------+-----------.
| Action | Time |
+------------------------------------------------------------+-----------+
| /user/auto | 0.000237s |
| /user/index | 0.000152s |
| /end | 0.000394s |
'------------------------------------------------------------+-----------'
[info] *** Request 2 (0.286/s) [24045] [Wed Jan 6 16:16:15 2016] ***
But if I navigate to the Foobar controller instead, there is no auto action, and no Hello!.
[info] *** Request 3 (0.250/s) [24045] [Wed Jan 6 16:16:20 2016] ***
[debug] Path is "foobar"
[debug] "GET" request for "foobar/" from "127.0.0.1"
[debug] Response Code: 200; Content-Type: text/html; charset=utf-8; Content-Length: unknown
[info] Request took 0.007135s (140.154/s)
.------------------------------------------------------------+-----------.
| Action | Time |
+------------------------------------------------------------+-----------+
| /foobar/index | 0.000181s |
| /end | 0.000179s |
'------------------------------------------------------------+-----------'
Note that Catalyst will call auto actions of all controllers involved, so it will also do the Root controller's auto if there is one in all requests.

Related

Mojolicious - how to intercept the incoming request before controller method handles and renders

In Mojolicious app, I need to figure out which controller method will be handling the incoming request so that I can log details of the remote client and add some logic. I want to do it at only one place and not in every controller methods. I have tried some of the HOOKS but could not figure out. Much appreciate any help on this.
Routes are generated/created from several OpenApi Plugin files and also use Oauth2 Plugin for OAuth.
Mojolicious detail:
CORE
Perl (v5.16.3, linux)
Mojolicious (8.22, Supervillain)
OPTIONAL
Cpanel::JSON::XS 4.04+ (n/a)
EV 4.0+ (4.22)
IO::Socket::Socks 0.64+ (n/a)
IO::Socket::SSL 2.009+ (2.060)
Net::DNS::Native 0.15+ (n/a)
Role::Tiny 2.000001+ (2.000005)
I asked in mojolicious mailing list and got the reply from the creator of the Mojolicious, Sebastian Riedel. Thanks.
For everybody's benifit. $c->match->stack in around_action hook has the info I was looking for.
Here is how:
In your application startup method:
sub startup {
my $self = shift;
...
$self->hook(
around_action => sub {
my ($next, $c, $action, $last) = #_;
use DDP;
p $c->match;
# prints all the info about the controller and the method/action
# it is going to call
...
}
);
...
}
DDP - Output
Mojolicious::Routes::Match {
Parents Mojo::Base
public methods (7) : endpoint, find, has, path_for, position, root, stack
private methods (1) : _match
internals: {
endpoint Mojolicious::Routes::Route,
position 0,
root Mojolicious::Routes,
stack [
[0] {
action "controller_method_name",
controller "ControllerClassName",
handler "openapi",
id 3336,
openapi.object Mojolicious::Plugin::OpenAPI,
openapi.op_path [
[0] "paths",
[1] "/api/endpoint/path/{id}/status",
[2] "get"
],
openapi.parameters [
[0] {
description "job id",
in "path",
name "id",
required JSON::PP::Boolean,
type "number"
}
]
}
]
}
}
Here is the info I am looking for in $c->match->stack:
action "controller_method_name",
controller "ControllerClassName",

Pass parameter through URL in Perl catalyst

Is it possible to pass a parameter through URL in perl catalyst
I have a link
<a href="/vbo/mortgage_reduction/yearly" >Yearly </a>
Can I pass a parameter with the link, like
<a href="/vbo/mortgage_reduction/yearly/1" >Yearly</a>
if so, how can I take the value in the module ?
I have just started learning Catalyst myself, but I can say that seems to be what :Args is for. You specify the number of parameters you need and they are added to #_. I have made this test:
sub test :Local :Args(1) {
my ( $self, $c, $word ) = #_;
$c->response->body($word);
}
and loaded http://localhost:3000/test/hello. This displayed "hello" in the browser and the server output:
[info] *** Request 1 (0.083/s) [14444] [Thu Jun 5 11:29:18 2014] ***
[debug] Path is "test"
[debug] Arguments are "hello"
[debug] "GET" request for "test/hello" from "127.0.0.1"
[debug] Response Code: 200; Content-Type: text/html; charset=utf-8; Content-Length: unknown
[info] Request took 0.00722s (138.504/s)
.------------------------------------------------------------+-----------.
| Action | Time |
+------------------------------------------------------------+-----------+
| /test | 0.000194s |
| /end | 0.000265s |
'------------------------------------------------------------+-----------'
This is documented in Catalyst::Manual::Intro under Action types.
It is also possible for a series of controller methods to examine the same request, each taking a certain number of those "URL parameters", with :CaptureArgs and action chains.

net-snmp perl subagent not being triggered by snmpget

I've been working on a custom SNMP Mib and I've come up against a wall while trying to get an agent to return the proper data.
MIB (validated by running smilint -l 6):
IDB-MIB DEFINITIONS ::= BEGIN
IMPORTS
MODULE-IDENTITY, OBJECT-TYPE, Integer32, enterprises
FROM SNMPv2-SMI
MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF;
idb MODULE-IDENTITY
LAST-UPDATED "201307300000Z" -- Midnight 30 July 2013
ORGANIZATION "*********"
CONTACT-INFO "email: *******"
DESCRIPTION "description"
REVISION "201307300000Z" -- Midnight 29 July 2013
DESCRIPTION "First Draft"
::= { enterprises 42134 }
iDBCompliance MODULE-COMPLIANCE
STATUS current
DESCRIPTION
"Compliance statement for iDB"
MODULE
GROUP testGroup
DESCRIPTION
"This group is a test group"
::= {idb 1}
test2 OBJECT-TYPE
SYNTAX Integer32
UNITS "tests"
MAX-ACCESS read-write
STATUS current
DESCRIPTION
"A test object"
DEFVAL { 5 }
::= { idb 3 }
testGroup OBJECT-GROUP
OBJECTS {
test2
}
STATUS current
DESCRIPTION "all test objects"
::= { idb 2 }
END
Agent file:
#!/usr/bin/perl
use NetSNMP::OID(':all');
use NetSNMP::agent(':all');
use NetSNMP::ASN(':all');
sub myhandler {
my ($handler, $registration_info, $request_info, $requests) = #_;
print "Handling request\n";
for ($request = $requests; $request; $request = $request->next()) {
#
# Work through the list of varbinds
#
my $oid = $request->getOID();
print "Got request for oid $oi\n";
if ($request_info->getMode() == MODE_GET) {
if ($oid == new NetSNMP::OID($rootOID . ".3")) {
$request->setValue(ASN_INTEGER, 2);
}
}
}
}
{
$subagent = 0;
print "Running new agent\n";
my $rootOID = ".1.3.6.1.4.1.42134";
my $regoid = new NetSNMP::OID($rootOID);
if (!$agent) {
$agent = new NetSNMP::agent('Name'=>'my_agent_name','AgentX' => 1);
$subagent = 1;
print "Starting subagent\n";
}
print "Registering agent\n";
$agent->register("my_agent_name", $regoid, \&myhandler);
print "Agent registered\n";
if ($subagent) {
$SIG{'INT'} = \&shut_it_down;
$SIG{'QUIT'} = \&shut_it_down;
$running = 1;
while ($running) {
$agent->agent_check_and_process(1);
}
$agent->shutdown();
}
}
sub shut_it_down() {
$running = 0;
print "Shutting down agent\n";
}
When I run the agent I get the following:
Running new agent
Starting subagent!
Registering agent with oid idb
Agent registered
So I know that much is working. However when I run the following command:
snmpget -v 1 -c mycommunity localhost:161 test2.0
I get this error message:
Error in packet
Reason: (noSuchName) There is no such variable name in this MIB.
Failed object: IDB-MIB::test2.0
I know from snmptranslate that the mib file is set correctly. I have even looked through the debug for snmpget (using -DALL) to make sure that the mib is being loaded and parsed correctly.
So my question is: Why is my subagent not being passed the request?
Update:
I've been told by #EhevuTov that my MIB file is not valid, however smilint does not report any issues and running snmpget -v 2c -c mycommunity localhost:161 .1.3.6.1.4.1.42134.3.0 does report the NAME of the object (IDB-MIB::test2.0) correctly, but does not find any data for it.
I am getting IDB-MIB::test2 = No Such Object available on this agent at this OID, which makes me think that my agent is not registering properly, however it's not throwing any errors.
Update 2:
I've been fiddling around with the agent code a bit. Based on the CPAN documentation (http://metacpan.org/pod/NetSNMP::agent), it looks like the $agent->register function call is supposed to return 0 if successful. So I checked the return code and got this:
Agent registered. Result: NetSNMP::agent::netsnmp_handler_registration=SCALAR(0x201e688)
Printing it out using Data::Dumper results in:
$VAR1 = bless( do{\(my $o = 34434624)}, 'NetSNMP::agent::netsnmp_handler_registration' );
I vaguely understand what bless does, but even so, I have no idea what this result is supposed to mean. So I'm starting to think that the agent is wrong somehow. Does anyone know how to debug these agents? Is there somewhere I can look to see if it's getting loaded properly into the master snmpd?
And I've solved the problem. It wasn't with the MIB, it was with the agent (which I had THOUGHT was working fine the whole time so I never bothered to check it).
I'd been running the agent stand-alone, because it seemed like it was working fine (never threw any errors when registering the handler). Apparently though, it needs to be run directly by snmpd.
I moved it to a directory that snmpd can access (because also apparently snmpd can't run scripts from /root, even though it's running as root), and added these lines in snmpd.conf:
perl print "\nRunning agents now\n";
perl do "/usr/share/snmp/agent.pl" || print "Problem running agent script: $!\n";
perl print "Agents run\n";
Note that these two lines were already present:
disablePerl false
perlInitFile /usr/share/snmp/snmp_perl.pl
I can now run the snmpget command and get the expected response.
> snmpget -v 2c -c mycommunity localhost:161 .1.3.6.1.4.1.42134.3
IDB-MIB::test2 = INTEGER: 2 tests

Mojolicious::Lite with Template Toolkit

I'm trying to get Template Toolkit to work as the default renderer in Mojolicious::Lite. What I have:
use strict;
use warnings;
use Mojolicious::Lite;
use Mojolicious::Plugin::TtRenderer;
plugin tt_renderer => { template_options => { INCLUDE_PATH => './tmpl', DEBUG => 1 } };
get '/' => sub {
my $self = shift;
$self->render( 'index' );
};
app->renderer->default_handler( 'tt' );
app->start;
When I try to hit the test server, I get:
[Fri Oct 12 14:02:02 2012] [info] Listening at "http://*:3000".
Server available at http://127.0.0.1:3000.
[Fri Oct 12 14:02:08 2012] [debug] Your secret passphrase needs to be changed!!!
[Fri Oct 12 14:02:08 2012] [debug] GET / (Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:16.0) Gecko/20100101 Firefox/16.0).
[Fri Oct 12 14:02:08 2012] [debug] Routing to a callback.
[Fri Oct 12 14:02:08 2012] [debug] Nothing has been rendered, expecting delayed response.
This happens regardless of what I pass as parameters to 'render'. I can't seem to figure out how to get any useful debugging information out of this; but I haven't used Mojo before.
I've confirmed by sprinkling in some warn statements that my get handler is being called.
After looking at the source of Mojolicious::Plugin::TtRenderer::Engine, I figured it out. The plugin ignores the INCLUDE_PATH option passed to Template Toolkit, and instead gets the path from $app->renderer_paths. So updating my code to include:
app->renderer->default_handler( 'tt' );
app->renderer->paths( [ './tmpl' ] );
makes it work.

In Specman, why is my macro label for the code body returning garbage?

Similar to this post
http://feedproxy.google.com/~r/cadence/community/blogs/fv/~3/IvdCIla8_Es/extending-multiple-when-subtypes-simultaneously.aspx
I want to make a macro that does loop unrolling to get around some of the when-subtyping and inheritance issues Specman has.
I've started with:
-- macros.e
<'
define <FOREACH_UNROLL'action> "FOREACH_UNROLL (<UNROLLEES>\[<unrollee'name>,...\]) (<STATEMENTS>{<statement>;...})" as computed {
print <UNROLLEES>;
print str_split(<UNROLLEES>,"/ *, */");
for each in str_split(<UNROLLEES>,"/ *, */") {
out(it.as_a(string));
var statements := str_replace( <STATEMENTS>,"\"REPLACE_ME\"",it);
result =appendf("%s %s;",result,statements);
};
};
'>
-- main.e
<'
import macros.e
extend sys {
run() is also {
FOREACH_UNROLL [baz,foo,bar] {
out("REPLACE_ME");
out("part2","REPLACE_ME");
};
};
};
'>
When I run this, I get:
specman -c 'load $HOME/main; test'
Welcome to Specman Elite(64) (08.20.007-s) - Linked on Tue Dec 15 17:07:26
2009
Protected by U.S. Patents 6,141,630 ;6,182,258; 6,219,809; 6,347,388;
6,487,704; 6,499,132; 6,502,232; 6,519,727; 6,530,054; 6,675,138; 6,684,359;
6,687,662; 6,907,599; 6,918,076; 6,920,583; Other Patents Pending.
0 notifications were modified by command 'set notify -severity=WARNING
DEPR_START_TCM_ARG_BY_REF'
Checking license ... OK
Loading macros.e (imported by main.e) ...
read...parse...update...patch...h code...code...clean...
Loading /nfs/pdx/home/rbroger1/main.e ...
read...parse... <UNROLLEES> = "[35]"
str_split(<UNROLLEES>,"/ *, */") =
0. "[35]"
[35]
update...patch...h code...code...clean...
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
REPLACE_ME
part2REPLACE_ME
No actual running requested.
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.
If you look at the printout of <UNROLLEES>:
<UNROLLEES> = "[35]"
Why does <UNROLLEES> give me [35] instead of the body inside the curly braces? 35 is the ascii value for #, so I'm at a loss why I would get a 35...
P.S. I realize macros are from the devil, but I think code copying is worse. I have to do this because Specman isn't really polymorphic.
It turns out I needed to use the function str_expand_dots in my version of Specman (8.2).
Here is the modified macros.e:
define <FOREACH_UNROLL'action> "FOREACH_UNROLL (<UNROLLEES>\[<unrollee'name>,...\]) (<STATEMENTS>{<statement>;...})" as computed {
-- print str_expand_dots(<UNROLLEES>);
--print str_expand_dots(<STATEMENTS>);
-- print str_split(str_expand_dots(<UNROLLEES>),"/ *, */");
for each in str_split(str_expand_dots(<UNROLLEES>),"/ *, */") {
var unrollee := str_replace(it, "[","");
unrollee = str_replace(unrollee, "]","");
--out(unrollee);
var statements := str_replace( str_expand_dots(<STATEMENTS>),"\"REPLACE_ME\"",unrollee);
result =appendf("%s %s;",result,statements);
};
};
Modified main.e:
import macros;
extend sys {
run() is also {
FOREACH_UNROLL ["baz","foo","bar"] {
out("REPLACE_ME");
out("part2","REPLACE_ME");
if "REPLACE_ME" == "baz" {
out("found baz");
};
};
};
};
And the output:
Welcome to Specman Elite(64) (08.20.007-s) - Linked on Tue Dec 15 17:07:26
2009
Protected by U.S. Patents 6,141,630 ;6,182,258; 6,219,809; 6,347,388;
6,487,704; 6,499,132; 6,502,232; 6,519,727; 6,530,054; 6,675,138; 6,684,359;
6,687,662; 6,907,599; 6,918,076; 6,920,583; Other Patents Pending.
0 notifications were modified by command 'set notify -severity=WARNING
DEPR_START_TCM_ARG_BY_REF'
Checking license ... OK
Loading /nfs/pdx/home/rbroger1/macros.e (imported by main.e) ...
read...parse...update...patch...h code...code...clean...
Loading /nfs/pdx/home/rbroger1/main.e ...
read...parse...update...patch...h code...code...clean...
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
baz
part2baz
found baz
foo
part2foo
bar
part2bar
No actual running requested.
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.