Tag Archives: automation

Use app-only authentication with the Microsoft Graph PowerShell SDK

This posting is ~1 year years old. You should keep this in mind. IT is a short living business. This information might be outdated.

In the previous blog post I have showed you how to interactively log in into the Microsoft Graph API. You had to enter a username, a password, and you had to enter a second factor. This is typically not want you want if you want to automate things. But there is another way to get access to the Microsoft Graph API.

Create an app registration

To get access, you have to register an app in your AzureAD. Go to your Azure portal and select “App registration” from the “Manage” section. Add a new registration by clicking to “New registration”.

Give your registration a meaningful name. Usually, only accounts in your AzureAD should be able to use this app.

The next step is to add permissions. This is equivalent to defining permission scopes during an interactive login. Make sure that you only follow the least-privilege method. In contrast to delegate access, this login type is truly limited to the permissions you grant in this step.

Select “Microsoft Graph” from the list.

Choose “Application permissions”.

Then select the necessary permissions.

Grant the permissions and select “Grant admin consent”. This step is pretty important. You, the admin, consent to the selected permissions. There is no further question to consent to the enduser.

Login with a client secret

But before we can use, we have to add something to use in the authentication process. There are two different methods to authenticate:

  • Certificate, or
  • client secret

A client secret is okay for test or dev environments. But I would not recommend the usage in a prod environment. You have to add this secret to a script or something, which is hard to protect. Create a new client secret. Please note, that a client secret has a lifetime. And make sure that you copy it. Tge client secret will be hidden later!

Make sure that you give your client secret a descriptive name.

The usage of a client secret is a two-step process. We need to get an access token, using the client secret, and use the token to connect to the Graph API. To get an access token, you need to install the Microsoft Authentication Libraries (MSAL) PowerShell module.

Install-Module MSAL.PS -Scope CurrentUser

Then we can aquire the token.

$AppId = '525b0e65-xxxx-xxxx-xxxx-7f8c32536247'
$TenantId = 'ffbc872a-xxxx-xxxx-xxxx-d81b43c67ffe'
$ClientSecret = 'NmO8Q~PPzVqZnxxxxxxxxi0vfRBhj8_xxxxxxx'
 
$Token = Get-MsalToken -TenantId $TenantId -ClientId $AppId -ClientSecret ($ClientSecret | ConvertTo-SecureString -AsPlainText -Force)
 
Connect-Graph -AccessToken $MsalToken.AccessToken

As you can see, this service principal login was made by the client secret.

Login with a certificate

Something more appropriate for a prod environment, is to use a certificate for the login. You can create a self-signed certificate, or use any other kind of X.509 certificate to authenticate. I used a S/MIME certificate in this case.

Make sure that you only upload the public key!! The certificate with the private key must be stored in the computer or user certificate store on the machine from which you want to access.

Upload the public key of a certificate.

Next step is to use the certificate hash during the login process:

Connect-MgGraph -ClientId 525b0e65-xxxx-xxxx-xxxx-7f8c32536247 -TenantId ffbc872a-xxxx-xxxx-xxxx-d81b43c67ffe -CertificateThumbprint DC427652498895A6F453671275BC69B352F3510A

Same result, a successful login, but different authentication method.

As already mentioned: I would prefer certificate over client secret. :)

Getting started with the Microsoft Graph PowerShell SDK

This posting is ~1 year years old. You should keep this in mind. IT is a short living business. This information might be outdated.

There is a new API in town… naa, not really new, but the Microsoft Graph API will replace most, if not all, other Azure AD/ Microsoft 365 APIs. Actually, Microsoft has planned to retire Azure AD Graph API and ADAL in Juni 2022. Now they have postponed this date to somewhere after December 2022. This will give you some extra time to refactor your PowerShell scrips and move them to use the PowerShell SDK for Graph.

What is Microsoft Graph? Microsoft Graph is the spider web that connects everything in Microsoft 365. One part of Graph is a single and unified API endpoint, which allows you to access and manage Azure AD and Microsoft 365 services, such as Teams and Exchange Online, Intune etc.

Source: Microsoft

