Class: VSphereCloud::Resources

Inherits:
Object
  • Object
show all
Defined in:
lib/cloud/vsphere/resources.rb,
lib/cloud/vsphere/resources/vm.rb,
lib/cloud/vsphere/resources/disk.rb,
lib/cloud/vsphere/resources/util.rb,
lib/cloud/vsphere/resources/folder.rb,
lib/cloud/vsphere/resources/scorer.rb,
lib/cloud/vsphere/resources/cluster.rb,
lib/cloud/vsphere/resources/datastore.rb,
lib/cloud/vsphere/resources/datacenter.rb,
lib/cloud/vsphere/resources/resource_pool.rb

Defined Under Namespace

Classes: Cluster, Datacenter, Datastore, Disk, Folder, PersistentDiskIndex, ResourcePool, Scorer, Util, VM

Constant Summary collapse

MEMORY_HEADROOM =
128
DISK_HEADROOM =
1024
STALE_TIMEOUT =
60
BYTES_IN_MB =
1024 * 1024

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(datacenter, config) ⇒ Resources

Returns a new instance of Resources.



12
13
14
15
16
17
18
19
# File 'lib/cloud/vsphere/resources.rb', line 12

def initialize(datacenter, config)
  @datacenter = datacenter
  @config = config
  @logger = config.logger
  @last_update = 0
  @lock = Monitor.new
  @drs_rules = []
end

Instance Attribute Details

#drs_rulesObject (readonly)

Returns the value of attribute drs_rules.



10
11
12
# File 'lib/cloud/vsphere/resources.rb', line 10

def drs_rules
  @drs_rules
end

Instance Method Details

#describe_cluster(cluster) ⇒ Object



101
102
103
104
105
# File 'lib/cloud/vsphere/resources.rb', line 101

def describe_cluster(cluster)
  "#{cluster.name} has #{cluster.free_memory}mb/" +
    "#{cluster.total_free_ephemeral_disk_in_mb / 1024}gb/" +
    "#{cluster.total_free_persistent_disk_in_mb / 1024}gb"
end

#pick_cluster_for_vm(requested_memory_in_mb, requested_ephemeral_disk_size_in_mb, existing_persistent_disks) ⇒ Cluster

Find a cluster for a vm with the requested memory and ephemeral storage, attempting to allocate it near existing persistent disks.

Parameters:

  • requested_memory_in_mb (Integer)

    requested memory.

  • requested_ephemeral_disk_size_in_mb (Integer)

    requested ephemeral storage.

  • existing_persistent_disks (Array<Resources::Disk>)

    existing persistent disks, if any.

Returns:

  • (Cluster)

    selected cluster if the resources were placed successfully, otherwise raises.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/cloud/vsphere/resources.rb', line 47

def pick_cluster_for_vm(requested_memory_in_mb, requested_ephemeral_disk_size_in_mb, existing_persistent_disks)
  @lock.synchronize do
    # calculate locality to prioritizing clusters that contain the most persistent data.
    clusters = @datacenter.clusters.values
    persistent_disk_index = PersistentDiskIndex.new(clusters, existing_persistent_disks)

    scored_clusters = clusters.map do |cluster|
      persistent_disk_not_in_this_cluster = existing_persistent_disks.reject do |disk|
        persistent_disk_index.clusters_connected_to_disk(disk).include?(cluster)
      end

      score = Scorer.score(
        @config.logger,
        cluster,
        requested_memory_in_mb,
        requested_ephemeral_disk_size_in_mb,
        persistent_disk_not_in_this_cluster.map(&:size_in_mb)
      )

      [cluster, score]
    end

    acceptable_clusters = scored_clusters.select { |_, score| score > 0 }

    @logger.debug("Acceptable clusters: #{acceptable_clusters.inspect}")

    if acceptable_clusters.empty?
      total_persistent_size = existing_persistent_disks.map(&:size_in_mb).inject(0, :+)
      cluster_infos = clusters.map { |cluster| describe_cluster(cluster) }

      raise "Unable to allocate vm with #{requested_memory_in_mb}mb RAM, " +
          "#{requested_ephemeral_disk_size_in_mb / 1024}gb ephemeral disk, " +
          "and #{total_persistent_size / 1024}gb persistent disk from any cluster.\n#{cluster_infos.join(", ")}."
    end

    acceptable_clusters = acceptable_clusters.sort_by do |cluster, _score|
      persistent_disk_index.disks_connected_to_cluster(cluster).map(&:size_in_mb).inject(0, :+)
    end.reverse

    if acceptable_clusters.any? { |cluster, _| persistent_disk_index.disks_connected_to_cluster(cluster).any? }
      @logger.debug('Choosing cluster with the greatest available disk')
      selected_cluster, _ = acceptable_clusters.first
    else
      @logger.debug('Choosing cluster by weighted random')
      selected_cluster = Util.weighted_random(acceptable_clusters)
    end

    @logger.debug("Selected cluster '#{selected_cluster.name}'")

    selected_cluster.allocate(requested_memory_in_mb)
    selected_cluster
  end
end

#pick_ephemeral_datastore(cluster, disk_size_in_mb) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/cloud/vsphere/resources.rb', line 107

def pick_ephemeral_datastore(cluster, disk_size_in_mb)
  @lock.synchronize do
    datastore = cluster.pick_ephemeral(disk_size_in_mb)
    if datastore.nil?
      raise Bosh::Clouds::NoDiskSpace.new(
          "Not enough ephemeral disk space (#{disk_size_in_mb}MB) in cluster #{cluster.name}")
    end

    datastore.allocate(disk_size_in_mb)
    datastore
  end
end

#pick_persistent_datastore(cluster, disk_size_in_mb) ⇒ Object



120
121
122
123
124
125
126
# File 'lib/cloud/vsphere/resources.rb', line 120

def pick_persistent_datastore(cluster, disk_size_in_mb)
  @lock.synchronize do
    datastore = cluster.pick_persistent(disk_size_in_mb)
    datastore.allocate(disk_size_in_mb)
    datastore
  end
end

#pick_persistent_datastore_in_cluster(cluster_name, disk_size_in_mb) ⇒ Datastore?

Place the persistent datastore in the given datacenter and cluster with the requested disk space.

Parameters:

  • cluster_name (String)

    cluster name.

  • disk_size_in_mb (Integer)

    disk size in mb.

Returns:

  • (Datastore?)

    datastore if it was placed succesfuly.



27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/cloud/vsphere/resources.rb', line 27

def pick_persistent_datastore_in_cluster(cluster_name, disk_size_in_mb)
  @lock.synchronize do
    cluster = @datacenter.clusters[cluster_name]
    if cluster.nil?
      raise Bosh::Clouds::NoDiskSpace.new(true), "Couldn't find cluster '#{cluster_name}'. Found #{@datacenter.clusters.values.map(&:name).join(", ")}"
    end

    datastore = cluster.pick_persistent(disk_size_in_mb)
    datastore.allocate(disk_size_in_mb)
    datastore
  end
end