Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions bosh_aws_cpi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ These options are specified under `cloud_options` in the `resource_pools` sectio
the EC2 availability zone the VMs should be created in
* `instance_type` (required)
which [type of instance](http://aws.amazon.com/ec2/instance-types/) the VMs should belong to
* 'disk_properties' (optional)
the EBS properties that the disk was created.
'provisioned_iops'
the [provisioned iops] EBS (http://aws.amazon.com/ebs/) the VMs should be using

### Network options

Expand Down
19 changes: 18 additions & 1 deletion bosh_aws_cpi/lib/cloud/aws/cloud.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class Cloud < Bosh::Cloud
DEFAULT_EC2_ENDPOINT = "ec2.amazonaws.com"
METADATA_TIMEOUT = 5 # in seconds
DEVICE_POLL_TIMEOUT = 60 # in seconds
EBS_IOPS_TYPE = "io1"

attr_reader :ec2
attr_reader :registry
Expand Down Expand Up @@ -159,8 +160,10 @@ def has_vm?(instance_id)
# @param [Integer] size disk size in MiB
# @param [optional, String] instance_id EC2 instance id
# of the VM that this disk will be attached to
# @param [optional, Hash] disk_properties Properties for
# provisioned iops EBS disk
# @return [String] created EBS volume id
def create_disk(size, instance_id = nil)
def create_disk(size, instance_id = nil, disk_properties = nil)
with_thread_name("create_disk(#{size}, #{instance_id})") do
unless size.kind_of?(Integer)
raise ArgumentError, "disk size needs to be an integer"
Expand All @@ -187,6 +190,20 @@ def create_disk(size, instance_id = nil)
:availability_zone => az
}

unless disk_properties.nil?
iops = disk_properties["provisioned_iops"]
unless iops.nil?
cloud_error("EBS minimal provisioned IOPS is 100") if iops < 100
cloud_error("EBS maximal provisioned IOPS is 10000") if iops > 10000
cloud_error("EBS IOPS/Size ratio is over 10") if iops * 1024 /size > 10
iops_params = {
:volume_type => EBS_IOPS_TYPE,
:iops => iops
}
volume_params.merge!(iops_params)
end
end

volume = @ec2.volumes.create(volume_params)
@logger.info("Creating volume `#{volume.id}'")
ResourceWait.for_volume(volume: volume, state: :available)
Expand Down
41 changes: 41 additions & 0 deletions bosh_aws_cpi/spec/unit/create_disk_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,47 @@
cloud.create_disk(2048).should == "v-foobar"
end

it "creates an EC2 volume with provisioned iops" do
iops_setting = {
"provisioned_iops" => 200
}
volume = double("volume", :id => "v-foobar")

cloud = mock_cloud do |ec2, region|
ec2.volumes.should_receive(:create) do |params|
params[:iops].should == 200
params[:volume_type].should == "io1"
volume
end
region.stub(:availability_zones => zones)
end

Bosh::AwsCloud::ResourceWait.stub(:for_volume).with(volume: volume, state: :available)
cloud.create_disk( 30 * 1024 , nil, iops_setting)
end

it "check min/max provisioned iops and its ratio to disk size" do
volume = double("volume", :id => "v-foobar")
Bosh::AwsCloud::ResourceWait.stub(:for_volume).with(volume: volume, state: :available)
cloud = mock_cloud do |ec2, region|
region.stub(:availability_zones => zones)
end
expect {
iops_setting = {"provisioned_iops" => 99}
cloud.create_disk(2000, nil, iops_setting)
}.to raise_error(Bosh::Clouds::CloudError, /EBS minimal provisioned IOPS is 100/)

expect {
iops_setting = {"provisioned_iops" => 10001}
cloud.create_disk(2000, nil, iops_setting)
}.to raise_error(Bosh::Clouds::CloudError, /EBS maximal provisioned IOPS is 10000/)

expect {
iops_setting = {"provisioned_iops" => 200}
cloud.create_disk(18000, nil, iops_setting)
}.to raise_error(Bosh::Clouds::CloudError, /EBS IOPS\/Size ratio is over 10/)
end

it "rounds up disk size" do
volume = double("volume", :id => "v-foobar")

Expand Down
3 changes: 2 additions & 1 deletion bosh_cpi/lib/cloud.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,9 @@ def configure_networks(vm_id, networks)
# @param [Integer] size disk size in MB
# @param [optional, String] vm_locality vm id if known of the VM that this disk will
# be attached to
# @param [optional, Hash] disk_properties Disk properties for provisioned disk
# @return [String] opaque id later used by {#attach_disk}, {#detach_disk}, and {#delete_disk}
def create_disk(size, vm_locality = nil)
def create_disk(size, vm_locality = nil, disk_properties = nil)
not_implemented(:create_disk)
end

Expand Down
2 changes: 1 addition & 1 deletion bosh_openstack_cpi/lib/cloud/openstack/cloud.rb
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ def configure_networks(server_id, network_spec)
# @param [optional, String] server_id OpenStack server UUID of the VM that
# this disk will be attached to
# @return [String] OpenStack volume UUID
def create_disk(size, server_id = nil)
def create_disk(size, server_id = nil, _ = nil)
with_thread_name("create_disk(#{size}, #{server_id})") do
raise ArgumentError, "Disk size needs to be an integer" unless size.kind_of?(Integer)
cloud_error("Minimum disk size is 1 GiB") if (size < 1024)
Expand Down
2 changes: 1 addition & 1 deletion bosh_vcloud_cpi/lib/cloud/vcloud/cloud.rb
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ def detach_disk(vapp_id, disk_id)
raise e
end

def create_disk(size_mb, vm_locality = nil)
def create_disk(size_mb, vm_locality = nil, _ = nil)
@client = client

with_thread_name("create_disk(#{size_mb}, vm_locality)") do
Expand Down
2 changes: 1 addition & 1 deletion bosh_vsphere_cpi/lib/cloud/vsphere/cloud.rb
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ def detach_disk(vm_cid, disk_cid)
end
end

def create_disk(size, _ = nil)
def create_disk(size, _ = nil, _ = nil)
with_thread_name("create_disk(#{size}, _)") do
@logger.info("Creating disk with size: #{size}")
disk = Models::Disk.new
Expand Down
2 changes: 1 addition & 1 deletion director/lib/cloud/dummy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def detach_disk(vm, disk)
raise NotImplemented, "detach_disk"
end

def create_disk(size, vm_locality = nil)
def create_disk(size, vm_locality = nil, disk_properties = nil)
raise NotImplemented, "create_disk"
end

Expand Down
3 changes: 2 additions & 1 deletion director/lib/director/instance_updater.rb
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,8 @@ def update_persistent_disk

if @job.persistent_disk > 0
@instance.model.db.transaction do
disk_cid = @cloud.create_disk(@job.persistent_disk, @vm.cid)
disk_properties = @resource_pool_spec.cloud_properties.nil? ? nil:@resource_pool_spec.cloud_properties["disk_properties"]
disk_cid = @cloud.create_disk(@job.persistent_disk, @vm.cid, disk_properties)
disk =
Models::PersistentDisk.create(:disk_cid => disk_cid,
:active => false,
Expand Down
25 changes: 22 additions & 3 deletions director/spec/unit/instance_updater_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,24 @@
},
"properties" => {"key" => "value"}
}
DISK_PLAN = {
"resource_pool" => {
"stemcell" => {
"name" => "ubuntu",
"network" => "network-a",
"version" => 3
},
"name" => "test_resource_pool",
"cloud_properties" => {
"ram" => "2GB",
"disk" => "10GB",
"cores" => 2,
"disk_properties" => {
"provisioned_iops" => 100
}
}
}
}
IDLE_PLAN = {
"deployment" => "test_deployment",
"job" => {
Expand Down Expand Up @@ -497,10 +515,11 @@ def make_updater(spec)
instance_updater.stub!(:cloud).and_return(@cloud)

@instance_spec.stub!(:spec).and_return(BASIC_PLAN)
@resource_pool_spec.stub!(:cloud_properties).and_return(DISK_PLAN["resource_pool"]["cloud_properties"])

@agent_1.should_receive(:drain).with("shutdown").and_return(0.01)
@agent_1.should_receive(:stop)
@cloud.should_receive(:create_disk).with(1024, "vm-id").and_return("disk-id")
@cloud.should_receive(:create_disk).with(1024, "vm-id", {"provisioned_iops" => 100}).and_return("disk-id")
@cloud.should_receive(:attach_disk).with("vm-id", "disk-id")
@agent_1.should_receive(:mount_disk).with("disk-id").and_return({"state" => "done"})
@agent_1.should_receive(:apply).with(BASIC_PLAN).and_return({
Expand Down Expand Up @@ -539,7 +558,7 @@ def make_updater(spec)

@agent_1.should_receive(:drain).with("shutdown").and_return(0.01)
@agent_1.should_receive(:stop)
@cloud.should_receive(:create_disk).with(1024, "vm-id").and_return("disk-id")
@cloud.should_receive(:create_disk).with(1024, "vm-id", nil).and_return("disk-id")
@cloud.should_receive(:attach_disk).with("vm-id", "disk-id")
@agent_1.should_receive(:mount_disk).with("disk-id").and_return({"state" => "done"})
@agent_1.should_receive(:migrate_disk).with("old-disk-id", "disk-id").and_return({
Expand Down Expand Up @@ -656,7 +675,7 @@ def make_updater(spec)
@cloud.should_not_receive(:delete_disk).with("new-disk-id")

# create, attach, mount and migrate to new disk
@cloud.should_receive(:create_disk).with(1024, "vm-id").and_return("disk-id")
@cloud.should_receive(:create_disk).with(1024, "vm-id", nil).and_return("disk-id")
@cloud.should_receive(:attach_disk).with("vm-id", "disk-id")
@agent_1.should_receive(:mount_disk).with("disk-id").and_return({"state" => "done"})
@agent_1.should_receive(:migrate_disk).with("old-disk-id", "disk-id").and_return({
Expand Down