Instead of different endpoints, the Graph API uses a single endpoint (https://graph.microsoft.com/v1.0), which is the pretty nice thing if it comes down to Firewall rules and traffic management. This single endpoint, together with a single access token, allows you to manage all M365 services using REST API calls. So you don’t have to use the PowerShell SDK, you can also use Python or curl. Furthermore, the Microsoft Graph PowerShell SDK is Open Source, it offers cross-platform support (Linux, MacOS, Windows), and its available on PowerShell 5.1 nd above. This is a pretty important thing for me. Now I can use a single PowerShell Module to manage all my M365 services. This was PITA in the past. Depending on the service, I had to use different PowerShell modules, and I had to switch between PowerShell and PoSh Core.

Install the Microsoft Graph PowerShell SDK

The installation is pretty simple. All you need is

  • at least PowerShell 5.1 or later,
  • .NET 4.7.2 or later, and
  • the PowerShell script execution policy must be set to remote signed or a less restrictive execution policy

The installation is done by calling Install-Module.

Install-Module Microsoft.Graph -Scope CurrentUser

Sure, you can also use -Scope AllUsers, but I prefer to install PowerShell modules in my CurrentUser context. That’s it! Now let’s authenticate to the Graph API.

Authentication & Authorization

First of all: The Graph API knows two types of authentication:

  • delegated access, and
  • app-only access

Delegates access allows an application to act as a specific user, where as application access allows an application to act as its own entity. If you want that an API call is executed with the users permissions, then you should use delegated access. If you want to run scripts, or a service, then you want to use app-only access. Some API call are only possible with delegated access, some calls can only be made with app-only access, and some calls can be made with either of the two methods.

As part of the login process, you must define the requested permission scope. This is to ensure that the least possible privileges are used. For example:

Connect-MgGraph -Scopes "User.Read.All","Group.ReadWrite.All"

As you can see, this command will open a connection to the Graph API and you must consent the requested permissions after entering valid user credentials. Side note: Graph offers all the modern authentication stuff that we want to use today.

The tenant is specified by the singed-in user. If you want to connect to a specific tenant (to avoid usage of a cached access token), then you can add –TenantId <TenantId> to the command above.

As you can see, I now have a working connection using the Graph API using delegated access and with the requested permission scopes.

This map of Azure AD and MSOnline cmdlets was pretty helpful when playing around with Graph.

If you want to run a script, you might want to register an app in your tenant. This allows you to define the required permission scopes as properties of the app itself. I will show this in a separate blog post. This blog post will also cover the certificate-based authentication, as well as the authentication using a client secret.

Make your life easier – KeeAgent for KeePass

This posting is ~4 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.

Using a password safe, or password management system, is not a best practice – it’s a common practice. I’m using KeePass for years, because it’s available for different platforms, it can be used offline, it is Open Source, and it is not bound to any cloud services. Keepass allows me securely store usernames, passwords, recovery codes etc. for different services and websites, and together with features like autotype, Keepass offers a plus security and convenience.

I use 2FA or MFA wherever I can. That’s the reason why I’m a big fan of SSH public key authentication. But SSH key handling is sometimes inconvenient. You simple don’t want to store your SSH private keys on a cloud drive, and you don’t want to store them on a USB stick, or distribute them over different devices. In the past, I stored my SSH private keys on a cloud-drive in an encrypted container. When I needed a key, I decrypted the container and was able to use them. But this solution was inconvenient.

So what to do?

AbsolutVision/ pixabay.com/ Pixybay License

While searching for a solution I stumbled over KeeAgent, which is a plugin for KeePass. Keeagent allows you to store SSH keys in a KeePass database. KeeAgent then acts as SSH agent. I’m using this with PuTTY and MobaXterm and it works like a charm.

Setup KeeAgent

All you need is KeePass 2.x and the KeeAgent plugin. After installing the plugin (simply put the plgx file into C:\Program Files (x86)\KeePass Password Safe 2\Plugins), you can create a new entry in your KeePass database.

The password is the SSH private key passphrase. Then add the public and private key file to the newly created keepass database entry.

The KeeAgent.settings entry will be added automatically. Jump to the “KeeAgent” tab.

If required, keys can be loaded automatically if the database is locked, or you can add them later using the menu “Extras > KeeAgent”. Not every database entry can be used with KeeAgent, you have to enable the first checkbox to allow KeeAgent to use a specific database entry.

I create a database entry for each key pair I want to use with KeeAgent. And I only add frequently used keys automatically to KeeAgent. I have tons of keys and 99% of them are only added if I need them.

With KeeAgent in place, I can start new SSH sessions and KeeAgent delivers the matching key. You can see this in this screenshot “…from agent”.

I really don’t want to miss KeePass and KeeAgent. It makes my life easier and more secure.

Wrong iovDisableIR setting on ProLiant Gen8 might cause a PSOD

This posting is ~7 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.

TL;DR: There’s a script at the bottom of the page that fixes the issue.

Some days ago, this HPE customer advisory caught my attention:

Advisory: (Revision) VMware – HPE ProLiant Gen8 Servers running VMware ESXi 5.5 Patch 10, VMware ESXi 6.0 Patch 4, Or VMware ESXi 6.5 May Experience Purple Screen Of Death (PSOD): LINT1 Motherboard Interrupt

And there is also a corrosponding VMware KB article:

ESXi host fails with intermittent NMI PSOD on HP ProLiant Gen8 servers

It isn’t clear WHY this setting was changed, but in VMware ESXi 5.5 patch 10, 6.0  patch 4, 6.0 U3 and, 6.5 the Intel IOMMU’s interrupt remapper functionality was disabled. So if you are running these ESXi versions on a HPE ProLiant Gen8, you might want to check if you are affected.

To make it clear again, only HPE ProLiant Gen8 models are affected. No newer (Gen9) or older (G6, G7) models.

Currently there is no resolution, only a workaround. The iovDisableIR setting must set to FALSE. If it’s set to TRUE, the Intel IOMMU’s interrupt remapper functionality is disabled.

To check this setting, you have to SSH to each host, and use esxcli  to check the current setting:

[root@esx1:~] esxcli system settings kernel list -o iovDisableIR

Name          Type  Description                                 Configured  Runtime  Default
------------  ----  ---------------------------------------     ----------  -------  -------
iovDisableIR  Bool  Disable Interrupt Routing in the IOMMU...   FALSE       FALSE    TRUE

I have written a small PowerCLI script that uses the Get-EsxCli cmdlet to check all hosts in a cluster. The script only checks the setting, it doesn’t change the iovDisableIR setting.

Here’s another script, that analyzes and fixes the issue.

Tiny PowerShell/ Azure project: Deploy-AzureLab.ps1

This posting is ~7 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.

One of my personal predictions for 2017 is, that Microsoft Azure will gain more market share. Especially here in Germany. Because of this, I have started to refresh my knowledge about Azure. A nice side effect is that I can also improve my PowerShell skills.

Currently, the script creates a couple of VMs and resource groups. Nothing more, nothing less. The next features I want to add are:

  • add additional disks to the DCs (for SYSVOL and NTDS)
  • promote both two servers to domain controllers
  • change the DNS settings for the Azure vNetwork
  • deploy a Windows 10 client VM

I created a new repository on GitHub and shared a first v0.1 as public Gist. Please note, that this is REALLY a v0.1.

Using WP fail2ban with the CloudFlare API to protect your website

This posting is ~7 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.

The downside of using WordPress is that many people use it. That makes WordPress a perfect target for attacks. I have some trouble with attacks, and one of the consequences is, that my web server crashes under load. The easiest way to solve this issue would be to ban those IP addresses. I use Fail2ban to protect some other services. So the idea of using Fail2ban to ban IP addresses, that are used for attacks, was obvious.

From the Fail2ban wiki:

Fail2ban scans log files (e.g. /var/log/apache/error_log) and bans IPs that show the malicious signs — too many password failures, seeking for exploits, etc. Generally Fail2Ban is then used to update firewall rules to reject the IP addresses for a specified amount of time, although any arbitrary other action (e.g. sending an email) could also be configured. Out of the box Fail2Ban comes with filters for various services (apache, courier, ssh, etc).

That works for services, like IMAP, very good. Unfortunately, this does not work out of the box for WordPress. But adding the WordPress plugin WP fail2ban brings us closer to the solution. For performance and security reasons, vcloudnine.de can only be accessed through a content delivery network (CDN), in this case CloudFlare. Because CloudFlare acts as a reverse proxy, I can not see “the real” IP address. Furthermore, I can not log the IP addresses because of the German data protection law. This makes the Fail2ban and the WordPress Fail2ban plugin nearly useless, because all I would ban with iptables, would be the CloudFlare CND IP ranges. But CloudFlare offers a firewall service. CloudFlare would be the right place to block IP addresses.

So, how can I stick Fail2ban, the WP Fail2ban plugin and CloudFlares firewall service together?

APIs FTW!

APIs are the solution for nearly every problem. Like others, CloudFlare offers an API that can be used to automate tasks. In this case, I use the API to add entries to the CloudFlare firewall. Or honestly: Someone wrote a Fail2ban action that do this for me.

First of all, you have to install the WP Fail2ban plugin. That is easy. Simply install the plugin. Then copy the wordpress-hard.conf from the plugin directory to the filters.d directory of Fail2ban.

[root@webserver filters.d]# cp wordpress-hard.conf /etc/fail2ban/filter.d/

Then edit the /etc/fail2ban/jail.conf and add the necessary entries for WordPress.

[wordpress-hard]

enabled  = true
filter   = wordpress-hard
logpath  = /var/log/messages
action   = cloudflare
maxretry = 3
bantime  = 604800

Please note, that in my case, the plugin logs to /var/log/messages. The action is “cloudflare”. To allow Fail2ban to work with the CloudFlare API, you need the CloudFlare API Key. This key is uniqe for every CloudFlare account. You can get this key from you CloudFlare user profile. Go to the user settings and scroll down.

Cloudflare Global API Key

Patrick Terlisten/ www.vcloudnine.de/ Creative Commons CC0

Open the /etc/fail2ban/action.d/cloudflare.conf and scroll to the end of the file. Add the token and your CloudFlare login name (e-mail address) to the file.

# Default Cloudflare API token
cftoken = 1234567890abcdefghijklmopqrstuvwxyz99

cfuser = user@domain.tld

Last step is to tell the WP Fail2ban plugin which IPs should be trusted. We have to add subnets of the CloudFlare CDN. Edit you wp-config.php and add this line at the end:

/** CloudFlare IP Ranges */
define('WP_FAIL2BAN_PROXIES','103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,104.16.0.0/12,108.162.192.0/18,131.0.72.0/22,141.101.64.0/18,162.158.0.0/15,172.64.0.0/13,173.245.48.0/20,188.114.96.0/20,190.93.240.0/20,197.234.240.0/22,198.41.128.0/17,199.27.128.0/21,2400:cb00::/32,2405:8100::/32,2405:b500::/32,2606:4700::/32,2803:f800::/32,2c0f:f248::/32,2a06:98c0::/29');

The reason for this can be found in the FAQ of the WP Fail2ban plugin. The IP ranges used by CloudFlare can be found at CloudFlare.

Does it work?

Seems so… This is an example from /var/log/messages.

Jan 15 20:01:46 webserver wordpress(www.vcloudnine.de)[4312]: Authentication attempt for unknown user vcloudnine from 195.154.183.xxx
Jan 15 20:01:46 webserver fail2ban.filter[4393]: INFO [wordpress-hard] Found 195.154.183.xxx

And this is a screenshot from the CloudFlare firewall section.

Cloudflare Firewall Blocked Websites

Patrick Terlisten/ www.vcloudnine.de/ Creative Commons CC0

Another short test with curl has also worked. I will monitor the firewall section of CloudFlare. Let’s see who’s added next…

Important note for those, who use SELinux: Make sure that you install the policycoreutils-python package, and create a custom policy for Fail2Ban!

[root@webserver ~]# grep fail2ban /var/log/audit/audit.log | audit2allow -M myfail2banpolicy
******************** IMPORTANT ***********************
To make this policy package active, execute:

semodule -i myfail2banpolicy.pp

A strong indicator are errors like this in /var/log/messages:

Jan 22 12:06:03 webserver fail2ban.actions[16399]: NOTICE [wordpress-hard] Ban xx.xx.xx.xx
Jan 22 12:06:03 webserver fail2ban.action[16399]: ERROR curl -s -o /dev/null https://www.cloudflare.com/api_json.html -d 'a=ban' -d 'tkn=7c8e62809d4183931347772b366e621003c63' -d 'email=patrick@blazilla.de' -d 'key=xx.xx.xx.xx' -- stdout: ''
Jan 22 12:06:03 webserver fail2ban.action[16399]: ERROR curl -s -o /dev/null https://www.cloudflare.com/api_json.html -d 'a=ban' -d 'tkn=7c8e62809d4183931347772b366e621003c63' -d 'email=patrick@blazilla.de' -d 'key=xx.xx.xx.xx' -- stderr: ''
Jan 22 12:06:03 webserver fail2ban.action[16399]: ERROR curl -s -o /dev/null https://www.cloudflare.com/api_json.html -d 'a=ban' -d 'tkn=7c8e62809d4183931347772b366e621003c63' -d 'email=patrick@blazilla.de' -d 'key=xx.xx.xx.xx' -- returned 7
Jan 22 12:06:03 webserver fail2ban.actions[16399]: ERROR Failed to execute ban jail 'wordpress-hard' action 'cloudflare' info 'CallingMap({'ipjailmatches': <function <lambda> at 0x7f49967edc80>, 'matches': '', 'ip': 'xx.xx.xx.xx', 'ipmatches': <function <lambda> at 0x7f49967edde8>, 'ipfailures': <function <lambda> at 0x7f49967edc08>, 'time': 1485083163.0328701, 'failures': 2, 'ipjailfailures': <function <lambda> at 0x7f49967eded8>})': Error banning xx.xx.xx.xx

You will find corresponding audit messages in the /var/log/audit.log:

type=AVC msg=audit(1485083254.298:17688): avc:  denied  { name_connect } for  pid=16575 comm="curl" dest=443 scontext=unconfined_u:system_r:fail2ban_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket

Make sure that you create a custom policy for Fail2Ban, and that you load the policy.

HPE ProLiant PowerShell SDK

This posting is ~7 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.

Some days ago, my colleague Claudia and I started to work on a new project: A greenfield deployment consisting of some well known building blocks: HPE ProLiant, HPE MSA, HPE Networking (now Aruba) and VMware vSphere. Nothing new for us, because we did this a couple times together. But this led us to the idea, to automate some tasks. Especially the configuration of the HPE ProLiants: Changing BIOS settings and configuring the iLO.

Do not automate what you have not fully understood

Some of the wisest words I have ever said to a customer. Modifying the BIOS and iLO settings is a well understood task. But if you have to deploy a bunch of ProLiants, this is a monotonous, and therefore error prone process. Perfect for automation!

Scripting Tools for Windows PowerShell

To support the automation of HPE ProLiant deployments, HPE offers the Scripting Tools for Windows PowerShell. HPE offers the PowerShell modules free for charge. There are three different downloads:

  • iLO cmdlets
  • BIOS cmdlets
  • Onboard Administrator (OA) cmdlets

The iLO cmdlets include PowerShell cmdlets to configure and manage iLO on HPE ProLiant G7, Gen8 or Gen9 servers. The BIOS cmdlets does not support G7 servers, so you can only configure and manage legacy and UEFI BIOS for Gen8 (except DL580) and all Gen9 models. The OA cmdlets support the configuration and management of the HPE Onboard Administrator, which is used with HPEs well known ProLiant BL blade servers. The OA cmdlets need at least  OA v3.11, whereby v4.60 is the latest version available.  All you need to get started are

  • Microsoft .NET Framework 4.5, and
  • Windows Management Framework 3.0 or later

If you are using Windows 8 or 10, you already have PowerShell 4 respectively PowerShell 5.

Support for HPE ProLiant Gen9 iLO RESTful API

If you have ever seen a HPE ProLiant Gen9 booting up, you might have noticed the iLO RESTful API icon down right. Depending on the server model, the BIOS cmdlets utilize the ILO4 RESTful API. But the iLO RESTful API ecosystem is it worth to be presented in an own blog post. Stay tuned.

Documentation and examples

HPE offers a simple documentation for the BIOS, iLO and OA cmdlets. You can find the documentation in HPEs Information Library. Documentation is important, but sometimes example code is necessary to quickly ramp up code. Check HPEs PowerShell SDK GitHub repository for examples.

Time to code

I’m keen on it and curious to automate some of my regular deployment tasks with these PowerShell modules. Some of these tasks are always the same:

  • change the power management and other BIOS settings
  • change the network settings of the iLO
  • change the initial password of the iLO administrator account and create additional iLO user accounts

Further automation tasks are not necessarily related to the HPE ProLiant PowerShell SDK, but to PowerShell, respectively VMware PowerCLI. PowerShell is great to automate the different aspects and modules of an infrastructure deployment. You can use it to build your own tool box.

HPE StoreVirtual REST API

This posting is ~7 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.

Representational State Transfer (REST) APIs are all the rage. REST was defined by Roy Thomas Fielding in his PhD dissertation “Architectural Styles and the Design of Network-based Software Architectures“. The architectural style of REST describes six constraints:

  • Uniform interface
  • Stateless
  • Cacheable
  • Client – Server communication
  • Layered system
  • Code on demand

RESTful APIs typically use HTTP and HTTP verbs (GET, POST, PUT, DELETE, etc.) to send data to, or retrieve data from remote systems. To do so, REST APIs use Uniform Resource Identifiers (URIs) to interact with remote systems. Thus, a client can interact with a remote system over a REST API using standard HTTP URIs and HTTP verbs. For the data transfer, common internet media types, like JSON or XML are used. It’s important to understand that REST is not a standard per se. But most implementations make use of standards such as HTTP, URI, JSON or XML.

Because of the uniform interface, you have different choices in view of a client. I will use PowerShell and the Invoke-RestMethod cmdlet in my examples.

HPE StoreVirtual REST API

With the release of LeftHand OS 11.5 (the latest release is 12.6), HPE added a REST API for management and storage provisioning. Due to a re-engineered management stack, the REST API is significantly faster than the same task processed on the CLI or using the  Centralized Management Console (CMC). It’s perfect for automation and scripting. It allows customers to achieve a higher level of automation and operational simplicity. The StoreVirtual REST API is using JavaScript Object Notation (JSON) for data transfer between client and the StoreVirtual management group. With the REST API, you can

  • Read, create, and modify volumes
  • Create and delete snapshots
  • Create, modify, and delete servers
  • Grant and revoke access of servers to volumes

I use two StoreVirtal VSA (LeftHand OS 12.6) in my lab. Everything I show in this blog post is based on LeftHand OS 12.6.

The REST API in LeftHand OS 12.6 uses:

  • HTTPS 1.1
  • media types application/JSON
  • Internet media types application/schema+JSON
  • UTF-8 character encoding

RESTful APIs typically use HTTP and HTTP verbs (GET, POST, PUT, DELETE, etc.). I case of the StoreVirtual REST API:

  • GET is used to retrieve an object. No body is necessary.
  • PUT is used to update an object. The information to update the object is sent within the body.
  • POST is used to create of an object, or to invoke an action or event. The necessary information are sent within the body.
  • DELETE is used to delete an object.

Entry point for all REST API calls is /lhos, starting from a node, eg.

https://fqdn-or-ip:8081/lhos/

Subsequent resources are relative to this base URI. Resources are:

Resource pathDescription
/lhos/managementGroupManagement group entity
/lhos/clustersCluster collection
/lhos/cluster/<id>Cluster entity
/lhos/credentialsCredentials collection
/lhos/credentials/<session token>Credentials entity
/lhos/serversServer collection
/lhos/servers/<id>Server entity
/lhos/snapshotsSnapshot collection
/lhos/snapshots/<id>Snapshot entity
/lhos/volumesVolume collection
/lhos/volumes/<id> Volume entity

The object model of the StoreVirtual REST API uses

  • Collections, and
  • Entities

to address resources. An entity is used to address individual resources, whereas a collection is a group of individual resources. Resources can be addressed by using a URI.

Exploring the API

First of all, we need to authenticate us. Without a valid authentication token, no REST API queries can be made. To create a credential entity, we have to use the POST method.

$cred = @{
            user='admin';
            password='Passw0rd'
}

$body = $cred | ConvertTo-Json

$a = Invoke-RestMethod -Uri https://vsa1.lab.local:8081/lhos/credentials -Method Post -Body $body -ContentType 'application/JSON'

$cred is a hash table which includes the username and the password. This hash table is converted to the JSON format with the ConvertTo-Json cmdlet. The JSON data will be used as body for our query. The result is an authentication token.

PS C:\Users\p.terlisten> $a

authToken                                                                                                                                                                                     
---------                                                                                                                                                                                     
fa0a7b56-0134-400f-9d62-79b3071c950a

This authentication token must be used for all subsequent API queries. This query retrieves a collection of all valid sessions.

$b = Invoke-RestMethod -Uri https://vsa1.lab.local:8081/lhos/credentials -Method Get -Headers @{'Authorization'=$a.authToken}

The GET method is used, and the authentication token is sent with the header of the request.

PS C:\Users\p.terlisten> $b


name        : REST Sessions Collection
description : Collection of authentication sessions used by the REST server.
type        : RESTSession
uri         : /lhos/credentials
total       : 1
members     : {@{name=fa0a7b56-0134-400f-9d62-79b3071c950a; description=REST Session; type=RESTSession; id=0; uri=/lhos/credentials/fa0a7b56-0134-400f-9d62-79b3071c950a; 
              created=2016-06-07T08:38:06.426241Z; modified=2016-06-07T08:44:28.255283Z; userName=admin; clientIP=192.168.200.90}}

To retrieve an individual credential entity, the URI of the entity must be used.

$b = Invoke-RestMethod -Uri https://vsa1.lab.local:8081/lhos/credentials/fa0a7b56-0134-400f-9d62-79b3071c950a -Method Get -Headers @{'Authorization'=$a.authToken}

The result of this query is the individual credential entity

PS C:\Users\p.terlisten> $b


name        : fa0a7b56-0134-400f-9d62-79b3071c950a
description : REST Session
type        : RESTSession
id          : 0
uri         : /lhos/credentials/fa0a7b56-0134-400f-9d62-79b3071c950a
created     : 2016-06-07T08:38:06.426241Z
modified    : 2016-06-07T08:51:56.358096Z
userName    : admin
clientIP    : 192.168.200.90

It’s important to know, that if a session has not been used for 15 minutes, it is automatically removed. The same applies to constantly active sessions after 24 hours. After 24 hours, the credential entity will be automatically removed.

Let’s try to create a volume. The information about this new volume has to be sent within the body of our request. We use again the ConvertTo-Json cmdlet to convert a hash table with the necessary information to the JSON format.

$vol = @{
            name='api-vol';
            description='Volume created via REST API';
            size=1073741824;
            clusterId=28;
            isThinProvisioned=$true;
            dataProtectionLevel=2
}

$body = $vol | ConvertTo-Json

Invoke-RestMethod -Uri https://vsa1.lab.local:8081/lhos/volumes -Method Post -Headers @{'Authorization'=$a.authToken} -Body $body -ContentType 'application/JSON'

The size must be specified in bytes. As a result, Invoke-RestMethod will output this:

name                          : api-vol
description                   : Volume created via REST API
type                          : volume
id                            : 3058
uri                           : /lhos/volumes/3058
created                       : 2016-06-07T08:55:41Z
modified                      : 
friendlyName                  : 
transport                     : 0
isThinProvisioned             : True
size                          : 1073741824
serialNumber                  : f9df3e8bb0a160f269027ecc0371884e0000000000000bf2
provisionedSpace              : 1073741824
numberOfReplicas              : 2
dataProtectionLevel           : 2
iscsiIqn                      : iqn.2003-10.com.lefthandnetworks:mgmt:3058:api-vol
isPrimary                     : True
isDeleting                    : False
bytesWritten                  : 0
isAvailable                   : True
clusterName                   : CLUSTER
clusterId                     : 28
isVIPRebalancing              : False
isAdaptiveOptimizationEnabled : True
isMigrating                   : False
scsiLUNStatus                 : available
hasUnrecoverableIOErrors      : False
restripePendingStatus         : none
replicationStatus             : normal
resynchronizationStatus       : none
migrationStatus               : none
isLicensed                    : True
transportServerId             : 0
fcTransportStatus             : 0
createdBy                     : Unknown
iscsiSessions                 : 
fibreChannelPaths             : 
snapshots                     : @{name=snapshots; type=snapshot; uri=/snapshots?volumeName=api-vol; resource=}

Using the CMC, we can confirm that the volume was successfully created.

storevirtual_rest_api_vol_1

Patrick Terlisten/ www.vcloudnine.de/ Creative Commons CC0

Since we have a volume, we can create a snapshot. To create a snapshot, we need to invoke an action on the volume entity. We have to use the POST method and the URI of our newly created volume.

$snapshot = @{
                action='createSnapshot';
                parameters = @{
                                name='vol-api-snap';
                                description='Volume snapshot created via REST API';
}
}

$body = $snapshot | ConvertTo-Json

Invoke-RestMethod -Uri https://vsa1.lab.local:8081/lhos/volumes/3058 -Method Post -Headers @{'Authorization'=$a.authToken} -Body $body -ContentType 'application/JSON'

In case of a successful query, Invoke-RestMethod will give us this output.

name                     : vol-api-snap
description              : Volume snapshot created via REST API
type                     : snapshot
id                       : 3060
uri                      : /lhos/snapshots/3060
created                  : 2016-06-07T09:01:12Z
modified                 : 
friendlyName             : 
transport                : 0
isThinProvisioned        : True
size                     : 1073741824
serialNumber             : f9df3e8bb0a160f269027ecc0371884e0000000000000bf4
provisionedSpace         : 8388608
iscsiIqn                 : iqn.2003-10.com.lefthandnetworks:mgmt:3060:vol-api-snap
isPrimary                : True
isDeleting               : False
bytesWritten             : 0
isAvailable              : True
clusterName              : CLUSTER
clusterId                : 28
iscsiSessions            : 
fibreChannelPaths        : 
snapshotACL              : 
writableSpaceUsed        : 0
managedBy                : 0
isAutomatic              : False
isMigrating              : False
scsiLUNStatus            : available
hasUnrecoverableIOErrors : False
restripePendingStatus    : none
replicationStatus        : normal
resynchronizationStatus  : none
migrationStatus          : none
isLicensed               : True
transportServerId        : 0
fcTransportStatus        : 0
createdBy                : Unknown

Again, we can use the CMC to confirm the success of our operation.

storevirtual_rest_api_vol_2

Patrick Terlisten/ www.vcloudnine.de/ Creative Commons CC0

To delete the snapshot, the DELETE method and the URI of the snapshot entity must be used.

Invoke-RestMethod -Uri https://vsa1.lab.local:8081/lhos/snapshots/3060 -Method Delete -Headers @{'Authorization'=$a.authToken}

To confirm the successful deletion of the snapshot, the GET method can be used. The GET method will retrieve a collection of all snapshot entities.

Invoke-RestMethod -Uri https://vsa1.lab.local:8081/lhos/snapshots -Method Get -Headers @{'Authorization'=$a.authToken}

The result will show no members inside of the snapshot collection.

name        : Snapshots Collection
description : Collection of Snapshot objects
type        : snapshot
uri         : /lhos/snapshots
total       : 0
members     : {}

At the end of the day, we remove our credential entity, because it’s not longer used. To delete the credential entity, we use the DELETE method with the URI of our credential entity.

Invoke-RestMethod -Uri https://vsa1.lab.local:8081/lhos/credentials/fa0a7b56-0134-400f-9d62-79b3071c950a -Method Delete -Headers @{'Authorization'=$a.authToken}

The next query should fail, because the credential entity is no longer valid.

PS C:\Users\p.terlisten> Invoke-RestMethod -Uri https://vsa1.lab.local:8081/lhos/credentials -Method Get -Headers @{'Authorization'=$a.authToken}
The remote server returned an error: (401) Unauthorized. (raised by: Invoke-RestMethod)

HTTPS workaround

The StoreVirtual API is only accessable over HTTPS. By default, the StoreVirtual nodes use an untrusted HTTPS certifificate. This will cause Invoke-RestMethod to fail.

[10,6: Invoke-RestMethod] The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

After a little research, I found a workaround. This workaround uses the System.Security.Cryptography.X509Certificates namespace. You can use this snippet to build a function or add it to a try-catch block.

add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@

[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

Final words

The StoreVirtual REST API is really handy. It can be used to perform all important tasks. It’s perfect for automation and it’s faster than the CLI. I’ve used PowerShell in my examples, but I’ve successfully tested it with Python. Make sure to take a look in to the HPE StoreVirtual REST API Reference Guide.

Dynamic VLAN assignment with AOS 6

This posting is ~7 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.

Manually assigning ports to VLANs can be a time consuming and error prone process. Depending on the size of the network, there is a point where it doesn’t make sense to do this manually. Especially in SMB networks, VLANs are assigned manually, because the effort of automating the VLAN assignment exceeds the effort for manually assigning VLANs. Those environments are often very static. I know many SMB networks where VLAN have not been addressed for a long time. With declining costs for Layer 3 switches, the separation of workloads in VLANs for SMB customers became affordable. Server virtualization was another mainspring for VLANs and inter-VLAN routing. To be honest: I’m talking about SMB customers, not enterprise customers or enterprise-grade SMB customers (latter is my special term for SMB customers with enormous IT budgets…). But the main driver for VLANs was Voice over IP (VoIP). With the increasing proliferation of VoIP, even the smallest SMB customer were forced to use VLANs. But this led to situations, where customers had to change the switch config every time a new client or IP phone was added to the network. Common workarounds:

  • pre-configuring switches, eg. port 1 to 12 for clients and 13 to 24 for IP phones
  • connecting clients behind IP phones and pre-configuring all switch ports (untagged client and tagged VoIP VLAN)

Suitable for small environments, but difficult to handle if environments grow over time. And I’m not a friend of connecting clients behind IP phones… Enterprise, or enterprise-grade SMB customers tend to implement 802.1x to manage access to their network. With 802.1x it’s possible to assign ports to VLANs depending on the user identity. But 802.1x is complex. If you have the the knowhow, the time and the budget, please do 802.1x! But you should take the complexity into account. Today I want to show options, offisde of 802.1x, to dynamically assign ports to VLANs with Alcatel-Lucent Enterprise OmniSwitches.

First of all: We have to differ between AOS 6, AOS 7 and AOS 8. Alcatel-Lucent Enterprise (ALE) currently uses three different software releases, depending on the switch platform.

Switch modelAOS release
OmniSwitch 6250AOS 6
OmniSwitch 6350AOS 6
OmniSwitch 6450AOS 6
OmniSwitch 6850EAOS 6
OmniSwitch 6855AOS 6
OmniSwitch 6860(E)AOS 8
OmniSwitch 6900AOS 7
OmniSwitch 9000(E)AOS 6
OmniSwitch 9900AOS 6
OmniSwitch 10KAOS 7

Depending on the specific AOS release, there are various ways to enable dynamic VLAN assignment. The main reason for the different AOS releases is, that ALE shifts its networking core platform from Windriver VxWorks (AOS 6) to Linux (AOS 7 and AOS 8) (source #1, source #2).

This blog post will focus on

  • OmniSwitch 6250/ 6350/ 6450 running AOS 6.7.1

I plan to publish similar blog posts for

  • OmniSwitch 6900/ 10k running AOS 7.3.4
  • OmniSwitch 6860/ 6860E running AOS 8.2.1

Dynamic VLAN assignment with AOS 6

In general, there are three different ways to dynamically assign ports to VLANs with AOS 6:

  • VLAN mobility
  • User Network Profiles (UNP)
  • LLDP Media Endpoint Detection (LLDP-MED)

Let’s take a look at VLAN mobility. VLAN mobility is used to dynamically assign one or more VLANs to a port, based on traffic characteristics that were received on that port. The following information can be used to classify traffic:

  • 802.1Q VLAN ID tag
  • DHCP MAC address
  • DHCP MAC range
  • DHCP port
  • DHCP generic
  • MAC address
  • MAC address range
  • Network address
  • Protocol
  • Port

You can’t use VLAN mobility on ports that

  • is an 802.1Q tagged port
  • belongs to a Link Aggregation Group (LAG)
  • has Spanning Tree enabled and the BPDU ignore status is disabled
  • is used to mirror traffic

To allow the switch to dynamically assign ports to VLANs, VLAN mobility has to be enabled. By default, all ports are non-mobile ports. A non-mobile port is statically assigned to a specific VLAN.

To enable VLAN mobility for a port:

vlan port mobile 1/1

You can also use a port range.

vlan port mobile 1/1-22 2/1-22

To disable VLAN mobility use the “no” form of the command.

vlan no port mobile 1/1-22 2/1-22

If a device sends ethernet frames with a 802.1Q VLAN ID tag, you can use the VLAN ID tag to dynamically assign a port to a VLAN. With VLAN mobility enabled, you only have to enable the “mobile-tag” option for the desired VLAN.

vlan 199 mobile-tag enable

As soon as the switch receives a frame with a 802.1Q VLAN ID tag for VLAN 199, the port that received this frame is dynamically assigned to VLAN 199. That’s VLAN mobility based on 802.1Q VLAN ID tags. But you can also use VLAN rules. VLAN rules are created per VLAN. You can have one or more rules per VLAN. You can use the

  • Source MAC address
  • Source MAC address ranges
  • Switch ports, or
  • the DHCP request itself

to dynamically assign a port to a VLAN. This rule matches to DHCP requests from a single MAC address.

vlan 199 dhcp mac 68:F7:28:FA:A0:D5

If a DHCP request with the specified MAC address is received, the port is dynamically assigned to VLAN 199. Because managing MAC addresses is not very handy, you can use MAC address ranges:

vlan 199 dhcp mac 68:F7:28:FA:00:00 68:F7:28:FA:FF:FF

To use all DHCP requests on a specific port, use the DHCP port rule:

vlan 199 dhcp port 1/1-22 2/1-22

To use all received DHCP requests, use the DHCP generic rule:

vlan 199 dhcp generic

To remove a rule, use the “no” form of the command.

vlan 199 no dhcp ...

Once the device has received an IP address from the DHCP server, the VLAN port assignment is dropped! Because of this, you can combine DHCP and network address rules. A network address rule dynamically assigns the VLAN depending on the IP subnet.

vlan 199 ip 192.168.20.0 255.255.255.0

This rule assigns VLAN 199 to a port, that receives traffic from a client in the subnet 192.168.20.0/24. If the DHCP server in VLAN 199 assigns IP addresses from this subnet, you can easily combine the DHCP and network address rule.

A MAC address rule assigns the VLAN depending on a single MAC address

vlan 199 mac range 68:F7:28:FA:A0:D5

 or on a range of MAC addresses.

vlan 199 mac range 68:F7:28:FA:00:00 68:F7:28:FA:FF:FF

Less frequently used are port and protocol rules. A port rule doesn’t require incoming traffic to trigger dynamic VLAN assignment. The specified mobile port is immediately assigned to the specified VLAN. Port rules only apply to outgoing broadcast traffic. You still need rules for the incoming traffic. To create a VLAN port rule:

vlan 199 port 1/1

A protocol rule uses the protocol type in an ethernet frame to assign VLANs to ports. Valid values for the port type are:

  • IP Ethernet-II
  • IP SNAP
  • Ethernet II
  • DECNet
  • AppleTalk
  • Ethertype
  • DSAP/SSAP
  • SNAP

A protocol rule is created by issuing

vlan 199 protocol ip-snap

As always, the “no” form of the command removes the rule.

vlan no 199 protocol ip-snap

or

vlan no 199 mac range 68:F7:28:FA:00:00 68:F7:28:FA:FF:FF

User Network Profiles (UNP) is a feature of Access Guardian. Access Guardian refers to security functions, like

  • Authentication and Classification
  • Host Integrity Check (HIC)
  • User Network Profiles (UNP), and
  • Virtual Network Profile (VPN)

UNP are available in AOS 6, AOS 7 and AOS 8. In AOS 6 we need a

  • policy condition
  • policy action
  • policy rule, and a
  • policy list

These four characteristics belong to the QoS feature of AOS. But a UNP needs a policy list, more specific the policy rules that are part of the policy list, to classify traffic and devices. The policy condition is necessary to identifiy a devices on which this policy should match.

policy condition ip_phones source mac 68:F7:28:00:00:00 mask 00:00:00:FF:FF:FF

Beside the MAC address, you can use source and destionation IP addresses, switch ports, source and destination TCP/ UDP ports, VLANs and many more. To use one or more IP addresses, simple use a network group.

policy network group sales 192.168.20.0 mask 255.255.255.0 192.168.30.0 mask 255.255.255.0

The group “sales” consists of two subnets. To remove a subnet, use the “no” form of the command.

policy network group sales no 192.168.20.0 mask 255.255.255.0

The policy action is used to determine, what should happen with the traffic. In this case: Priorize the traffic.

policy action high_prio priority 7 802.1p 7

The rule binds condition and action.

policy rule rule_voip condition ip_phones action high_prio log no default-list

A policy list is used to group one or more policy rules.

policy list qos_list_voip rules rule_voip

A UNP binds a name, a VLAN and a policy list together.

aaa user-network-profile name voip vlan 199 policy-list-name qos_list_voip

A third way to dynamically assign ports to VLANs is LLDP Media Endpoint Detection (LLDP-MED). LLDP Media Endpoint Detection was developed to increase the interoperability of VoIP devices with other devices on the network (eg. PC, switches etc). AOS uses LLDP-MED network policies to advertise information to devices. A network policy contains information about VLAN ID and L2/ L3 priorities. First, we have to enable network policy support, either for a port or for the chassis.

lldp 1/1 tlv med network-policy enable

To enable network policies for the chassis use the keyword “chassis” instead of a port.

lldp chassis tlv med network-policy enable

To create a network policy enter:

lldp network-policy 1 application voice vlan 100 l2-priority 5 dscp 46

The created policy (ID 1) will advertise the VLAN 100, L2 priority 5 and DSCP 46 to voice devices. The next step is to bind the policy to a port or the chassis.

lldp chassis med network-policy 1

Or for a specific port.

lldp 1/1 med network-policy 1

Furthermore, you need to enable VLAN mobility on the ports. If the IP phones sends tagged VLAN frames, you also have to enable the “mobile tag” feature for the VLAN.

vlan 100 mobile-tag enable

The IP phone receives the configuration information over of the network policy. VLAN mobility and “mobile tag” will make sure, that the VoIP phone is pushed to the correct VLAN.

Summary

Manually assigning VLANs can be a time consuming and error prone process. AOS 6 offers

  • VLAN mobility
  • User Network Profiles, and
  • LLDP-MED

to dynamically assign ports to VLANs. Each of the options has its pros and cons. Especially the combination of VLAN mobility and LLDP-MED is really easy to implement. I will publish more blog posts about the same topic, but with AOS 7 and AOS 8.

First steps with Python and pyVmomi (vSphere SDK for Python)

This posting is ~7 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.

In December 2013, VMware made an christmas gift to the community by releasing pyVmomi. pyVmomi is a SDK that allows you to manage VMware ESXi and vCenter using Python and the VMware vSphere API. Nearly 18 months are past since then and pyVmomi has developed over time.

I’ve started to play around with Python, and I’ve written about the reasons in one of my last blog posts (Hey infrastructure guy, you should learn Python!).

How to get pyVmomi?

You can install the official release of pyVmomi using pip (pip installs packages, a recursive acronym).

pip3 install --upgrade pyvmomi

The latest version is available on GitHub. To get the latest version, use

python setup.py develop

or

python setup.py install

That you can fetch the latest version from GitHub is pretty cool and shows a big benefit: The community can contribute to pyVmomi and it’s more frequently updated. A huge benefit in regard of code quality and features.

What Python releases are support?

The latest information about supported Python releases can be found on the GitHub page of the project.

  • pyVmomi 6.0.0.2016.4 and later support 2.7, 3.3 and 3.4
  • pyVmomi 6.0.0 and later support 2.7, 3.3 and 3.4
  • pyVmomi 5.5.0-2014.1 and 5.5.0-2014.1.1 support Python 2.6, 2.7, 3.3 and 3.4
  • pyVmomi 5.5.0 and below support Python 2.6 and 2.7

Interesting fact: pyVmomi version numbers correlate with vSphere releases. pyVmomi 6.0.0 was released with the GA of VMware vSphere 6. pyVmomi supports the corresponding vSphere release and the previous four vSphere releases.

I’m using Python 3 for my examples. I wouldn’t recommend to start with Python 2 these days.

First steps

pyVmomi allows you to manage VMware ESXi and vCenter using Python and the VMware vSphere API. Because of this, the VMware vSphere API Reference Documentation will be your best friend.

First of all, you need a connection to the API. To connect to the vSphere API, we have to import and use the module pyVim, more precise, the pyVim.connect module and the SmartConnect function. pyVim.connect is used for the connection handling (creation, deletion…) to the Virtualization Management Object Management Infrastructure (VMOMI). pyVim is part of pyVmomi and it’s installed automatically.

from pyVim.connect import SmartConnect


c = SmartConnect(host="192.168.20.1", user="root", pwd='Passw0rd')

SmartConnect accepts various parameters, but for the beginning it’s sufficient to use three of them: host, user and pwd. You can use “help(SmartConnect)” to get information about the SmartConnect function. “c” is the object (pyVmomi.VmomiSupport.vim.ServiceInstance) which we will use later.

A connection itself is useless. But how can we explore the API? Python doesn’t support typing, so it can be difficult to “explore” an API. That’s why the VMware vSphere API Reference Documentation and the Managed Object Browser (MOB) will be your best friends. The MOB is a web-based interface and represents the vSphere API. It allows you to navigate through the API. Any changes you make through the MOB, by invoking methods, take effect and change the config or will give you an output.

Important note: If you are using VMware vSphere 6 (ESXi 6.0 and vCenter 6.0), you have to enable the MOB. The MOB is disabled by default. Check VMware KB2108405 (The Managed Object Browser is disabled by default in vSphere 6.0) for more details.

Open a browser and open https://ip-or-fqdn/mob. You can use the IP address or the FQDN of an ESXi host or a vCenter Server (Appliance). I use a standalone ESXi 5.5 host in this example.

python_esxi_mob_1

Patrick Terlisten/ www.vcloudnine.de/ Creative Commons CC0

Our first code

Let’s try something easy. I’ve framed a method in the screenshot above. We will use this method now.

from pyVim.connect import SmartConnect


c = SmartConnect(host="192.168.20.1", user="root", pwd='Passw0rd')

print(c.CurrentTime())

This code will connect to the vSphere API, invoke the method “CurrentTime()” and prints the result. What happens if we execute our first lines of Python code? We will get an error…

self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:645)

Python checks SSL certificates in strict mode. Because of this, untrusted certificates will cause trouble. This applies to Python 3, as well as to Python >= 2.7.9 (PEP 0466). Most people use untrusted certificates. To deal with this, we have to create a context for our HTTP connection. This context can be used by the SmartConnect function. To create a context, we have to import the ssl module of Python.

from pyVim.connect import SmartConnect
import ssl


s = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
s.verify_mode = ssl.CERT_NONE

c = SmartConnect(host="192.168.20.1", user="root", pwd='Passw0rd', sslContext=s)

print(c.CurrentTime())

“s” is the new object (ssl.SSLContext) we will use and the parameter “sslContext=s” will told SmartConnect to use this object.

Save this code into a file (I called it pyvmomitest.py in my example). Navigate to the folder, open a Python REPL and import the file you’ve saved (module) a moment ago.

C:\Users\p.terlisten\Documents\Development\Python\Playground>python
Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:38:48) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyvmomitest
2016-05-20 12:29:23.837049+00:00
>>>

Hurray! We used the vSphere API to get the current date and time (CET).

But what if we have deployed valid certificates? And what about housekeeping? We have connected, but we haven’t disconnected from the API? We can use a try-except block to handle this. And because we are nice, we import also the function “Disconnect” from pyVim.connect to disconnect from the vSphere API at the end.

from pyVim.connect import SmartConnect, Disconnect
import ssl

s = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
s.verify_mode = ssl.CERT_NONE

try:
    c = SmartConnect(host="192.168.20.1", user="root", pwd='Passw0rd')
    print('Valid certificate')
except:
    c = SmartConnect(host="192.168.20.1", user="root", pwd='Passw0rd', sslContext=s)
    print('Invalid or untrusted certificate')

print(c.CurrentTime())

Disconnect(c)

With this code, we should get the following output.

C:\Users\p.terlisten\Documents\Development\Python\Playground>python
Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:38:48) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyvmomitest
Invalid or untrusted certificate
2016-05-20 12:36:28.707876+00:00
>>>

