Chef multiple level attribute file override with role JSON - json

I have an attributes file that looks like this:
default['ftp_provision']['vsftpd']['pasv_ip'] = "192.168.0.10"
where the first attribute is the cookbook name, the second is the program, and the third is the option I want to change, implemented in a template .erb file as:
pasv_ip=<%node['ftp_provision']['vsftpd']['pasv_ip']%>
This is working correctly as expected.
However, I would like to add a role to change these attributes as required for several nodes. I'm using knife role create ftp_node1 to do that doing something like:
"default_attributes": {
"ftp_provision" => {"ftp_provision" => "vsftpd" => "pasv_ip" => "192.168.0.10"}
},
I keep getting syntax errors. All the examples I've been able to see have referenced making JSON files from Ruby DSL with only one level deep of attributes (e.g. default['key']['value']) so I'd like to know how to do this correctly per role.

you'll need to use actual JSON for this, and not sure what you mean about one level deep. this will create a hash 3 or 4 levels deep, depending on how you count it. i haven't seen issues with going further with attributes, and see many cookbooks in the wild with default['really']['freakin']['long']['strings']['of'] = attributes
i took a look at chef's examples and they're using ruby's hash format there rather than json, and that method of creating hashes makes rubocop squawk and say it's been deprecated. i can certainly see how that example would mislead you.
use a linter when building json, here's one https://jsonlint.com/
also I think this may work for you:
{
"ftp_provision": {
"vsftpd": {
"pasv_ip": "192.168.0.10"
}
}
}

Related

OData: How to add operations for get by id?

