我是厨师环境的新手。并制作一本简单的食谱。
为了简化,我有以下属性:
属性/ default.rb:
default[:user1] = ""
default[:user2] = ""
default[:filename] = ""
食谱/ default.rb: 在运行时,我从另一本食谱中获取文件名,我必须从该文件中提取用户。
file = "#{node[:filename]}"
ruby_block 'extract userdata' do
block do
json = File.read(file)
obj = JSON.parse(json)
userdata = obj['users']
if userdata.empty?
raise "Errors: userdata not available"
else
node.override[:user1] = userdata['user1']
node.override[:user2] = userdata['user2']
end
end
puts "user1: #{node[:user1]}"
puts "user2: #{node[:user2]}"
action :run
end
在运行时从块上面记录(puts)会正确地获取用户名。
现在,我正在尝试使用上面两个更新的属性,如下面的菜谱配方。
user1 = #{node[:user1]}
user2 = #{node[:user2]}
但是这两个值都是空的,好像它们没有设置/覆盖一样。
请建议我如何获取最新数据。
答案 0 :(得分:2)
我将总结以下答案(其中给出了关于同一问题的另一种观点),并举例说明了您的具体案例。
这里的问题是compile time versus converge time
这里发生的是在编译时评估配方和资源,并在收敛时评估ruby_block
资源的内容。
有两种解决方案可以解决这个问题:
第一个选项是在编译时运行ruby_block:
ruby_block 'extract userdata' do
block do
json = File.read(file)
obj = JSON.parse(json)
userdata = obj['users']
if userdata.empty?
raise "Errors: userdata not available"
else
node.override[:user1] = userdata['user1']
node.override[:user2] = userdata['user2']
end
end
puts "user1: #{node[:user1]}"
puts "user2: #{node[:user2]}"
action :nothing
end.run_action(:run)
注意action :nothing
以避免资源在收敛时间执行,.run_action(:run)
告诉评估在评估后立即运行该资源。
第二个选项是在其他资源中使用lazy evaluation:
execute "Do something" do
command lazy { "/path/command #{node['user1]}" }
end
lazy {}
必须包含整个属性值,而不仅仅是变量,否则会引发错误。
我建议尽可能多地使用选项2。在编译时执行操作可能会导致难以理解何时出错,因为操作是在两个不同的流程中进行的。
我建议使用字符串来访问节点属性,在固定文本时单引号,在需要插值时双引号,因为符号可能会在属性名称与配方DSL名称空间中的现有符号匹配时获得意外行为。
答案 1 :(得分:0)
在覆盖/设置新值到代码块中的属性后尝试添加 public class NotificationService extends Service
{
ConnectionFactory factory = new ConnectionFactory();
Connection connection;
Channel channel;
String HostName = "192.168.2.11";
String UserName = "o";
String Password = "m";
public void onCreate()
{
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
String qName="0833";
String routeKey="0833";
new AsyncSubscribe().execute(qName, routeKey);
return Service.START_STICKY;
}
@Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
@Override
public IBinder onBind(Intent intent)
{
return null;
}
private class AsyncSubscribe extends AsyncTask<String, Void, Void> {
Consumer consumer;
ArrayList<String> messages = new ArrayList<String>();
@Override
protected void onPreExecute() {
}
@Override
protected Void doInBackground(String... params) {
try {
consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
properties.builder().deliveryMode(2);
// here we add messages to arraylist
messages.add(new String(body, "UTF-8"));
}
};
channel.basicConsume(params[0], true, consumer);
}
catch ( Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
// here we show arraylist size
Toast.makeText(NotificationService.this, Integer.toString( messages.size()), Toast.LENGTH_SHORT).show();
try {
channel.close();
connection.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
public void SubscribeSet() {
try {
factory.setHost(HostName);
factory.setUsername(UserName);
factory.setPassword(Password);
connection = factory.newConnection();
channel = connection.createChannel();
}
catch ( Exception e)
{
e.printStackTrace();
}
}
}
。
node.save