Okay, the vSphere API wasn’t designed to retrieve the current date and time. Let’s look at something more useful. This script will give us the names of all VMs in the datacenter.

from pyVim.connect import SmartConnect, Disconnect
import ssl

s = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
s.verify_mode = ssl.CERT_NONE

try:
    c = SmartConnect(host="192.168.20.1", user="root", pwd='Passw0rd')
    print('Valid certificate')
except:
    c = SmartConnect(host="192.168.20.1", user="root", pwd='Passw0rd', sslContext=s)
    print('Invalid or untrusted certificate')

datacenter = c.content.rootFolder.childEntity[0]
vms = datacenter.vmFolder.childEntity

for i in vms:
    print(i.name)

Disconnect(c)

Let’s take this statement and look at everything after the “c”. We will use the MOB to navigate through the API. This will help you to understand, how the Python code and the structure of the vSphere API correlate.

datacenter = c.content.rootFolder.childEntity[0]

Open the MOB. You will easily find  the property “content”.

python_esxi_mob_2

Patrick Terlisten/ www.vcloudnine.de/ Creative Commons CC0

Click on “content” and search for the property “rootFolder”.

python_esxi_mob_3

Patrick Terlisten/ www.vcloudnine.de/ Creative Commons CC0

Click on the value “ha-folder-root.” The property “childEntity” is an ManagedObjectReference (MOR) and references to all datacenters (the counting starts at 0) known to the ESXi or vCenter. The value “childEntity[0]” will give us the first datacenter.