My swagger.json on the backend lists two different paths for each operation like so:
"paths": {
"/api/Clients": {
...
"/api/Clients({key}: {"
...
When I try to edit the OpenAPI markup directly and add new path, it says duplicate path.
I also tried adding {key} as an optional parameter to the existing Clients opeartion, but it didnt like being marked optional, but having the value come from the path. From this post it looks like its possible, but I cannot figure out how.
Based on the post that you shared, the recommendation was to use a path like /api/Clients/{key} and then rewrite the URI as required.
To be exact to the recommendation, you could go for /api/{entity}/{key} itself, catching all entities.

Chef - expressions in `kitchen.yml` attributes?

In kitchen.yml, I would like to have an expression in the attributes: part. However it seems it is just a static file with literal values.
Is it somehow possible to have the values in attributes: evaluated?
The reason for that need is that I have some node.defaults in defaults.rb, and some of them are URLs at the same host, say, http:foo.org/service. And in the kitchen.yml I want to parametrize the host. So I would have:
...
attributes: { serviceX_baseURL: "http://bar.org/service" }
I want the override to happen with kitchen_*.yml override and not attributes/*.rb (that would be easier) because the override happens later in the process, after the main kitchen.yml file is already generated.
Any practical solutions for that are welcome.
You can use Erb formatting in the .kitchen.yml for some very simplistic templating, but you didn't really give a concrete example. Chances are you should not do this, generally parameterizing both the code and tests on the same input means the tests are brittle or not testing what you think they are.

Dynamically generating FormFlow from JSON file

I am try to utilize JSON data to dynamically generate a form flow. In the Improved Sandwich Bot, each field in the form flow is independent to each other. For example, no matter I choose what kind of sandwich, I can continue to choose any type of bread. The only way to add some customization is using the following code:
.Field(new FieldJson(schema, "Specials")
.SetType(null)
.SetActive((state) => (string)state["Length"] == "FootLong")
.SetDefine(async (state, field) =>
{
field
.AddDescription("cookie", "FreeCookie")
.AddTerms("cookie", "cookie", "FreeCookie")
.AddDescription("drink", "FreeDrink")
.AddTerms("drink", "drink", "FreeDrink");
return true;
}))
However, since different sandwich stores have different menus, the dependency between different fields varies a lot. For example,
Store A may say only Sandwich1 can have toppings1, 2, 3. And store B
may say only Bread1 can have cheese1, 2, 3.
So I don't want to use the code above to implement the logic. It is not scalable.
So is it possible to include those dependency relations in the JSON file? In that way, the form builder can directly build the form flow with certain dependency relation.
No, it's not possible at this point but it seems like a very good suggestion. You can give the feedback at https://feedback.botframework.com/.

In CouchDB how do you take in parameters from REST call

Hi so I'm new to CouchDB looks great so far, but really struggling with what must be simple to do!
I have documents structured as:
{
"_id" : "245431e914ce42e6b2fc6e09cb00184d",
"_rev": "3-2a69f0325962b93c149204aa3b1fa683",
"type": "student",
"studentID": "12345678",
"Name": "Test",
"group: "A"
}
And would like to access them them with queries such as http://couchIP/student?group=A or something like that. Are Views what I need here? I don't understand how to take the parameter from the query in the Map functions in Views. example:
function(doc,req) {
if(req.group==='A'){
emit(doc.id, doc.name);
}
}
Is my understanding of how Couch is working wrong or what's my problem here? Thanks in advance, I'm sure this is Couch 101
Already read through http://guide.couchdb.org/ but it didn't really answer the question!
You need views to achieve the desired results.
Define the following map function inside a view of a design document. ( let's name the view "byGroup" and assume this lives in a design document named "_design/students" )
function(doc) {
if(doc.group){
emit(doc.group,null);
}
}
Results can be obtained from the following url
http://couchIP:5984/dbname/_design/students/_view/byGroup?startkey="A"&endkey="A"&include_docs=true
To have friendly url couchdb also provides url rewriting options.
You need to some further reading about views and the relevance that they return key/pair values.
It's not clear what you want to return from the view so I'll guess. If you want to return the whole document you'd create a view like:
function (doc) { emit(doc.group, doc) };
This will emit the group name as a key which you can lookup against, the whole doc will be returned as the value when you look it up.
If you want to just have access to the names of those users you want to do something like:
function (doc) { emit(doc.group, doc.name) };
Your question arises from a misconception about what a view does. Views use map/reduce to generate a representation of your data. You have no control of the output of your view in your query because the view is updated according to changes in your DB documents only.
Using a list is also not a good option. It may seem that you can use knowledge of your request in your list to generate a different output depending on the query parameters but this is wrong because couchdb uses ETags for caching and this means that most times you will get the same answer regardless of your list parameters since the underlying documents won't have changed. There is a trick though to fool couchdb in this case and this implies using two different alternating users but I wouldn't even try this way because surely there are easier ways to achieve your objectives and you can probably solve your problem using group as a key in your map function.

Parse and change elements from database to the XML file

I got XML items.xml file with (almost) the same values as my items table has, I mean fe. there is a field in the items table: level and for any id the level is set to 144, but in the XML file, the level= attribute is set to "1" (for the same id) - what is the best way to correct values like this?
It should go like this:
Check value level in the database table for any id.
If the level value from the database is other than the level="" attribute for this ID, set it to the same level value as in the
database.
It can be kinda hard, since there is about ~40000 records to check.
I will appreciate some examples also!
Depending on what programming-language you are using, find the corresponding StAX-implementation. For Java I would go with XMLStreamReader (JavaDocs) and XMLStreamWriter (JavaDocs). You should find some tutorials on the internet.
When you encounter the START_ELEMENT event while reading the XML, check the tag's name (getLocalName()). If you are on the correct tag, check for the attributes, i.e. using the getAttribute...()-methods and handle the writing differently.
Along all of this, use an XMLStreamWriter to write your new XML to some OutputStream. After all, just write the OutputStream to whereever you wish (File, etc.).
Don't forget to read your Input-XML using a BufferedInputStream (or some other buffered way).
Good luck!
P.S.: You can also use XMLEventReader or XMLEventWriter, but personally I prefer XMLStreamReader / XMLStreamWriter. Also, you could use different StAX-Implementations like Woodstox.
P.P.S.: For PHP use XMLReader and XMLWriter. See here.