create directory with timestamp in chef - ruby

I want to create a directory from chef recipe to backup my existing artifacts. i want to create the backup directory with following format.
appname_bkp_17-10-11-125845
for example I need to create this directory and add the directory name into a variable which is something like;
bkp_dir_name = appname_bkp_17-10-11-125845
Please advice.

While Chef is a DSL, it is still first and foremost pure Ruby. You should try to learn a little about Ruby basics before committing to Chef entirely, because a lot of what you might want to do will be more efficient if you know the language.
time = Time.now.strftime("%F-%T").gsub(':','')
dir = "appname_bkp_#{time}"
path = ::File.join(node['default']['default_backup_path'], dir)
# Chef resource to create a directory with default properties
directory path

Related

How to set dynamic variable once it is identified to all recipes in a cookbook

I need a help to set a global variable in chef recipes.
I have below series of recipes:
Discovers the tomcat from path variable/attibutes/default.rb:
default['tomcat_cookbook']['tomcathome']="['/home/tomcat','/home/ApacheTomcat']"
This recipe will identify the tomcat installation as either one of the directory will be available on server out of this two directories.
Lets say, if it sets the tomcathome to directory "/home/tomcat", I have some more subsequent recipes like start/stop/restart tomcat.
Currently for every recipe I am running discovery logic inside stop/start recipes while knowing that on a particular server, tomcathome is set to "/home/tomcat" .
Is there any way I can remove duplicate code for tomcat home discovery and make use of the identified tomcathome variable for remaining recipes.
Please suggest.
I think this would be a good use of libraries. I'll assume the cookbook name is tomcat_cookbook. In the libraries folder in a cookbook, create a file called path.rb.
Add the following code into the path.rb file. I prefer to namespace my libraries to organize my methods using CookbookName::ModuleName format.
libraries/path.rb:
module TomcatCookbook
module Path
def install_path
node['tomcat_cookbook']['tomcathome'].each do |path|
return path if ::Dir.exist?(path)
end
end
end
end
Within any recipe, you can include this module and use the methods in it:
# Use this include for use in the recipe
Chef::Recipe.send(:include, TomcatCookbook::Path)
# Use this include for using methods in the directory resource itself
Chef::Resource::Directory.send(:include, TomcatCookbook::Path)
Chef::Log.info("Install Path: #{install_path}")
directory "tomcat_install_path" do
path install_path
action :create
end
In certain situations, I have needed to create a common cookbook which includes only libraries which I can use across multiple cookbooks.

Data versioning of "Hello_World" tutorial

i have added "versioned: true" in the "catalog.yml" file of the "hello_world" tutorial.
example_iris_data:
type: pandas.CSVDataSet
filepath: data/01_raw/iris.csv
versioned: true
Then when I used
"kedro run" to run the tutorial, it has error as below:
"VersionNotFoundError: Did not find any versions for CSVDataSet".
May i know what is the right way for me to do versioning for the "iris.csv" file? thanks!
Try versioning one of the downstream outputs. For example, add this entry in your catalog.yml, and run kedro run
example_train_x:
type: pandas.CSVDataSet
filepath: data/02_intermediate/example_iris_data.csv
versioned: true
And you will see example_iris.data.csv directory (not a file) under data/02_intermediate. The reason example_iris_data gives you an error is that it's the starting data and there's already iris.csv in data/01_raw so, Kedro cannot create data/01_raw/iris.csv/ directory because of the name conflict with the existing iris.csv file.
Hope this helps :)
The reason for the error is that when Kedro tries to load the dataset, it looks for a file in data/01_raw/iris.csv/<load_version>/iris.csv and, of course, cannot find such path. So if you really want to enable versioning for your input data, you can move iris.csv like:
mv data/01_raw/iris.csv data/01_raw/iris.csv_tmp
mkdir data/01_raw/iris.csv
mv data/01_raw/iris.csv_tmp data/01_raw/iris.csv/<put_some_timestamp_here>/iris.csv
You wouldn't need to do that for any intermediate data as this path manipulations are done by Kedro automatically when it saves a dataset (but not on load).

Reuse template across different recipes

