I am currently trying to convert a ruby script to rust, but I'm facing some errors with the conversion of for each loops, and my use of HashMaps. I would greatly appreciate some help(I am going to post quite a bit of code, but it's mainly just context).
Ruby Code:
file = File.open("aws_instances", "rb")
tag_file = File.open("aws_tags.sh", "wb")
instances = file.read
instances_list = JSON.parse(instances)
ec2 = {}
usedtypes = {}
untagged = Array[]
instances_list["Reservations"].each do |reservation|
reservation["Instances"].each do |instance|
next if instance["InstanceLifecycle"] == "spot"
name = ""
az = instance["Placement"]["AvailabilityZone"]
type = instance["InstanceType"]
eol = ""
if instance.has_key?("Tags")
instance["Tags"].each do |tag|
name = tag["Value"] if tag["Key"] == "Name"
end
instance["Tags"].each do |tag|
eol = tag["Value"] if tag["Key"] == "upl_expected_eol"
end
has_tag = 0
instance["Tags"].each do |tag|
if tag["Key"] == "stack"
has_tag = 1
break
end
end
if has_tag == 0
untagged.push(name)
end
layer_name = nil
instance["Tags"].each do |tag|
if tag["Key"].start_with?('opsworks:layer:')
layer_name=tag["Value"]
tag_file.write( "#{$awscmd} ec2 create-tags --region us-west-2 --resources #{instance["InstanceId"]} --tags Key=opsworks:layer,Value='#{layer_name}'\n")
end
end
end
key = type # + "/" + az
ec2[key] = [] if ec2.has_key?(key) == false
if usedtypes.has_key?(key) == false
usedtypes[key] = "1"
#puts "used type #{key}"
end
if eol == ""
ec2[key] << "#{name}"
else
ec2[key] << "#{name}:*#{eol}*"
end
end
end
tag_file.close
The script essentially opens some files, reads them, JSON parses it, and then loops through the file.
My rust code:
// Open aws_instances
file = File::open("aws_instances").expect("File can't be opened.");
// Open aws_tags
let mut tag_file = File::open("aws_tags.sh").expect("File can't be opened.");
// Read aws_instances
let mut instances = String::new();
file.read_to_string(&mut instances).expect("File can't be read");
// Parse aws_instances as JSON
let instances_list: serde_json::Value =
serde_json::from_str(&instances).expect("Json was not well formatted.");
// Create a new HashMap
let mut ec2 = HashMap::new();
let mut usedtypes = HashMap::new();
//Create a new Vector
let mut untagged = Vec::new();
for reservation in instances_list.get("Reservations"){
for instance in reservation.get("Instances"){
if instance["InstanceLifecycle"] == "spot"{
continue;
}
let mut name = "";
let mut az = &instance["Placement"]["AvailabilityZone"];
let mut r#type = &instance["Type"];
let mut eol = "";
if let Some(key) = instance["Tags"].as_str(){
for tag in instance.get("Tags").iter(){
if tag["Key"] == name{
name = tag["Value"].as_str().unwrap_or("");
println!("{:?}", name);
}
}
for tag in instance.get("Tags").iter(){
if tag["Key"] == "upl_expected_eol"{
eol = tag["Value"].as_str().unwrap_or("");
println!("{:?}", eol);
}
}
let mut has_tag = 0;
for tag in instance.get("Tags").iter(){
if tag["Key"] == "stack"{
has_tag = 1;
break;
}
}
if has_tag == 0{
untagged.push(name);
}
let mut layer_name;
for tag in instance.get("Tags").iter(){
if tag["Key"].starts_with("opsworks:layer:"){
layer_name = &tag["Value"];
let data = ("aws ec2 create-tags --region us-west-2 --resources {} --tags Key=opsworks:layer,Value='#{layer_name}'\n", instance["InstanceId"]);
file::put("tag_file", &data).expect("Unable to write file");
}
}
let mut key = r#type;
let mut arr = Vec::new();
if ec2.contains_key(&key) == false{
ec2.insert(key, arr);
}
if usedtypes.contains_key(&key) == false{
usedtypes.insert(key, "1");
}
if eol == ""{
ec2.get_key_value(&key).push("{}", name);
}else{
ec2.get_key_value(&key).push("{}:*{}*", name, eol);
}
}
}
}
drop(tag_file);
I get an error of method not found in 'Value':
if tag["Key"].starts_with("opsworks:layer:")
I am unsure why this is failing because tag["Key"] should be a string and it should be checking if it starts with a specific substring.
This next error says it's not implemented for (&str, Value)
. I believe this might be due to an obsolete file writing crate?
file::put("tag_file", &data).expect("Unable to write file");
These errors both have the problem of the trait 'Hash' is not implemented for 'Value'. I was looking through the HashMap API, I thought contains_key worked like this. Some clarification would be really helpful on how the method works.
if ec2.contains_key(&key) == false
if usedtypes.contains_key(&key) == false
Finally, the last error, is method cannot be called on HashMap<&Value, Vec<_>>
due to unsatisfied trait bounds. Again, I think I misunderstood the HashMap API. Some clarification on how get_key_value would be really helpful.
ec2.get_key_value(&key).push("{}", name);
ec2.get_key_value(&key).push("{}:*{}*", name, eol);
I believe the main problem for the errors are lack of understanding of the for each loops and the HashMap API. I will continue doing research, but any tips would be helpful. Thanks for your time.