Skip to content

(QENG-5305) Improve vmpooler host selection#242

Merged
mattkirby merged 17 commits into
puppetlabs:masterfrom
mattkirby:improved_host_selection_cleanup
Jan 10, 2018
Merged

(QENG-5305) Improve vmpooler host selection#242
mattkirby merged 17 commits into
puppetlabs:masterfrom
mattkirby:improved_host_selection_cleanup

Conversation

@mattkirby

@mattkirby mattkirby commented Oct 14, 2017

Copy link
Copy Markdown
Contributor

This change updates how vmpooler creates VMs, migrates VMs, and significantly reduces strain placed upon vsphere appliances by eliminating duplicate host state inspection.

  1. Clone operations target the resource pool for a cluster instead of a specific host. Host selection is left for vsphere to determine.
  2. Host selection used for migrating VMs is updated to eliminate duplicate host inspection by maintaining a global list of available target hosts within a cluster and updating it when it becomes stale.
  3. VMs are evaluated for migration against the list instead of occupying a slot for migration to be evaluated.
  4. A optional capability to create pool folders is added (this can be moved to a separate PR if desired)
  5. Host object retrieval is updated to use the searchIndex instead of iterating through a list of cluster objects until the matching name is found.
  6. A safeguard against no quickstats being found is added by ensuring that CPU utilization is not 0.

TODO:

  • Finish adding tests for new functionality in vsphere.rb

@mattkirby mattkirby changed the title Improve vmpooler host selection (QENG-5305) Improve vmpooler host selection Oct 17, 2017
@mattkirby mattkirby force-pushed the improved_host_selection_cleanup branch from f768ec3 to 0d8c131 Compare October 17, 2017 19:40
@mattkirby mattkirby requested a review from glennsarti October 17, 2017 19:47
Comment thread lib/vmpooler/pool_manager.rb Outdated
finish = migrate_vm_and_record_timing(vm_name, pool_name, parent_host_name, host_name, provider)
$logger.log('s', "[>] [#{pool_name}] '#{vm_name}' migrated from #{parent_host_name} to #{host_name} in #{finish} seconds")
$redis.sadd('vmpooler__migration', vm_name)
target_host_name = select_next_host(provider_name, vm['datacenter'], vm['cluster'], vm['architecture'])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if select_next_host returns 'nil'?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should cause a failure to be logged reporting that vm migration failed with an error raised from lib/vmpooler/providers/vsphere.rb:90 when migrate_vm is called. Perhaps it's worth emitting a more clear error that there was no target host provided.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will call the next line migrate_vm_and_record_timing() with target_host_name = nil which seems to go all the way down to the vcenter API to try and get the host by dns name?
We should fail earlier than that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will now fail if the datacenter, or cluster are missing, and if the target is empty, before trying to run the methods with bad data.

Comment thread lib/vmpooler/pool_manager.rb Outdated

def select_next_host(provider_name, datacenter, cluster, architecture)
provider_hosts = $provider_hosts
host = provider_hosts[provider_name][datacenter][cluster]['architectures'][architecture][0]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if provider_hosts[provider_name][datacenter][cluster]['architectures'][architecture] is a string then [0] could return the first character which is not what you probably expect here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true. It's populated by select_least_used_hosts from lib/vmpooler/providers/vsphere.rb:607 which returns an array. Do you think I should be more explicit than this at some point to ensure an array is returned?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I got it, thanks

Comment thread lib/vmpooler/providers/vsphere.rb Outdated
end

hosts_with_arch_versions.each do |host|
architectures[host[2]] << [host[0], host[1], host[2]]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it hard to know what is in each index host[0], host[1], host[2]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it probably makes sense to put it in a hash and give these values some titles.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This now uses a hash which should make clear what's being placed into this array.

@glennsarti glennsarti left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is vpshere specific concepts in the pool manager code (datacenter, cluster etc.). This should really all be in the vsphere provider.

Comment thread lib/vmpooler/pool_manager.rb Outdated
$threads = {}