I have a Chef cookbook with many recipes that have the same code, beside other particular things.
template 'stack_file' do
local true
source File.join(base_dir, 'stack_templates/admin.yml.erb')
path File.join(base_dir, 'stacks/admin.yml')
variables(context)
end
template 'settings_file' do
sensitive true
local true
source File.join(base_dir, 'config_templates/settings_admin.yml.erb')
path File.join(base_dir, 'configs/settings_admin.yml')
variables(context)
end
Is it possible to somehow put this code in a method that I would call with my source_file, destination_file and variables?
I guess you can write a module and include it in your recipes as you do in plain Ruby.
module StackFile
...the code you want to share...
end
Then you can use:
inlclude StackFile
or
Chef::Recipe.send(:include, StackFile)
or when using *_if conditions
Chef::Resource.send(:include, StackFile)
Do this:
create new cookbook.
don't create recipes in it, but instead create a resource
you can define any parameters (inputs like source file, dest file etc like you mentioned)
add your templates to the new cookbook.
in your other cookbooks, create dependency to the previously created cookbook. This will enable you to call the resource you created there (remember that when you call resource from another cookbook and it is creating templates, it will try to take the template file from the current cookbook and not the one where the resource is defined. That is why you need to specify cookbook name when creating template (in the shared cookbook's resource) - see cookbook attribute of https://docs.chef.io/resource_template.html)
Repeat for any number of cookbooks.

Specifying index path with Hibernate Search and Spring

I have problem setting the correct path for my index. It would be great if it was inside my spring application, since it would work even after I deploy my application to Cloudbees I guess.
This is my obejct that I trying to index:
#Entity
#Table(name="educations")
#Indexed(index="educations")
public class Education {
I have the following in servlet-context.xml:
<resources mapping="/resources/**" location="/resources/"/>
I specify the lucene index path like this:
Properties props = new Properties();
props.put("hibernate.search.default.indexBase", "resources/lucene/indexes");
entityManagerFactory.setJpaProperties(props);
Which doesnt give me any error but I cant find the folder either, which I dont understand. I tried searching for it.
I also tried:
props.put("hibernate.search.default.indexBase", "classpath:/lucene/indexes");
and
props.put("hibernate.search.default.indexBase", "/resources/lucene/indexes");
But still cant find the folder. However after a while of struggling with this I try to put it in my home directory. (which might give me problem later when deploying to the cloud):
props.put("hibernate.search.default.indexBase", "/lucene/indexes");
I getting the following
Cannot write into index directory: /lucene/indexes for index educations
So I assume its a permission error. I try the following in terminal (OSX):
sudo chmod -R u+rwX /lucene/indexes/
and
sudo chmod -R 755 /lucene/indexes/
But still the same error. Can someone spread some light on this?
Thank you!
Edit:
After some more investigation I am sure it is a problem of permissions. If I specify the full path to my root of the Spring application, it works. I still don't know how to specify this without giving it the full path.
Relative paths are relative to the directory the Java process is launched from. If you have some startup script or similar look in the directory of this script. Absolute paths work fine, but of course you need permissions to write to it.
If you want a more generic solution for your case, you could for example set the right directory as a system property when starting the application and read it from there when creating your Properties. Or you try in another way to determine the full path of your app at runtime.
I couldn't find where the folders were located either so i came up with the following solution:
First i get the location of the working directory by calling System.getProperty("user.dir"). This is OS independent so it works both on linux and windows. The working directory is the directory from which your application is loaded. Next i simply append the relative path that i want as a location for my lucene indexes to the working directory folderpath. Then i use that as the value for hibernate.search.default.indexBase. Now i'll always know where to look for the lucene indexes.
Heres the code:
String luceneFilePath = System.getProperty("user.dir") + "/resources/lucene/indexes";
Properties props = new Properties();
props.put("hibernate.search.default.indexBase", luceneFilePath);
entityManagerFactory.setJpaProperties(props);

Chef-solo: deploy: access to release_path

I have following Chef cookbook:
deploy "/home/prj" do
repo "https://path_to_repo"
user node.project_owner
group node.project_owner
symlink_before_migrate({})
end
How can I access to the provider's release path? In my case in will be: /home/prj/releases/20120506125222/ .
It depends on where you want to access the release path. "Inside" the resource, i.e. the callbacks, that's easily possible using something iike
deploy "/home/prj" do
before_migrate do
gemfile = File.read("#{release_path}/Gemfile")
end
end
Outside of the resource, you don't have the release_path variable available. You can however use the current symlink which points to the currently deployed version, i.e. the last release:
current_path = "home/prj/current"
release_path = File.readlink(current_path)
Most of the time, you can to things directly in the current_path without having to resort to resolving the symlink target.
That said, you typically don't want to actually do things in there directly. Instead, you are encouraged to generate additional files in the shared directory (i.e. /home/prk/shared) and let chef symlink those files into the release during deployment. That's exactly what symlink_before_migrate is for. That way, you don't need to actually know the release path yourself but can let chef handle that for you.

Resources