How to create a Dataflow Template without running code? - google-cloud-platform

I am creating a Dataflow template that runs perfectly if I pass all required parameters but my use case is to create a Generic Template where I can pass parameters at Runtime.
All my options are ValueProvider but still, it is trying to execute the code while creating the template and that gives an error. Is there any way I can create a Dataflow template without executing code?
I have also faced one weird issue when I use create template command along with all the parameters then it creates the template successfully but at that time all parameters get hard coded in the code and if I pass the new parameter value while running it does not change the value with the template.
Is it the correct behavior of the Dataflow template?
Command without passing all parameters :
mvn compile exec:java -D"exec.mainClass"="org.example.Main" -D"exec.args"="--runner=DataflowRunner --project=<project> --stagingLocation=gs://test-bucket/staging_4 --templateLocation=gs://test-bucket/templates/my_template --region=asia-south1 " -P dataflow-runner -X

After designing my code multiple times, I got to know what mistake I was doing.
What I got to know is that your code should be designed in such a way that it will not ask for any value for generating the Graph except Project Id, Stage Path, and Template Path. if it is asking then check the below practices and design accordingly.
Following are the practice you should follow if you are creating Custom Template.
1.Declare all the options as ValueProvider so that it will be calculated at Run Time and the Template creation process will skip it.
2.Do not assign the ValueProvider value to the normal variable as below.
String Query = options.getQuery().toString();
PCollection<TableRow> rows = p.apply("Read From Source", JdbcIO.<TableRow>read()
.withQuery(Query)
3.Try to pass ValueProvider value directly to the method. For example above code snippet should be like below
PCollection<TableRow> rows = p.apply("Read From Source", JdbcIO.<TableRow>read()
.withQuery(options.getQuery())
4.Do not use options only inside any one particular block of code which is never accessible during Template creation. As below example.
Boolean Check = false;
if (options.getA().isAccessible()){
Check = true;
}
if (Check == true){
//Use of Options.getB().
}
In the above case if you are not pass --a option while creating a template then the Check value will always false and a particular below block of code will not be executable. If we are not using --b out of Check block then after the creation of Template options b will be unknown to Template and it will give an error if you pass it at Run time.
5.If you have use case where you need to manipulate data of input options passed then you should use NestedValueProvider instead of converting ValueProvider into a Normal variable such as String and manipulate data.
Fo example, avoid the below practice.
String Query = String.format("SELECT * FROM %s", options.getTableName().toString());
PCollection<TableRow> rows = p.apply("Read From Source", JdbcIO.<TableRow>read()
.withQuery(Query)
Instead implement same logic as below:
ValueProvider<String> Query = NestedValueProvider.of(options.getTableName(),
new SerializableFunction<String, String>() {
#Override
public String apply(TranslatorInput<String, String> input)
{
return String.format("SELECT * FROM %s", input);;
}
});;
PCollection<TableRow> rows = p.apply("Read From Source", JdbcIO.<TableRow>read()
.withQuery(Query)

Use FlexTemplates instead. Documentation can be found here.

Related

Changing model parameters by cPar in other module

I am using this module hierarchy :
Node: {udpApp[0]<->udp<->networkLayer->wlan[0]} and wlan[0]: {CNPCBeacon<->mac<->radio}
I have given some initial parameter in the ini file for udpApp as :
**.host*.numUdpApps = 2
**.host*.udpApp[0].typename = "UDPBasicApp"
**.host*.udpApp[0].chooseDestAddrMode = "perBurst"
**.host*.udpApp[0].destAddresses = "gw1"
**.host*.udpApp[0].startTime = 1.32s
**.host*.udpApp[0].stopTime = 1.48s
But at run time I want to change the startTime and stopTime for udpAPP[0] through CNPCBeacon module. Hence I changed CNPCBeacon.cc as:-
cModule* parentmod = getParentModule();
cModule* grantParentmod = parentmod->getParentModule();
cModule* udpmod;
for (cSubModIterator iter(*grantParentmod); !iter.end(); iter++)
{
//EV<<"get the modulde "<< iter()->getFullName()<<endl;
if (strcmp(iter()->getFullName(), "udpApp[0]") == 0)
{
udpmod = iter();
break;
}
}
cPar& startTime = udpmod->par("startTime");
cPar& stopTime = udpmod->par("stopTime");
And I am successfully able to receive the values of startTime and stopTime. However I want to change these value in current module, which is resulting in an error by following code:
udpmod->par("startTime").setDoubleValue(4.2);
Can anybody please suggest me a way to change it at run time.
Declaring your parameter as volatile should solve your problem. But for future reference I'll provide further explanation below
Volatile vs. non-volatile:
Here it depends how you want to use this parameter. Mainly via the .ini file you have two types of parameters: volatile and non-volatile.
volatile parameters are read every time during your run. That woule be helpful if you want this parameter to be generated by a built-in function, for example, uniform(0,10) each time this volatile parameter will get a different value.
On the other hand non-volatile parameters are read just one, as they don't change from run to run.
Using the volatile type parameter does not give you full flexibility, in the sense that your parameter value will always fall with in a range predefined in the .ini
Dynamic Variable (parameter) Reassignment:
Instead what you could do is use a more robust approach, and re-define the variable which stores the value from that module parameter each time you have to do so.
For example in your case you could do the following:
varHoldingStartTime = par("startTime").doubleValue();
varHoldingStartTime = 4.2;
This way the actual value will change internally without reflecting to your run.
Parameter Studies:
Alternatively if you want this change of the parameter to be applied to multiple runs you could use the advanced built-in approach provided by OMNeT++ which allows you to perform Parameter Studies.
I have explained here how Parameter Studies work: https://stackoverflow.com/a/30572095/4786271 and also here how it can be achieved with constraints etc: https://stackoverflow.com/a/29622426/4786271
If none of the approaches suggested by me fit your case, answers to this question altogether might solve your problem: How to change configuration of network during simulation in OMNeT++?
EDIT: extending the answer to roughly explain handleParameterChange()
I have not used handleParameterChange() before as well, but from what can I see this function provides a watchdog functionality to the module which utilizes it.
To activate this functionality first the void handleParameterChange(const char *parameterName); has to be re-defined.
In essence what it seems to do is the following:
Assume we have two modules moduleA and moduleB and moduleB has parameter parB. moduleA changes the parB and when that happens, moduleB reacts to this change based on the behaviour defined in:
moduleB::handleParameterChange(parB);
The behaviour could be re-reading the original value for parB from the .ini etc.

Error - Cannot access display string yet for new node creation in Omnet

I am trying to create a node at run time in my module in Omnet. I am able to create it with this code and its working fine.
cModule* parentmod = getParentModule();
cModule* grantParentMod = parentmod->getParentModule();
cModule* grantParentMod1 = grantParentMod->getParentModule();
// To check if the module is already created
for (cSubModIterator iter(*grantParentMod1); !iter.end(); iter++)
{
EV << iter()->getFullName()<<endl;
if (iter()->getFullName() == "host_send4")
return;
}
cModuleType *meshnode1 = cModuleType::get("inet.networklayer.manetrouting.PASER.meshnode");
cModule *mod = meshnode1->create("host_send4", grantParentMod1);
cDisplayString& dispstr = getDisplayString();
dispstr.parse("p=1000,535;r=200,green");
mod->finalizeParameters();
mod->buildInside();
mod->scheduleStart(simTime()+2*beaconInterval);
However this module is not generated at desired place in simulation output (the coordinates and the display). I believe the display string created here is not attached to the module and hence I tried to do it by this :-
cDisplayString& dispstr = getDisplayString();
dispstr.parse("p=1000,535;r=200,green");
mod->getDisplayString().set(dispstr);
But with this I encounter following error at run time :- Cannot access display string yet: Parameters not yet set up . I know the problem is in mod->getDisplayString().set(dispstr);
So is there any other way to assign the parameter or am I doing some minor error.
Thanks for this help.
Make sure you are following the module creation procedure as given in the OMNeT++ manual.
If you navigate to the The Detailed Procedure sub-section you will notice a comprehensive list which tells what step should be performed where:
Find the factory object;
Create the module;
Set up its parameters and gate sizes as needed;
Tell the (possibly compound) module to recursively create its internal submodules and connections;
Schedule activation message(s) for the new simple module(s).
Step 3 I believe is the one you are looking for. Little below is given a detailed explanation of what should be done for step 3:
If you want to set up parameter values or gate vector sizes (Step
3.), the code goes between the create() and buildInside() calls:
// create
cModuleType *moduleType = cModuleType::get("foo.nodes.WirelessNode");
cModule *module = moduleType->create("node", this);
// set up parameters and gate sizes before we set up its submodules
module->par("address") = ++lastAddress;
module->finalizeParameters();
module->setGateSize("in", 3);
module->setGateSize("out", 3);
// create internals, and schedule it
module->buildInside();
module->scheduleStart(simTime());
Be aware of the usage of the module->par("<parameter_name>") function.
PS: I was writing my answer, and in meanwhile you answered your own question. This answer can be left there for future reference, if useful.
Well I modified the code as :-
cModuleType *meshnode1 = cModuleType::get("inet.networklayer.manetrouting.PASER.meshnode");
cModule *mod = meshnode1->create("host_send4", grantParentMod1);
mod->finalizeParameters();
std::string displayString = "p=1000,535;r=200,green;i=device/smallrouter";
mod->getDisplayString().parse(displayString.c_str());
mod->buildInside();
mod->scheduleStart(simTime()+2*beaconInterval);
and then its working perfect. According to my understanding, I should add mod->finalizeParameters(); before changing the display setting and display string should be a simple string but not the cDisplayString object.

ADO Command saying that I am inserting NULL, when I'm not

I'm using ADO to communicate with my Sybase server..
This is how I'm executing a simple command:
_ConnectionPtr m_ConnPtr;
//... Instantiate connection
_CommandPtr m_CommPtr;
m_CommPtr->CreateInstance(__uuidof(Command))
m_CommPtr->ActiveConnection = m_ConnPtr;
Variant m_variant;
m_variant.SetString("My Param Value");
_ParameterPtr ParamPtr;
ParamPtr = m_CommPtr->CreateParameter("#StrParam", (DataTypeEnum) m_variant.vt, adParamInput, NULL, m_variant);
m_CommPtr->Parameters->Append(PrmPtr);
m_CommPtr->CommandText = "EXECUTE my_stored_procedure #StrParam";
m_CommPtr->Execute(NULL, NULL, adOptionUnspecified);
#StrParam is supposed to be a VarChar type..
Running this gives me an error:
Attempt to insert NULL value into column 'StrParam'. table 'MYTABLE';
column does not allow nulls. Update fails.
I'm not sure why I'm getting this error, since I am specifiying its value ("My Param Value")..
Does anyone know what I'm doing wrong?
(I didn't include the Stored procedure,, because I'm sure there's nothing wrong with the procedure itself.. Other application using the same procedure works fine. So there must be something wrong with how I'm using the parametized command)
I have no clue what your Variant class even is. But the traditional variant type (vt) and the ADO data type are not synonymous. Second, you're not setting up the call nor parameters correctly for a typical stored-proc invoke.
Below is how you would do this using a standard stored proc call and variant_t from the comutil library:
_CommandPtr m_CommPtr(__uuidof(Command));
m_CommPtr->ActiveConnection = m_ConnPtr;
m_CommPtr->CommandType = adoCmdStoredProc;
m_CommPtr->CommandText = L"my_stored_procedure";
// setup parameter
variant_t vParam = L"My Param Value";
_ParameterPtr ParamPtr = m_CommPtr->CreateParameter(L"#StrParam", adBSTR, adParamInput, 0, vParam);
m_CommPtr->Parameters->Append(ParamPtr);
m_CommPtr->Execute(NULL, NULL, adOptionUnspecified);
Note that the ParamPtr is generally optional and you can straight-away append the parameter to the command's Parameters collection if you don't need it for anything else, like this:
m_CommPtr->Parameters->Append(m_CommPtr->CreateParameter(
L"#StrParam", adBSTR, adParamInput, 0, vParam));
The method you're using is common for parameters that are both input and output, as you retain the parameter object reference to extract the output side of the parameter. I see no evidence of that in your call, which is the only reason I mention it here.
Also note that unless the command returns rows for a result set you should also invoke with adExecuteNoRecords for the execution third option (which is typical for many fire-and-forget stored procedure executions)
Finally, the names of the parameters are not important unless you use the NamedParameters property of the command object. This is commonly done when you have additional parameters with default values that you would like to retain, setting only specific parameters as part of your append list.
Best of luck.

Request context in a Go template

I would like to write such a conditional fragment in a Go HTML template :
{{if isUserAdmin}}
<a href"/admin/nuke">Go to the big red nuclear button</a>
{{end}}
However, this is not directly possible because the template is not aware of the request that triggered its execution, so it cannot determine if the user is admin or not.
Is there some normal way to achieve this ?
In advance I point out that :
I do not want to use Pipelines for this specific data (see other question about this)
I acknowledge that only the handlers/controllers should deal with logic, and views should only do the rendering. But the condition {{if isUserAdmin}} is not logic itself, it's a necessary construct to leverage a boolean value already calculated by the controller.
The Funcs method can help, but is currently not lean enough for easily defining specific method isUserAdmin()
I would agree with Darshan Computing, I think the proper way of passing information from the request would be in the pipeline. You can have your data being split between the data you want to render and the context, e.g. by having your template data structure embed them both if you want to clearly separate the two:
type TemplateData struct {
*Content
*Context
}
Which gives this for example. You can then reuse some of your context/content information depending on what is shared and what is query specific.
Here is a working solution attempt (link to Playground) using Funcs to overwrite "isAdmin", after template compilation but before each execution (thanks to Valentin CLEMENT in other question).
But it has several flaws :
It is weird to declare a dummy empty "isAdmin" function before template compilation.
(Using Funcs several times is painful because I cannot just overwrite a single method, I have to provide a complete FuncMap with all the functions) edit : in fact previous funcs are not lost, i was wrong about that.
It is inherently not thread-safe and will fail when several goroutines alter and execute the same template
The normal thing to do is to simply pass your template a struct with whatever static data you like. Unless I've misunderstood what you're trying to do, there doesn't seem to be any need for Funcs here. Simplifying your example:
package main
import (
"html/template"
"os"
)
const hometmpl = `
{{if .IsAdmin}}
Go to the big red nuclear button
{{end}}
`
var t = template.Must(template.New("home").Parse(hometmpl))
func isAdmin(token string) bool {
const adminToken = "0xCAFEBABE"
return token == adminToken
}
func main() {
token := "0xCAFEBABE" // Or extracted from the http.Request
t.ExecuteTemplate(os.Stdout, "home", struct{IsAdmin bool}{isAdmin(token)})
}

A few questions about CodeSmith

I have recently started studying CodeSmith and I have a few questions.
I would like to make a template with 4 blocks.
Each block will be selected by the user.
How can I set the text block
(function) to selecting user?
How can I move blocks in separate
files?
For example there is a template
using System;
public class Hello3
{
public static void Main(string[] args)
{
Blocl 1
Blocl 2
Blocl 3
Blocl 4
}
}
Each of these blocks should be selected by the user. Each block is stored in a separate file.
Each block is a function. The output of one block enters to the input of another block.
P.S. Sorry for my bad english.
You could use a string property to set the name of a template or generated value. Then you would just render this string content during generation time.
Another option would be to create an enum that names different Code Blocks. Then inside of your template you could render a sub template or return some static text.
You could also create a custom dropdown list that allows you to choose a CodeSmith template. All of this logic would need to happen in a UITypeEditor and you would need to return a CodeTemplate using the API. This is a lot tougher than the first or second option.
I don't know how to do it using CodeSmith, but you would be better off using a "building-blocks" approach. AtomWeaver offers a way to build a code generator by smaller parts, called "Atoms". These Atoms are Templates that you can combine together.
In you case, I would build an Atom Template called cs_class:
The Template's Exec Code would be:
code([[
using System;
public class Hello3
{
public static void Main(string[] args)
{
{{code_blocks}}
}
}
]])
Notice the {{code_blocks}} marker. Another Template will put some code there.
Then, create the cs_code_block Atom Template. Use this code:
For the Admin Section:
under("cs_class")
For the Exec Section:
cursor("code_blocks")
code([[
<put user code here>
]])
The under() command helps you build an interactive modeling environment in AtomWeaver. Now, your user can create a model with one cs_class Atom, and then he can add as many cs_code_block Atoms as he wish. Executing the model will generate the desired code.
AtomWeaver lets you evolve your models and code generators. It's easy to start with a few lines and then grow it to obtain complete generators.
I know this is a very, very simplistic example of what you can build with AtomWeaver, but it's just to give you a quick idea of what you can accomplish.