python_esxi_mob_4

Patrick Terlisten/ www.vcloudnine.de/ Creative Commons CC0

If we have the datacenter, the way to get the names of the VMs is the same. You can use the MOB, to verify this.

vms = datacenter.vmFolder.childEntity

Click on the value “ha-datacenter”. At the bottom of the list, you will find the property “vmFolder”.

python_esxi_mob_5

Patrick Terlisten/ www.vcloudnine.de/ Creative Commons CC0

Click on the value “ha-folder-vm”.

python_esxi_mob_6

Patrick Terlisten/ www.vcloudnine.de/ Creative Commons CC0

The MOR “childEntity” references to two VMs. Click on one of the IDs.

python_esxi_mob_7

Patrick Terlisten/ www.vcloudnine.de/ Creative Commons CC0

The property “name” includes the name of the VM. Because of this, we can use a simple

for i in vms:
    print(i.name)

to get the name for each VM.

Summary

This was only a short introduction into pyVmomi. You should be now able to install pyVmomi, make a connection to the vSphere API and retrieve some basic stuff.

Every day I discover something new. It’s important to understand how the vSphere API works. Play with pyVmomi and with the vSphere API. It looks harder as it is.

btw: There is a Hands-on-Lab available “HOL-SDC-1622 VMware Development Tools and SDKs“. Check it out!