# Host tracking object
$provider_hosts = {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: REALLY REALLY try to avoid adding more global variables. Instance level should be enough.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@glennsarti are you sure? I specifically require that this variable be accessible across all vmpooler provider threads.

@mattkirby

Copy link
Copy Markdown
Contributor Author

@glennsarti how do you think this can be solved in the vsphere code when it needs to constrain and share data across pool manager operations?

@glennsarti

Copy link
Copy Markdown
Contributor

Sure

  • Only one instance of a provider exists for one or more pools so it's able to maintain the state inside the provider
  • All operations have to go through the provider so they can be gated through there

The only reason I can think of to keep state in the pool manager is to allow across-provider communication. Which is not (should not) be required for vsphere host selection.

@mattkirby

Copy link
Copy Markdown
Contributor Author

Ok. I have reworked this to do away with global variables and now use an instance variable in the provider to track host state on a per-provider basis. Tests pass, but I need to complete adding coverage for changes in vsphere and the base provider, but wanted to get this put here so I could get further feedback and input if there are still some clear changes needed. I still intend to address the other feedback.

@mattkirby mattkirby force-pushed the improved_host_selection_cleanup branch 2 times, most recently from 407af83 to 5252075 Compare November 3, 2017 19:54
@mattkirby

mattkirby commented Nov 3, 2017

Copy link
Copy Markdown
Contributor Author

I've pushed an update here that moves migrate_vm to the vsphere provider. This should be a lot cleaner. I've addressed the confusing array population that @sbeaulie brought up earlier, and global variables are no longer used here in favor of instance variables on the provider, which works great. A mutex is added to ensure that all writing to provider_hosts in the provider is safe across all threads.

I added one more change to this, which allows a user to specify whether vmpooler should manage host selection at clone time, or if it should be deferred to vsphere. If vmpooler is managing host selection it uses the same method now used for migrations.

I'm still working through a handful of remaining tests on the vsphere provider, but this is all functional now.

@mattkirby

mattkirby commented Nov 3, 2017

Copy link
Copy Markdown
Contributor Author

The jruby tests pass, the others are failing. If I'm reading travis correctly it looks as though setup to run the tests is what's failing. Tests do pass locally for me on ruby 2.3.5p376.

@mattkirby mattkirby force-pushed the improved_host_selection_cleanup branch from 5252075 to 2d343f0 Compare November 3, 2017 20:23

def migrate_vm(vm_name, pool_name, provider)
Thread.new do
begin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provider really shouldn't need to contact redis for this. In this case the provider is just removing it from the queue. So the $redis.srem('vmpooler__migrating__' + pool_name, vm_name) should be called here PRIOR to the provider.migrate_vm call

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took your suggestion and placed this prior to calling provider.migrate_vm.

Comment thread lib/vmpooler/pool_manager.rb Outdated
rescue => err
$logger.log('s', "[x] [#{pool_name}] '#{vm_name}' migration failed with an error: #{err}")
remove_vmpooler_migration_vm(pool_name, vm_name)
provider.remove_vmpooler_migration_vm(pool_name, vm_name, $redis)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new method remove_vmpooler_migration_vm doesn't exist on the base and on inspection probably shouldn't be in a provider anyway. It's just removing the VM from the task queue.

By doing my previous suggestion, it's not needed as the VM is removed from the queue prior to be actioned in the provider.

end
end

def migration_limit(migration_limit)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the migration limit is now a per vSphere provider setting the documentation should be updated too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably should be a per vSphere provider setting, but it's still tracking migrations in redis and getting the setting from the global configuration section instead of checking the provider for this setting. I could add this change here. I was considering tackling that and the task_limit concept in a future change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be as simple as add in the docs migration limit (Only affects vSphere Provider)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see what you're saying, not that it's a per provider setting, but rather that it is only a vsphere provider setting.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah... The docs suggest its global but no longer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a mention in the example configuration file. I couldn't find another reference to migration_limit, please let me know if I've missed another location this should go.

Comment thread lib/vmpooler/providers/base.rb Outdated
attr_reader :metrics
# Provider options passed in during initialization
attr_reader :provider_options
# Hash for tracking hosts for deployment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These settings seem vsphere specific. Perhaps instead of modifying base, which affects all providers, move them there

Comment thread lib/vmpooler/providers/base.rb Outdated
@logger = logger
@metrics = metrics
@provider_name = name
@provider_hosts = {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above. vsphere provider specific.

# inputs
# [String] pool_name : Name of the pool
# [String] vm_name : Name of the VM to migrate
# [Class] redis : Redis object

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from Redis, how is this method signature different from migrate_vm_to_host?. Is it just simply calling

migrate_vm_to_host(pool_name, vm_name, nil) ?

Redis is already a global variable, so no ed to pass it through. That should probably be a separate PR

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main difference to me, beyond the redis part which as you point out shouldn't be there, is that there's no longer a need to provide the destination host name, so I figured keeping migrate_vm instead of migrate_vm_to_host made sense. I can change it if it makes more sense.

migration_limit if migration_limit >= 1
end

def migrate_vm(vm_name, pool_name, provider)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is currently no way in Pool Manager to actually add a VM to the migration queue. So this PR will not have any affect yet. Is this by design?

@mattkirby mattkirby Nov 3, 2017

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's an oversight. It's fixed now.

@mattkirby

Copy link
Copy Markdown
Contributor Author

I've updated this to include a fix for a behavior witnessed when running this over the weekend. Specifically, if no hosts are available for deployment check_time_finished is still updated in order to allow for things waiting on host selection to proceed. Previously, they would be stuck waiting and gum up pool_manager. Now, they will fail fast and report an error that makes clear why the clone or migration failed. Additionally, settings for utilization maximum and max age are exposed and documented.

@mattkirby mattkirby force-pushed the improved_host_selection_cleanup branch 2 times, most recently from c81c83c to 1aed90b Compare November 8, 2017 20:59
This commit adds a global provider_hosts concept in order to allow checking cluster utilization once per interval for a given cluster and retain the results, reusing them for an interval, and tracking the least used set of hosts. Without this change each migration and clone operation inspect host utilization and state for each host in the cluster, which is computationally expensive for vsphere.
This commit adds the capability to create folders within an existing target folder. Without this change folders to support platforms targets need to be created manually.
This commit updates create_vm to target a cluster instead of an individual host for clone operations. Without this change cluster host utilization needs to be inspected for everyone clone operation.
This commit updates cluster host resource inspection to stop weighting memory as a part of the results. Additionally, instead of returning a single least used host a percentage of the eligible hosts with below average utilization are selected. Without this change host migration logic can cause cluster resource imbalances due to a single host being targeted for many migrations before the impacts of the migrations cause numbers to adjust.
This commit moves the migrate_vm logic to the vsphere provider. Without
this change migrate_vm has lots of vsphere specific logic in
pool_manager migrate_vm method.
This commit updates the providers to move provider_hosts under the vsphere provider, which is the only place it's applicable. Methods where redis is passed through are updated to remove this pass through and use the globally available redis object, where applicable. Remove_vmpooler_migration_vm method is not needed and is removed.
This commit updates host selection to write check_time_finished whether
host retrieval was successful or not. Without this change when host
selection fails threads waiting for host selection to complete will
stuck waiting because check_time_finished doesn't update. Additionally,
because it would leave checking => true it would not attempt to inspect
and run host selection again.

Host selection for clones and migrations now make clear that no hosts
are available and fail logging a message. Without this change both
migrations and clones would fail with cryptic error messages logged
indicating clone and migrations failed.

Additionally, this change makes max_age configurable so a user can
specify that host selection should happen more or less frequently, as
required for migrations or clone operations when host selection is
enabled.
This change documents new vshpere specific parameters introduced related
to host selection and folder creation. Without this change these paremeters are not
documented.
This commit removes an unnecessary rescue that results in duplicate clone error messages. Without this change clone failures due to unavailable host resources are logged twice. A log message is added to specify the host the VM is running on when migration_limit is not set and migration is disabled. Lastly, when a migration fails it reports the host the VM is running on in addition to the reason for the failed migration.
@mattkirby mattkirby force-pushed the improved_host_selection_cleanup branch from 96f68ec to dd12125 Compare November 28, 2017 21:14

@glennsarti glennsarti left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ship it

@shrug

shrug commented Jan 2, 2018

Copy link
Copy Markdown

@mattkirby Ready to merge this?

@mattkirby

Copy link
Copy Markdown
Contributor Author

Just about. I've got one more set of tests I'm going to push shortly after which this should be ready to go. That should cover the bits I've added that haven't had tests added yet.

This commit adds tests for the remaining new vsphere functionality.
@mattkirby

Copy link
Copy Markdown
Contributor Author

I've finished tests and this should be ready to go.

@mattkirby mattkirby merged commit 6ab2e2f into puppetlabs:master Jan 10, 2018
@mattkirby mattkirby deleted the improved_host_selection_cleanup branch January 10, 2018 20:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants