<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Openstack on Stephen Finucane (Fin-oo-can)</title>
    <link>https://that.guru/categories/openstack/</link>
    <description>Recent content in Openstack on Stephen Finucane (Fin-oo-can)</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-IE</language>
    <lastBuildDate>Mon, 05 Jan 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://that.guru/categories/openstack/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Are We Typed Yet?</title>
      <link>https://that.guru/blog/are-we-typed-yet/</link>
      <pubDate>Mon, 05 Jan 2026 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/are-we-typed-yet/</guid>
      <description>&lt;p&gt;This is a living document that describes the status of typing in various Python packages in the OpenStack system.
Currently this document focuses on libraries and clients. While many services have introduced some degree of typing,
none are complete and they are not intended to be consumed by others, thus they are not documented here.&lt;/p&gt;
&lt;p&gt;We determine whether a package is typed or not by looking for two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;py.typed&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;This is what Python itself uses to determine whether to consume type hints from the library. If this file is
present, the package is considered at least partially typed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use of &lt;a href=&#34;https://mypy.readthedocs.io/en/stable/getting_started.html#strict-mode-and-configuration&#34;&gt;mypy&amp;rsquo;s strict mode&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;mypy is currently the only type checker in use across OpenStack projects. If &lt;code&gt;[tool.mypy] strict&lt;/code&gt; is set to &lt;code&gt;true&lt;/code&gt;
in a package&amp;rsquo;s &lt;code&gt;pyproject.toml&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; the &lt;code&gt;py.typed&lt;/code&gt; file is present, then the library is considered &lt;em&gt;fully&lt;/em&gt; typed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;Last updated April 12, 2026&lt;/div&gt;
&lt;/aside&gt;

&lt;h2 id=&#34;oslo-libraries&#34;&gt;Oslo libraries&lt;/h2&gt;

  
    &lt;table&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th&gt;Package&lt;/th&gt;
          &lt;th&gt;Typed?&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/automaton&#34;&gt;automaton&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 3.4.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/castellan&#34;&gt;castellan&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              ❌
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/debtcollector&#34;&gt;debtcollector&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 3.1.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/etcd3gw&#34;&gt;etcd3gw&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 2.6.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/futurist&#34;&gt;futurist&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 3.3.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/microversion-parse&#34;&gt;microversion-parse&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 2.1.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/openstackdocstheme&#34;&gt;openstackdocstheme&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 3.6.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/os-api-ref&#34;&gt;os-api-ref&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 3.2.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.cache&#34;&gt;oslo.cache&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 4.1.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.concurrency&#34;&gt;oslo.concurrency&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 7.3.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.config&#34;&gt;oslo.config&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (unreleased)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.context&#34;&gt;oslo.context&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 6.3.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.db&#34;&gt;oslo.db&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              ❌
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.i18n&#34;&gt;oslo.i18n&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 6.7.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.limit&#34;&gt;oslo.limit&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 2.9.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.log&#34;&gt;oslo.log&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 8.0.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.messaging&#34;&gt;oslo.messaging&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              ❌
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.metrics&#34;&gt;oslo.metrics&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 0.15.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.middleware&#34;&gt;oslo.middleware&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 7.0.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.policy&#34;&gt;oslo.policy&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 5.0.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.privsep&#34;&gt;oslo.privsep&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 3.10.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.reports&#34;&gt;oslo.reports&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (unreleased)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.rootwrap&#34;&gt;oslo.rootwrap&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 7.9.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.serialization&#34;&gt;oslo.serialization&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 5.9.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.service&#34;&gt;oslo.service&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              ❌
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.upgradecheck&#34;&gt;oslo.upgradecheck&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 2.7.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.utils&#34;&gt;oslo.utils&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 9.2.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.versionedobjects&#34;&gt;oslo.versionedobjects&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (unreleased)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslo.vmware&#34;&gt;oslo.vmware&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              ❌
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/oslotest&#34;&gt;oslotest&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 6.1.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/osprofiler&#34;&gt;osprofiler&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (unreleased)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/sphinx-feature-classification&#34;&gt;sphinx-feature-classification&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 2.1.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/stevedore&#34;&gt;stevedore&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 5.6.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/taskflow&#34;&gt;taskflow&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              ❌
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/tooz&#34;&gt;tooz&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              ❌
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/whereto&#34;&gt;whereto&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 0.6.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
      &lt;/tbody&gt;
    &lt;/table&gt;

    
    
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
    
    
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;&lt;p&gt;The following packages have been excluded:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;cookiecutter (a cookiecutter template)&lt;/li&gt;&lt;li&gt;devstack-plugin-amqp1 (a devstack plugin)&lt;/li&gt;&lt;li&gt;devstack-plugin-kafka (a devstack plugin)&lt;/li&gt;&lt;li&gt;openstack-doc-tools (docs-only)&lt;/li&gt;&lt;li&gt;oslo-cookiecutter (a cookiecutter template)&lt;/li&gt;&lt;li&gt;oslo-specs (docs-only)&lt;/li&gt;&lt;li&gt;oslo.tools (deprecated)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;
&lt;/aside&gt;
    
  


&lt;h2 id=&#34;sdks-and-clients&#34;&gt;SDKs and Clients&lt;/h2&gt;

  
    &lt;table&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th&gt;Package&lt;/th&gt;
          &lt;th&gt;Typed?&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/cliff&#34;&gt;cliff&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 4.11.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/keystoneauth&#34;&gt;keystoneauth&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 5.13.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/openstacksdk&#34;&gt;openstacksdk&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ⚠️ (partial, since 0.37.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/os-service-types&#34;&gt;os-service-types&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 1.8.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/osc-lib&#34;&gt;osc-lib&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              
                ✅ (since 4.2.0)
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
        &lt;tr&gt;
          &lt;td&gt;&lt;a href=&#34;https://pypi.org/project/python-openstackclient&#34;&gt;python-openstackclient&lt;/a&gt;&lt;/td&gt;
          &lt;td&gt;
            
              ❌
            
          &lt;/td&gt;
        &lt;/tr&gt;
        
      &lt;/tbody&gt;
    &lt;/table&gt;

    
    
    
      
    
      
    
      
    
      
    
      
    
    
    
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;&lt;p&gt;The following packages have been excluded:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;codegenerator (not intended for external consumption)&lt;/li&gt;&lt;li&gt;openapi (not intended for external consumption)&lt;/li&gt;&lt;li&gt;openstackclient (meta package)&lt;/li&gt;&lt;li&gt;os-client-config (deprecated)&lt;/li&gt;&lt;li&gt;requestsexceptions (deprecated)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;
&lt;/aside&gt;
    
  


</description>
    </item>
    
    <item>
      <title>Manage Your OpenStack Resources From Kubernetes With ORC</title>
      <link>https://that.guru/talks/manage-your-openstack-resources-from-kubernetes-with-orc/</link>
      <pubDate>Sat, 18 Oct 2025 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/talks/manage-your-openstack-resources-from-kubernetes-with-orc/</guid>
      <description>&lt;p&gt;This talk introduced OpenStack Resource Controller (ORC), a set of controllers that allows management of OpenStack
resources using Kubernetes CRDs. It was delivered during &lt;a href=&#34;https://summit2025.openinfra.org/a/schedule/#&#34;&gt;OpenInfra Summit Europe&lt;/a&gt; in Paris in October 2025.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Managing OpenStack resources efficiently can be complex, especially when striving for cloud-native agility and GitOps
workflows. In this talk, we&amp;rsquo;ll introduce the OpenStack Resource Controller (ORC), a powerful solution combining the
benefits of Kubernetes Custom Resource Definitions (CRDs) and controllers with OpenStack&amp;rsquo;s rich and mature APIs and
application ecosystem. We&amp;rsquo;ll explore ORC&amp;rsquo;s fundamental &amp;ldquo;raison d&amp;rsquo;être,&amp;rdquo; highlighting how it directly addresses common
provisioning pain points many developers and operators face. We&amp;rsquo;ll compare ORC against “the competition”, exploring
both its strengths and weaknesses. Discover its core goals, design philosophy, and how ORC simplifies the declarative
management of your OpenStack infrastructure, enabling seamless resource orchestration for modern cloud-native
applications.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;More information is available on the &lt;a href=&#34;https://summit2025.openinfra.org/a/schedule/#&#34;&gt;OpenInfra Summit Europe 2025&lt;/a&gt; website.&lt;/p&gt;

&lt;script async class=&#34;speakerdeck-embed&#34; data-id=&#34;fe689fb7df5f470bacc5f701b2ee968c&#34; data-ratio=&#34;1.77777777777778&#34; src=&#34;//speakerdeck.com/assets/embed.js&#34;&gt;&lt;/script&gt;


</description>
    </item>
    
    <item>
      <title>Steps Down the OpenAPI Path</title>
      <link>https://that.guru/talks/steps-down-the-openapi-path/</link>
      <pubDate>Sat, 18 Oct 2025 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/talks/steps-down-the-openapi-path/</guid>
      <description>&lt;p&gt;This talks was delivered during the &lt;a href=&#34;https://summit2025.openinfra.org/a/schedule/#&#34;&gt;OpenInfra Summit Europe&lt;/a&gt; in Paris in
October 2025. It was a continuation of a talk I gave at the &lt;a href=&#34;https://that.guru/talks/api-contracts-bringing-openapi-and-typing-to-openstack/&#34;&gt;previous OpenInfra Summit&lt;/a&gt;
and focused on the continued development of the OpenAPI effort over the intervening two OpenStack releases.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;OpenStack has been on a journey towards implementing formal OpenAPI v3.1 API specifications for all services for a
number of releases now. We have many goals - better understanding our APIs, improving our documentation, easing client
and library development, etc. - and we are finally delivering on many of these. Come learn about the milestones we&amp;rsquo;ve
reached to date, and the benefits we&amp;rsquo;re already seeing from these efforts, and our plans for the next . We&amp;rsquo;ll talk
about the complexities of implementing common functionality across services with vastly different APIs and stacks, the
cool/horrifying things we&amp;rsquo;ve (re)discovered about our APIs, and the oxidation of our clients. We&amp;rsquo;ll also demonstrate
some of the fruits of our labours and discuss how you, as a user, deployer, or contributor, can get involved in the
effort.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;More information is available on the &lt;a href=&#34;https://summit2025.openinfra.org/a/schedule/#&#34;&gt;OpenInfra Summit Europe 2025&lt;/a&gt; website.&lt;/p&gt;

&lt;script async class=&#34;speakerdeck-embed&#34; data-id=&#34;7f0c15e3f8554064b4f69db5b5951b27&#34; data-ratio=&#34;1.77777777777778&#34; src=&#34;//speakerdeck.com/assets/embed.js&#34;&gt;&lt;/script&gt;


</description>
    </item>
    
    <item>
      <title>Glance Tasks API</title>
      <link>https://that.guru/blog/glance-tasks-api/</link>
      <pubDate>Fri, 15 Aug 2025 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/glance-tasks-api/</guid>
      <description>&lt;p&gt;One the joys (or miseries) of working on OpenStack client tooling is that you get exposed to all the nuances of the
OpenStack API tooling. The microservice-like architecture, with projects being managed by often wholly separate teams,
means there&amp;rsquo;s precious little consistency across APIs, beyond that enforced by the long-dormant &lt;a href=&#34;https://specs.openstack.org/openstack/api-sig/&#34;&gt;API SIG&lt;/a&gt;. I&amp;rsquo;ve
touched on this before, covering things like the disparity in &lt;a href=&#34;https://that.guru/blog/api-versioning-in-openstack/&#34;&gt;API versioning&lt;/a&gt;, and its been particularly
notable during work on the &lt;a href=&#34;https://that.guru/blog/an-update-on-openapi-in-openstack/&#34;&gt;OpenAPI effort&lt;/a&gt;. OpenStack is also pretty old (at least in software terms) and most
service APIs come with at least a decade of baggage: there is an abundance of APIs that still exist in services but are
no longer relevant or useful in modern deployments.&lt;/p&gt;
&lt;p&gt;The Glance Tasks API is an example of one such API. It&amp;rsquo;s a positively ancient API, dating back to the &lt;a href=&#34;https://wiki.openstack.org/wiki/Glance-tasks-api&#34;&gt;Havana
release&lt;/a&gt; (2013), and has long-since been made redundant by the image import API introduced in the Mitaka
release (2016). Nonetheless, python-openstackclient (OSC) and openstacksdk (SDK) aim to support all OpenStack APIs, and
the tasks API, while deprecated, is still present in Glance in the Flamingo release, meaning OSC and SDK should support
them.&lt;/p&gt;
&lt;p&gt;As always, when adding support for a new API to SDK and OSC, its important that you figure out how that API actually
works, ideally by playing around with the API using a local DevStack: the OpenStack API docs are good, but they&amp;rsquo;re not
flawless, and if I had a euro for every time the API docs had said one thing only for the API to behave a different way,
I wouldn&amp;rsquo;t be stuck doing my own painting. Anywho, adding support for the tasks API is no different and I conducted a
few tests to prove things out while reviewing some recent patches against both SDK and OSC. Below are my test notes,
which I&amp;rsquo;m sharing in case anyone else ends up having to do something similar.&lt;/p&gt;
&lt;h2 id=&#34;notes&#34;&gt;Notes&lt;/h2&gt;
&lt;p&gt;We start by creating a task. Because the tasks API is deprecated and replaced by the image import process, OSC has
indicated that it won&amp;rsquo;t add support for task creation. Thus, for this one we need to use either glanceclient or &lt;code&gt;curl&lt;/code&gt;.
I used the former, creating a sample task for an existing image. I provided syntactically valid-but-nonsense input since
I only wanted to test the behavior of the API; I didn&amp;rsquo;t actually need the task to complete:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ glance task-create --type &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;api_image_import&amp;#34;&lt;/span&gt; --input &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &amp;#34;image_id&amp;#34;: &amp;#34;8bd3bebc-8e1b-40fe-a292-1a63a53dcfd9&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &amp;#34;import_req&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    &amp;#34;method&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;      &amp;#34;name&amp;#34;: &amp;#34;copy-image&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    &amp;#34;all_stores&amp;#34;: true,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    &amp;#34;all_stores_must_succeed&amp;#34;: false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &amp;#34;backend&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    &amp;#34;fast&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    &amp;#34;cheap&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    &amp;#34;slow&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    &amp;#34;reliable&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    &amp;#34;common&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  ]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once created, I was able to view this task in a few ways. Firstly, by listing all tasks. This is supported by OSC, so I
used that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack image task list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+--------------------------------------+------------------+------------+----------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| ID                                   | Type             | Status     | Owner                            |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+--------------------------------------+------------------+------------+----------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 546641fe-6a35-4b0e-90d2-b45367fc94b2 | api_image_import | processing | d8dea803f1fe44e2bdf9d9d017750b4e |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+--------------------------------------+------------------+------------+----------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;or, via &lt;code&gt;curl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ token&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;openstack token issue -f value -c id&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ curl -s -X GET &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://10.0.111.148/image/v2/tasks&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    -H &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Accept: application/json&amp;#34;&lt;/span&gt;-H &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; -H &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;X-Auth-Token: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;token&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; | jq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tasks&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;546641fe-6a35-4b0e-90d2-b45367fc94b2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;api_image_import&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;processing&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;owner&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;d8dea803f1fe44e2bdf9d9d017750b4e&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;created_at&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2025-08-15T11:32:10Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;updated_at&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2025-08-15T11:32:10Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;self&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/v2/tasks/546641fe-6a35-4b0e-90d2-b45367fc94b2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;schema&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/v2/schemas/task&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;first&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/v2/tasks&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;schema&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/v2/schemas/tasks&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I could also inspect the individual task:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack image task show 546641fe-6a35-4b0e-90d2-b45367fc94b2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| Field      | Value                                                                                                                                                                                                                    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| created_at | 2025-08-15T11:32:10Z                                                                                                                                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| expires_at | None                                                                                                                                                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| id         | 546641fe-6a35-4b0e-90d2-b45367fc94b2                                                                                                                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| input      | &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;image_id&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;8bd3bebc-8e1b-40fe-a292-1a63a53dcfd9&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;import_req&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;method&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;copy-image&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;all_stores&amp;#39;&lt;/span&gt;: True, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;all_stores_must_succeed&amp;#39;&lt;/span&gt;: False&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;backend&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;fast&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;cheap&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;slow&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;reliable&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;common&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]}&lt;/span&gt; |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| message    |                                                                                                                                                                                                                          |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| owner_id   | d8dea803f1fe44e2bdf9d9d017750b4e                                                                                                                                                                                         |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| properties |                                                                                                                                                                                                                          |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| result     | None                                                                                                                                                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| status     | processing                                                                                                                                                                                                               |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| type       | api_image_import                                                                                                                                                                                                         |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| updated_at | 2025-08-15T11:32:10Z                                                                                                                                                                                                     |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;again, via &lt;code&gt;curl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ curl -s -X GET &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://10.0.111.148/image/v2/tasks/546641fe-6a35-4b0e-90d2-b45367fc94b2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    -H &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Accept: application/json&amp;#34;&lt;/span&gt;-H &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; -H &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;X-Auth-Token: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;token&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; | jq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;546641fe-6a35-4b0e-90d2-b45367fc94b2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;input&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;8bd3bebc-8e1b-40fe-a292-1a63a53dcfd9&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;import_req&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;method&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;copy-image&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;all_stores&amp;#34;&lt;/span&gt;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;all_stores_must_succeed&amp;#34;&lt;/span&gt;: false
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;backend&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fast&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cheap&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;slow&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;reliable&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;common&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;api_image_import&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;processing&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;owner&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;d8dea803f1fe44e2bdf9d9d017750b4e&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;: null,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;created_at&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2025-08-15T11:32:10Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;updated_at&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2025-08-15T11:32:10Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;self&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/v2/tasks/546641fe-6a35-4b0e-90d2-b45367fc94b2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;schema&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/v2/schemas/task&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;8bd3bebc-8e1b-40fe-a292-1a63a53dcfd9&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;request_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;req-1918a068-0ce3-4eff-81f5-625e2d0037ae&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;105a84e11f0a421ea814833a5d23f37b&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, I could list tasks associated with the image. For reasons unbeknownst to me, glance opted to implement this
via a separate, nested API (&lt;code&gt;/images/{imageID}/tasks&lt;/code&gt;) rather than a new filter on the existing API
(&lt;code&gt;/tasks?image_id={imageID}&lt;/code&gt;). This is supposedly supported by glanceclient, but attempting to use this command with the
latest glanceclient version yielded the following error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ glance image-tasks 8bd3bebc-8e1b-40fe-a292-1a63a53dcfd9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Server does not support image tasks API &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;v2.12&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This seemed odd since the API &lt;em&gt;should&lt;/em&gt; be supported. Sure enough, when I tried with &lt;code&gt;curl&lt;/code&gt;, things worked as expected:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ curl -s -X GET &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://10.0.111.148/image/v2/tasks/546641fe-6a35-4b0e-90d2-b45367fc94b2&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    -H &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Accept: application/json&amp;#34;&lt;/span&gt;-H &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; -H &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;X-Auth-Token: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;token&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; | jq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;546641fe-6a35-4b0e-90d2-b45367fc94b2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;input&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;8bd3bebc-8e1b-40fe-a292-1a63a53dcfd9&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;import_req&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;method&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;copy-image&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;all_stores&amp;#34;&lt;/span&gt;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;all_stores_must_succeed&amp;#34;&lt;/span&gt;: false
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;backend&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fast&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cheap&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;slow&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;reliable&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;common&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;api_image_import&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;processing&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;owner&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;d8dea803f1fe44e2bdf9d9d017750b4e&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;: null,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;created_at&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2025-08-15T11:32:10Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;updated_at&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2025-08-15T11:32:10Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;self&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/v2/tasks/546641fe-6a35-4b0e-90d2-b45367fc94b2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;schema&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/v2/schemas/task&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;8bd3bebc-8e1b-40fe-a292-1a63a53dcfd9&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;request_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;req-1918a068-0ce3-4eff-81f5-625e2d0037ae&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;105a84e11f0a421ea814833a5d23f37b&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Clearly a bug report is needed here.&lt;/p&gt;
&lt;p&gt;Finally, task deletion. There isn&amp;rsquo;t a task deletion API. Rather, tasks have an expiry date, after which glance will reap
the task. You can likely force this with &lt;code&gt;glance-manage&lt;/code&gt; but I didn&amp;rsquo;t care enough to do so.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A Closer Look at the Cinder CSI Driver and the Topology Feature</title>
      <link>https://that.guru/blog/csi-drivers-and-openstack/</link>
      <pubDate>Thu, 03 Apr 2025 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/csi-drivers-and-openstack/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve recently found myself once again working on the OpenStack Cinder CSI Driver and the Operator that OpenShift uses to
deploy this. This work has inspired me to improve my knowledge of how the Cinder CSI Driver - and CSI drivers in
general - work. Below is my current high-level understanding of both as well as a quick summary of changes we are making
to the Cinder CSI Driver Operator in OpenShift 4.19.&lt;/p&gt;
&lt;h2 id=&#34;deployment-of-the-cinder-csi-driver&#34;&gt;Deployment of the Cinder CSI Driver&lt;/h2&gt;
&lt;p&gt;The Cinder CSI Driver Operator deploys the driver itself as two components: a controller component and a per-node
component, which is the &lt;a href=&#34;https://kubernetes-csi.github.io/docs/deploying.html&#34;&gt;typical deployment model for CSI Drivers&lt;/a&gt;. The controller component is managed
via a Deployment which you can see &lt;a href=&#34;https://github.com/openshift/csi-operator/blob/release-4.18/assets/overlays/openstack-cinder/generated/standalone/controller.yaml&#34;&gt;here&lt;/a&gt;. It consists of the controller plugin and a number of sidecar
containers which interface between the controller and the Kubernetes controller manager (&lt;code&gt;kube-controller-manager&lt;/code&gt;) via
a Unix domain socket and handle different RPC calls. Breaking these down one-by-one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The controller plugin container (&lt;code&gt;csi-driver&lt;/code&gt;) implements the Controller Service and Identity Service set of RPCs
described in the &lt;a href=&#34;https://github.com/container-storage-interface/spec/blob/master/spec.md#rpc-interface&#34;&gt;CSI spec&lt;/a&gt;. It is responsible for handling requests by calling the cloud provider&amp;rsquo;s APIs
(Cinder and Nova, this case).&lt;/p&gt;
&lt;p&gt;You can find the Cinder CSI implementation of the Controller Service &lt;a href=&#34;https://github.com/kubernetes/cloud-provider-openstack/blob/release-1.32/pkg/csi/cinder/controllerserver.go&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The attacher sidecar container (&lt;code&gt;csi-attacher&lt;/code&gt;) watches for attach and detach calls and calls
&lt;code&gt;ControllerPublishVolume&lt;/code&gt; and &lt;code&gt;ControllerUnpublishVolume&lt;/code&gt;, respectively. (&lt;a href=&#34;https://github.com/kubernetes-csi/external-attacher&#34;&gt;source&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The provisioner sidecar container (&lt;code&gt;csi-provisioner&lt;/code&gt;) watches for PVC creation and deletion and calls &lt;code&gt;CreateVolume&lt;/code&gt;
and &lt;code&gt;DeleteVolume&lt;/code&gt;, respectively. (&lt;a href=&#34;https://github.com/kubernetes-csi/external-provisioner&#34;&gt;source&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The snapshotter sidecar container (&lt;code&gt;csi-snapshotter&lt;/code&gt;) does the same as the provisioner but for snapshots, calling
&lt;code&gt;CreateSnapshot&lt;/code&gt; and &lt;code&gt;DeleteSnapshot&lt;/code&gt;. (&lt;a href=&#34;https://github.com/kubernetes-csi/external-snapshotter&#34;&gt;source&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The resizer sidecar container (&lt;code&gt;csi-resizer&lt;/code&gt;) watches for changes to a PVC and calls &lt;code&gt;ControllerExpandVolume&lt;/code&gt; as
necessary. (&lt;a href=&#34;https://github.com/kubernetes-csi/external-resizer&#34;&gt;source&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The per-node component, by comparison, is deployed to each node using a DaemonSet. You can see the definition for this
&lt;a href=&#34;https://github.com/openshift/csi-operator/blob/release-4.18/assets/overlays/openstack-cinder/generated/standalone/node.yaml&#34;&gt;here&lt;/a&gt;. It consists of the node plugin and a single sidecar container:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The node plugin container (&lt;code&gt;csi-driver&lt;/code&gt;) implements the Node Service and Identity Service sets of RPCs described in
the &lt;a href=&#34;https://github.com/container-storage-interface/spec/blob/master/spec.md#rpc-interface&#34;&gt;CSI spec&lt;/a&gt;. It is responsible for reporting information about the node and for bind mounting volumes
once they are attached to the host. Specifically, it reports an ID of the node, the maximum number of volumes it
supports, and topology information. In the case of Cinder, both the ID and topology information are sourced from the
metadata service, while the volume limit is determined via a configuration option.&lt;/p&gt;
&lt;p&gt;You can find the Cinder CSI implementation of the Node Service &lt;a href=&#34;https://github.com/kubernetes/cloud-provider-openstack/blob/release-1.32/pkg/csi/cinder/nodeserver.go&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The node-driver-registrar sidecar container (&lt;code&gt;csi-node-driver-registrar&lt;/code&gt;) registers the CSI driver with kubelet,
allowing kubelet to call &lt;code&gt;NodeGetInfo&lt;/code&gt;, &lt;code&gt;NodeStageVolume&lt;/code&gt;, &lt;code&gt;NodePublishVolume&lt;/code&gt; etc. (&lt;a href=&#34;https://github.com/kubernetes-csi/node-driver-registrar&#34;&gt;source&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;changes-to-topology-auto-configuration&#34;&gt;Changes to topology auto-configuration&lt;/h2&gt;
&lt;p&gt;Now that we understand the various components that make up the CSI Driver, let&amp;rsquo;s take a look at the changes we&amp;rsquo;ve been
working on in this area. As I&amp;rsquo;ve &lt;a href=&#34;https://that.guru/blog/availability-zones-in-openstack-and-openshift-part-2&#34;&gt;previously discussed&lt;/a&gt;, the Cinder CSI Driver has support for
Availability Zones (or, in CSI parlance, the CSI Topology Feature) and since OpenShift 4.16 or so the Cinder CSI Driver
Operator has supported auto-configuration of this feature. Without getting too into the weeds, the way this is
determined is via a simple set comparison: the set of Compute AZs is compared to the set of Block Storage AZs, and if
the former isn&amp;rsquo;t a subset of the latter (e.g. if there was a Compute AZ called &lt;code&gt;foo&lt;/code&gt; but no equivalent Block Storage AZ
of the same name) then we determine that the feature should be disabled. Once we&amp;rsquo;ve determined this, we toggle the
&lt;code&gt;Topology&lt;/code&gt; feature gate of the CSI Provisioner sidecar container, thus ensuring that the &lt;code&gt;AccessibilityRequirements&lt;/code&gt;
field of the &lt;code&gt;CreateVolumeRequest&lt;/code&gt; struct generated by the provisioner (and fed to the controller plugin) &lt;a href=&#34;https://github.com/kubernetes-csi/external-provisioner/blob/release-5.1/pkg/controller/controller.go#L682-L697&#34;&gt;would not be
populated&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;However, things change and the Topology feature is now considered mature and is enabled by default. This means it is
likely that the feature flag will be removed at some point in the not-too-distant future, which in turn means we need to
find another way to enable and disable topology support from the operator. The solution we&amp;rsquo;ve arrived at is to copy what
was done in Manila and add support for a new &lt;code&gt;--with-topology&lt;/code&gt; option to both the controller plugin and node plugin
services. This new option has different effects depending on where it is set:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For the controller plugin, the option determines whether (a) the calls to Cinder include a requested AZ and (b)
whether the &lt;code&gt;CreateVolumeResponse&lt;/code&gt; returned by the &lt;code&gt;CreateVolume&lt;/code&gt; call includes topology accessibility information.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For the node plugin, the option determines whether the node reports (a) the capability (as part of the
&lt;code&gt;GetPluginCapabilities&lt;/code&gt; RPC) and (b) a topology information (as part of the &lt;code&gt;NodeGetInfo&lt;/code&gt; call).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This work has been implemented in &lt;a href=&#34;https://github.com/kubernetes/cloud-provider-openstack/pull/2743&#34;&gt;kubernetes/cloud-provider-openstack#2743&lt;/a&gt; (with some follow-ups in
&lt;a href=&#34;https://github.com/kubernetes/cloud-provider-openstack/pull/2862&#34;&gt;kubernetes/cloud-provider-openstack#2862&lt;/a&gt; and &lt;a href=&#34;https://github.com/kubernetes/cloud-provider-openstack/pull/2865&#34;&gt;kubernetes/cloud-provider-openstack#2865&lt;/a&gt;). With
the new option in place, we&amp;rsquo;ve been able to change how the Operator toggles the Topology feature. Now, instead of
enabling and disabling the feature gate on the &lt;code&gt;csi-provisioner&lt;/code&gt; container, it can enable and disable the feature on the
&lt;code&gt;csi-driver&lt;/code&gt; containers in the controller deployment and node daemonsets. &lt;em&gt;That&lt;/em&gt; work has been implemented in
&lt;a href=&#34;https://github.com/openshift/csi-operator/pull/345&#34;&gt;openshift/csi-operator#345&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m hoping this is last time I feel the need to write about the Cinder CSI Driver and its Operator. The work we&amp;rsquo;ve done
here should future proof both and ensure that, barring major changes to the CSI Spec itself, few other changes will be
needed for the foreseeable. I would however like to get a better understanding of how the equivalent feature in the
Manila CSI Driver works, so watch our for a possible post on that topic down the line.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>An Update on OpenAPI in Openstack</title>
      <link>https://that.guru/blog/an-update-on-openapi-in-openstack/</link>
      <pubDate>Thu, 03 Apr 2025 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/an-update-on-openapi-in-openstack/</guid>
      <description>&lt;p&gt;I previously presented on our work to bring OpenAPI to OpenStack as part of the 2024 OpenInfra Summit Asia, the slides
for which you can find &lt;a href=&#34;https://that.guru/talks/api-contracts-bringing-openapi-and-typing-to-openstack/&#34;&gt;here&lt;/a&gt;. Since that talk, another
release cycle has come and gone and our work has continued to progress. Below is a summary of the current &amp;ldquo;state of
play&amp;rdquo; for OpenAPI support in OpenStack and a reminder of our long-term goals in the area.&lt;/p&gt;

&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;This information is accurate as of the start of the 2025.2 (Flamingo) cycle. I will attempt to update it over the course
of this cycle.&lt;/div&gt;
&lt;/aside&gt;


&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;Updated on 2025-04-15 to better describe the ongoing work in OSC and SDK.&lt;/div&gt;
&lt;/aside&gt;

&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;The work to add OpenAPI schemas can be broken into two parts: adding schemas to services and writing tooling to consume
these schemas and generate both documentation and clients.&lt;/p&gt;
&lt;h3 id=&#34;services&#34;&gt;Services&lt;/h3&gt;
&lt;p&gt;The tl;dr: of this section is that we are relying on the fact that OpenAPI 3.1 is a superset of JSON Schema Draft
2020-12 and are adding JSON Schema schemas to as many services as possible. When put this way, it sounds pretty simple
but as is often the case, the devil is in the detail. OpenStack is made up of multiple independent services maintained
by different groups of people, and while the Oslo project has helped ensure some level of consistency around things like
configuration (&lt;code&gt;oslo.conf&lt;/code&gt;), database connectivity (&lt;code&gt;oslo.db&lt;/code&gt;) and messaging (&lt;code&gt;oslo.messaging&lt;/code&gt;), there is huge variance
in the API frameworks used:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Nova, Cinder, Glance, and Manila use a combination of &lt;a href=&#34;https://pypi.org/project/Routes/&#34;&gt;Routes&lt;/a&gt; (for routing), &lt;a href=&#34;https://pypi.org/project/WebOb/&#34;&gt;WebOb&lt;/a&gt; (for
request/response models), &lt;a href=&#34;https://pypi.org/project/Paste/&#34;&gt;Paste&lt;/a&gt; (for application dispatch) and &lt;a href=&#34;https://pypi.org/project/PasteDeploy/&#34;&gt;PasteDeploy&lt;/a&gt; (for
middleware).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Neutron uses the same Routes + WebOb + Paste + PasteDeploy combo used by Nova, Cinder, Glance, and Manila, but with
the addition of &lt;a href=&#34;https://pypi.org/project/pecan/&#34;&gt;Pecan&lt;/a&gt; in place of the &amp;ldquo;homegrown&amp;rdquo; WSGI frameworks used in those projects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Keystone uses &lt;a href=&#34;https://pypi.org/project/Flask/&#34;&gt;Flask&lt;/a&gt; and &lt;a href=&#34;https://pypi.org/project/Flask-RESTful/&#34;&gt;Flask-Restful&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Swift uses PasteDeploy (but I admittedly know very little about Swift).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ironic uses Pecan (which in turn uses WebOb, so you&amp;rsquo;ll see references to this too)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;etc etc&amp;hellip;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fortunately, despite the wide differences in frameworks, they pretty much all have the same building blocks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Controllers (or Applications) which are responsible for a given resource and handles calls for same. These are
typically classes with methods for each HTTP verb that the API supports.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Middleware that inspects and/or modifies requests and responses.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Routers that map a HTTP request to a controller. This is typically implemented as a special type of middleware.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this model, both parsing of requests and generation of responses happens in the controller methods, which makes this
a natural place to add validation for same. And there are a few things we want to validate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;API version (for services that uses &lt;a href=&#34;https://that.guru/blog/api-versioning-in-openstack/&#34;&gt;API microversions&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Request path and query string parameters&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Request and response bodies&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By wrapping the controller methods with decorators, we we are able to inspect both the request or response objects,
comparing them against schemas for same.&lt;/p&gt;
&lt;h3 id=&#34;tooling&#34;&gt;Tooling&lt;/h3&gt;
&lt;p&gt;Having schemas in place for all services is of little help if we don&amp;rsquo;t do anything with them. To this end, we want
tooling that can inspect services and extract their JSON Schema schemas, combining them to produce OpenAPI
schemas.&lt;/p&gt;
&lt;p&gt;Once we have these OpenAPI schemas, we can start generating (self-validating) documentation and clients/libraries. For
the former, OpenAPI will replace the &lt;code&gt;os-api-ref&lt;/code&gt; Sphinx extension currently used across OpenStack. &lt;code&gt;os-api-ref&lt;/code&gt; allows
us to describe our APIs in reStructuredText and it is a tool that has worked relatively well for us, but the lack of
machine readability means it&amp;rsquo;s hard to validate against the code. For the latter, we hope to lessen the burden of
maintaining libraries and clients in multiple languages, as this has proven very challenging to do given the very large
number of OpenStack APIs in multiple. Once again, OpenAPI is better suited to this challenge than &lt;code&gt;os-api-ref&lt;/code&gt; or
anything else we have.&lt;/p&gt;
&lt;h2 id=&#34;current-status-and-future-plans&#34;&gt;Current status and future plans&lt;/h2&gt;
&lt;h3 id=&#34;nova&#34;&gt;Nova&lt;/h3&gt;
&lt;p&gt;Nova started from the best position, since it was already using JSON Schema for request validation. However, there were
a couple of issues to overcome:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The version of JSON Schema used for the schemas, Draft 04, is over 12 years old, meaning the schemas needed migrating
to Draft 2020-12.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There were two different mechanisms for API versioning: if-else checks inside the controller methods, plus a decorator
that relied on the &lt;a href=&#34;https://docs.python.org/3/howto/descriptor.html&#34;&gt;descriptor protocol&lt;/a&gt; to allow us to define
version-specific controller methods. The latter made inspection of the API router more difficult than necessary and
had to be replaced.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;While many APIs had request query string and request body schemas, not all of them did.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Most importantly, there were no schemas for response bodies.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most of these have now been resolved. We have bumped our schemas to Draft 2020-12, we have added all the missing request
schemas, and we have added response body schemas for a number of resources. The outstanding changes to address the API
versioning issues and add the remaining response body schemas are all ready and just waiting for review, so with any
luck we will be able to close this out in the 2025.2 (Flamingo) release. Once this work has merged, the final step will
be to start generating api-ref documentation from the OpenAPI schemas instead of using the &lt;code&gt;os-api-ref&lt;/code&gt; tool we
currently use. The patches for Nova can be found &lt;a href=&#34;https://review.opendev.org/q/project:openstack/nova+topic:openapi&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;cinder&#34;&gt;Cinder&lt;/h3&gt;
&lt;p&gt;Cinder was in a very similar position to Nova thanks to their shared lineage. This means it had the same advantage -
pre-existing use of JSON Schema for request validation - and the same issues. However, it also had the added issue of
having a mountain of tech debt mainly related to the support for multiple API versions that Cinder offered until
relatively recently. This has necessitated a lot of additional cleanup patches to do things like remove the
&lt;code&gt;cinder.api.v2&lt;/code&gt; module and consolidate everything under &lt;code&gt;cinder.api.v3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Unfortunately, while the bulk of the changes have been written, none of them have merged. I&amp;rsquo;m hoping we can double down
on this in 2025.2 (Flamingo) release and start making some progress. The patches for Cinder can be found
&lt;a href=&#34;https://review.opendev.org/q/project:openstack/nova+topic:openapi&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;keystone&#34;&gt;Keystone&lt;/h3&gt;
&lt;p&gt;Once again, Keystone had the good fortune of having existing use of JSON Schema for request query string and request
body validation, but this was done inconsistently and didn&amp;rsquo;t cover response body schemas. Most of the work here has
focused on adding these missing schemas and making the router easier to inspect by moving validation from inside the
controller methods to decorators and splitting methods that previously handling multiple endpoints (e.g. &lt;code&gt;GET /foo&lt;/code&gt; and
&lt;code&gt;GET /foo/123&lt;/code&gt;) into multiple single-purpose methods.&lt;/p&gt;
&lt;p&gt;Many resources have been fully specced by now but some remain. In addition, there are some decisions to be made
regarding support for undocumented API options that have been (re)discovered during this work. None of it should be
insurmountable, however. The patches for Keystone can be found
&lt;a href=&#34;https://review.opendev.org/q/project:openstack/keystone+topic:openapi&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;manila&#34;&gt;Manila&lt;/h3&gt;
&lt;p&gt;Yet another service with JSON Schema already in place. Once again, the work here consists of adding missing schemas and
making the router easier to inspect. A small number of patches have merged here and more are in-flight. The patches for
Manila can be found &lt;a href=&#34;https://review.opendev.org/q/project:openstack/manila+file:schemas&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;ironic&#34;&gt;Ironic&lt;/h3&gt;
&lt;p&gt;Ironic hasn&amp;rsquo;t historically used JSON Schema for validation, instead using its own homegrown validation framework and
taking advantage of some Pecan functionality to maintain API versioning. As a result, there&amp;rsquo;s quite a bit of work needed
to get schemas into Ironic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Move API versioning to decorators&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rework request path, query string and body parameter validation to use JSON Schema schemas (via decorators) instead of
the homegrown framework&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add request body parameter validation&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This work is in very early stages, but there are people working on it and there appears to be broad buy-in from the
Ironic team, so I hope to see significant progress over the course of the 2025.2 (Flamingo) cycle. The patches for
Ironic can be found &lt;a href=&#34;https://review.opendev.org/q/project:openstack/ironic+topic:openapi&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;other-services-neutron-swift-glance-octavia-&#34;&gt;Other services (Neutron, Swift, Glance, Octavia, &amp;hellip;)&lt;/h3&gt;
&lt;p&gt;To the best of my knowledge, no work has been started in other projects. Of the &amp;ldquo;core&amp;rdquo; projects, I expect the Glance
effort to be relatively small since they already have formal schemas (exposed via the API!) for most of their resources.
Conversely, I expect the Neutron effort to be both large and complicated, given the number and highly dynamic nature of
Neutron&amp;rsquo;s API, driven by it&amp;rsquo;s extension-based &amp;ldquo;versioning&amp;rdquo; system. I have somehow never worked on Swift and haven&amp;rsquo;t a
clue about that.&lt;/p&gt;
&lt;h3 id=&#34;tooling-1&#34;&gt;Tooling&lt;/h3&gt;
&lt;p&gt;There are two tooling-related efforts ongoing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Development of the &lt;a href=&#34;https://opendev.org/openstack/codegenerator&#34;&gt;codegenerator&lt;/a&gt; project.&lt;/li&gt;
&lt;li&gt;Improvements to the openstacksdk project, python-openstackclient project, and related projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The codegenerator project provides a collection of utilities for generating OpenAPI schemas and a (Rust-based 🦀) client
from these schemas. Development on this tool first started in earnest during the 2024.1 (Caracal) cycle, but the tool has
continued to evolve over the course of the 2024.2 (Dalmatian) and 2025.1 (Epoxy) cycles. I expect to see more progress
as schemas continue to get added to the Nova project. If you&amp;rsquo;re interested in learning more about this work, I&amp;rsquo;d
encourage to review the following material from my upstream colleague, Artem Goncharov (gtema), who is driving much of
it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://gtema.github.io/slides/openstack_openapi/openapi_reveal.html&#34;&gt;OpenStack OpenAPI specs: Building up OpenAPI specs for OpenStack APIs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gtema.github.io/slides/rust_cli/rust_cli_reveal.html&#34;&gt;OpenStack CLI rewritten in Rust&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The openstacksdk and python-openstackclient projects, meanwhile, are far more established. As a quick reminder, the
openstacksdk project provides the primary OpenStack client library, while the python-openstackclient project is the
primary OpenStack CLI. In recent releases, we&amp;rsquo;ve been undertaking work to prepare them for a future when they can both
be at least partially auto-generated. This has taken the form of the addition of typing and a more general &amp;ldquo;removal of
weirdness&amp;rdquo; goal.&lt;/p&gt;
&lt;p&gt;The addition of typing is probably easier to grok and easier to measure. To achieve this, we have been adding type hints
to openstacksdk and python-openstackclient, as well as dependencies of same. As of the 2025.1 (Epoxy) release, we have
full type coverage for keystoneauth (a dependency of openstacksdk) and for both cliff and osc-lib (dependencies of
python-openstackclient). We also have initial coverage of both openstacksdk and python-openstackclient themselves, with
more comprehensive coverage of some of the non-core aspects of the former. Completely typing openstacksdk in particular
though is more challenging due to the aforementioned weirdness, but we will continue to make progress on this over the
2025.2 (Flamingo) cycle.&lt;/p&gt;
&lt;p&gt;The &amp;ldquo;removal of weirdness&amp;rdquo; goal is, as we noted, a little more general and cover a few related issues we&amp;rsquo;re facing. The
two biggest of these, however, is (a) the over-use of variadic arguments and keyword arguments (&lt;code&gt;*args&lt;/code&gt; and &lt;code&gt;**kwargs&lt;/code&gt;)
in the proxy and cloud layers in particular, and (b) the munging of request and response body parameters in the
&lt;code&gt;Resource&lt;/code&gt; class used throughout openstacksdk. The former is hopefully self-explanatory so let&amp;rsquo;s focus on the latter. By
way of a demonstration of the issue, consider the compute service&amp;rsquo;s &lt;code&gt;/servers&lt;/code&gt; API. This API expects you to pass
&lt;code&gt;networks&lt;/code&gt; and &lt;code&gt;block_device_mapping_v2&lt;/code&gt; fields in the request for &lt;code&gt;POST /servers&lt;/code&gt;, to configure networking and block
devices respectively. However, it returns this information - in a different form, no less - via the &lt;code&gt;addresses&lt;/code&gt; and
&lt;code&gt;os-extended-volumes:volumes_attached&lt;/code&gt; in response to &lt;code&gt;GET /servers/{serverID}&lt;/code&gt; and &lt;code&gt;GET /servers/detail&lt;/code&gt;. Because we
currently munge the request and response body fields, our &lt;code&gt;Server&lt;/code&gt; class therefore looks like this (in highly minimized
form):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Server&lt;/span&gt;(resource&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Resource):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    addresses &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; resource&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Body(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;addresses&amp;#39;&lt;/span&gt;, type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;dict)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    attached_volumes &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; resource&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Body(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;os-extended-volumes:volumes_attached&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        aka&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;volumes&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;list,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        list_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;volume_attachment&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;VolumeAttachment,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        default&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;[],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    block_device_mapping &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; resource&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Body(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;block_device_mapping_v2&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    networks &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; resource&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Body(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;networks&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But if you attempt to set either &lt;code&gt;addresses&lt;/code&gt; or &lt;code&gt;attached_volumes&lt;/code&gt; before a &lt;code&gt;Server.create&lt;/code&gt; call, you will get an error.
On the other hand, if you do a &lt;code&gt;Server.fetch&lt;/code&gt; or &lt;code&gt;Server.list&lt;/code&gt; call, the &lt;code&gt;block_device_mapping&lt;/code&gt; and &lt;code&gt;networks&lt;/code&gt;
attributes will always be set to &lt;code&gt;None&lt;/code&gt; since they don&amp;rsquo;t form part of the response body. This has necessitated a whole
load of special casing in python-openstackclient, and special casing is bad for things you wish to auto-generate. By
separating these, we make it easier to type and easier to auto-generate. While a number of PoCs have been produced, none
have been implemented yet. We expect work on this to continue during the 2025.2 (Flamingo) cycle.&lt;/p&gt;
&lt;h2 id=&#34;questions&#34;&gt;Questions?&lt;/h2&gt;
&lt;p&gt;Come discuss these topics in the OpenStack Virtual PTG, running from 07-11 April 2025. More information of the event and
sessions can be found at &lt;a href=&#34;https://ptg.opendev.org/&#34;&gt;ptg.opendev.org&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>API Contracts: Bringing OpenAPI and Typing to OpenStack</title>
      <link>https://that.guru/talks/api-contracts-bringing-openapi-and-typing-to-openstack/</link>
      <pubDate>Wed, 11 Sep 2024 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/talks/api-contracts-bringing-openapi-and-typing-to-openstack/</guid>
      <description>&lt;p&gt;This talk was delivered during the &lt;a href=&#34;https://2024.openinfraasia.org/&#34;&gt;OpenInfra Summit Asia in Suwon&lt;/a&gt; in September 2024. It focused on two efforts
currently underway in the OpenStack community, one to add OpenAPI schema generation to many services, and another to add
type annotations to the SDK and OpenStackClient.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;OpenStack&amp;rsquo;s APIs - of both RESTful and Python variety - have evolved organically over time. This has allowed them to
grow and change as new use cases have arisen (and older ones died away), but this organic growth has resulted in a
large amount of cruft, weird corner cases and bugs, and generally lots of undefined behaviour, all things commonly
known as tech debt. While a lot has been done to reduce this tech debt - ranging from low-hanging fruit like improved
docstrings and better unit test coverage to bigger efforts like the api-ref docs and functional API tests - we know
from experience that there are a non-trivial number of latent issues just waiting to be triggered. Fortunately, the
broader tech ecosystem has not stood still since OpenStack was first introduced in the early 2010s. Two technologies
in particular promise to massively improve how we document and understand our APIs: OpenAPI and Python type
annotations. OpenAPI promises to provide a machine-readable definition of the various APIs, while Python type
annotations allow us a way to provide guarantees about type information that were not previously possible in Python.
In this talk, we will explore the work that has been ongoing to integrate both technologies into projects across
OpenStack, how you as a user or developer can taking advantage of them, and how you can get involved.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;More information is available on the &lt;a href=&#34;https://2024.openinfraasia.org/&#34;&gt;OpenInfra Summit Asia 2024&lt;/a&gt; website.&lt;/p&gt;

&lt;script async class=&#34;speakerdeck-embed&#34; data-id=&#34;06a0288d97cf415a944d3d1fd36ab907&#34; data-ratio=&#34;1.77777777777778&#34; src=&#34;//speakerdeck.com/assets/embed.js&#34;&gt;&lt;/script&gt;


</description>
    </item>
    
    <item>
      <title>Block Storage in OpenStack</title>
      <link>https://that.guru/blog/block-devices-in-openstack/</link>
      <pubDate>Thu, 22 Aug 2024 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/block-devices-in-openstack/</guid>
      <description>&lt;p&gt;It&amp;rsquo;s an often overlooked fact that OpenStack has two wholly different mechanisms for provisioning block devices for
instances. While most people are aware of the Block Storage service, Cinder, not everyone is aware of or gives much
thought to the various types of block devices or &lt;em&gt;&amp;ldquo;ephemeral&amp;rdquo;&lt;/em&gt; storage that the Compute service, Nova, is able to
provide. This article serves to provide a high-level overview and comparison of these two different mechanisms,
including examples of how you can use them and some hopefully (interesting) asides.&lt;/p&gt;

&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;This article focuses on exclusively on block devices, ignoring the other types of storage available in OpenStack such as
objects (provided by Swift) or shareable filesystems (provided by Manila). Covering those will have to be left for
another day.&lt;/div&gt;
&lt;/aside&gt;

&lt;h2 id=&#34;types-of-block-storage&#34;&gt;Types of block storage&lt;/h2&gt;
&lt;p&gt;Broadly speaking, OpenStack has two types of block storage: storage provisioned by Nova, and storage provisioned by
Cinder. Somewhat confusingly, these are often referred to as &lt;em&gt;ephemeral&lt;/em&gt; storage and &lt;em&gt;persistent&lt;/em&gt; storage, respectively.
The origin for these names is likely based on the fact that Nova-provisioned storage is associated with an individual
instance and has a lifecycle that is tied to the lifecycle instance itself, meaning if you delete the instance then any
Nova-provisioned storage associated with that instance is also deleted. By comparison, Cinder-provisioned storage can
&amp;ldquo;persist&amp;rdquo; after an instance is deleted and may be re-attached to other instances (or in some cases even attached to
multiple instances at the same time).&lt;/p&gt;
&lt;p&gt;When and where you can use either type of storage depends on the type of disk you want to create, something we&amp;rsquo;ll get
to in a moment. However, to call these storage types ephemeral and persistent invites confusion on multiple fronts.
Firstly, there is the fact that Nova already has its own separate concept of &amp;ldquo;ephemeral disks&amp;rdquo;, which we cover below.
More pressingly, calling Nova-provisioned storage ephemeral suggests it is somehow unsafe or unreliable. In reality,
both Nova and Cinder provide a level of configurability about where or how the underlying data for the block devices are
stored. Cinder achieves this by being pluggable and supporting a wide variety of drivers, which can be found
&lt;a href=&#34;https://docs.openstack.org/cinder/latest/reference/support-matrix.html#driver-support-matrix&#34;&gt;here&lt;/a&gt;. Cinder supports backends like LVM and Ceph, as well as a large variety of other proprietary and
open source backends. For Nova, this is determined by the virt driver in use, the value of the &lt;code&gt;[compute] use_cow_images&lt;/code&gt; configuration option, and optionally one or more virt driver-specific configuration options. If using
the libvirt driver then the following options are all relevant:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[compute] use_cow_image&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[compute] force_raw_images&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[libvirt] images_types&lt;/code&gt; (and mechanism-specific options),&lt;/li&gt;
&lt;li&gt;and &lt;code&gt;[DEFAULT] instances_path&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In a default DevStack deployment, block devices will be stored as &lt;code&gt;qcow2&lt;/code&gt; image files in the path indicated by
&lt;code&gt;[DEFAULT] instances_path&lt;/code&gt;, &lt;code&gt;/opt/stack/data/nova/instances&lt;/code&gt;, on the compute host that instance is located on.
When using this default configuration, a migrated instance will need its block storage files migrated too and if the
host dies then you will lose any of these Nova-provisioned block devices with it. However, this is only one potential
configuration: you can also choose to store the images in Ceph (&lt;code&gt;[libvirt] images_types = rdb&lt;/code&gt;, with &lt;code&gt;[libvirt] images_rbd_pool&lt;/code&gt; and &lt;code&gt;[libvirt] images_rbd_ceph_conf&lt;/code&gt; set to relevant options). Alternatively, you can choose to use use
any of the other local storage mechanisms with a suitable replication or backup strategy, whether that&amp;rsquo;s LVM (&lt;code&gt;[libvirt] images_types = lvm&lt;/code&gt; and &lt;code&gt;[libvirt] images_volume_group&lt;/code&gt; set to a relevant volume group (VG)) and backups, or one of the
file-based mechanisms with the directory indicated by &lt;code&gt;[DEFAULT] instances_path&lt;/code&gt; placed on a network-attached
filesystem. Suffice to say that, with correct configuration, your data should never be at risk regardless of where it&amp;rsquo;s
placed.&lt;/p&gt;
&lt;h2 id=&#34;types-of-disk&#34;&gt;Types of disk&lt;/h2&gt;
&lt;p&gt;Now that we&amp;rsquo;re aware of &lt;em&gt;how&lt;/em&gt; the block storage is actually stored, let&amp;rsquo;s look at how these block devices are exposed
and used in OpenStack. OpenStack typically refers to block devices as either disks or volumes. I don&amp;rsquo;t have a good
explanation for when you&amp;rsquo;d use one or the other, and my own mental shortcut is to call any block device attached to an
instance a disk, unless that block device is a non-root device provisioned by Cinder in which case it&amp;rsquo;s a volume. With
that clarified (🙃), let&amp;rsquo;s take a look at the first disk type, root disks.&lt;/p&gt;
&lt;h3 id=&#34;root-disks&#34;&gt;Root disks&lt;/h3&gt;
&lt;p&gt;This is the one most people will be familiar with and it&amp;rsquo;s the only disk that&amp;rsquo;s absolutely required. As the name
suggests, the root disk is where &lt;code&gt;/&lt;/code&gt; is mounted. By default, the root disk will be provisioned by Nova and its size will
be configured in GB using the &lt;code&gt;disk&lt;/code&gt; property of the flavor used to create the instance. For example, by looking at the
&lt;code&gt;m1.small&lt;/code&gt; flavor on a local DevStack deployment I can see &lt;code&gt;disk&lt;/code&gt; set to &lt;code&gt;20&lt;/code&gt; or 20GB:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack flavor show m1.small -f value -c disk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we create a instance using this flavor (and no other block device-related configuration, obviously), we will get a
root disk that is 20GB in size.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.small --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can confirm this by SSH&amp;rsquo;ing into the machine:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server add floating ip test-server &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;FIP&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server ssh test-server -- -l cirros
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ lsblk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vda     252:0    &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  20G  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; disk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-vda1  252:1    &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  20G  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; part /
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;-vda15 252:15   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;   8M  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; part
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can also opt to use a Cinder volume for the root disk (which some people will now call a &amp;ldquo;root volume&amp;rdquo; - see previous
&amp;ldquo;clarification&amp;rdquo; 😅). If you&amp;rsquo;re using OpenStackClient (OSC), this can be accomplished using the &lt;code&gt;--boot-from-volume&lt;/code&gt;
option:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.small --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --boot-from-volume &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When you do this, Nova will create the volume for you by proxying the request through to Cinder. You can confirm this
using the &lt;code&gt;openstack volume list&lt;/code&gt; command:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;❯ openstack volume list
+--------------------------------------+------+--------+------+--------------------------------------+
| ID                                   | Name | Status | Size | Attached to                          |
+--------------------------------------+------+--------+------+--------------------------------------+
| 68584677-0d53-4c52-8d1c-5600c96768a1 |      | in-use |    5 | Attached to test-server on /dev/vda  |
+--------------------------------------+------+--------+------+--------------------------------------+
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And, like above, you can confirm the disk size in the guest:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ lsblk
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
vda     252:0    0   5G  0 disk
|-vda1  252:1    0   5G  0 part /
`-vda15 252:15   0   8M  0 part
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finally, you can choose to use an existing volume as the root disk. To do this, use the &lt;code&gt;--volume&lt;/code&gt; option:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.small --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --volume test-volume &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This volume must be bootable, and you would likely use this to re-create a deleted instance using its root volume.&lt;/p&gt;

&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;&lt;p&gt;It&amp;rsquo;s probably useful to note that, by default, volumes attached to an instance are not automatically removed when the
instance is deleted. This is either or a pro or a con, depending on how you look at it. On the positive side, this
allows you to re-attach the disk to a new instance (more on this later). On the negative side, this means you can end up
with a whole load of stale volumes sitting around, taking up space on your Ceph cluster (or whatever backend Cinder is
using). To work around this, you can modify the &lt;code&gt;delete_on_termination&lt;/code&gt; attribute of the volume attachment:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server volume list test-server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+----------+--------------------------------------+--------------------------------------+------+------------------------+--------------------------------------+--------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| Device   | Server ID                            | Volume ID                            | Tag  | Delete On Termination? | Attachment ID                        | BlockDeviceMapping UUID              |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+----------+--------------------------------------+--------------------------------------+------+------------------------+--------------------------------------+--------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| /dev/vda | 339acd3a-41e3-45b9-8dbf-1d7dcc1bd8bc | 1bd2c131-7961-4eeb-84ff-4990917bb9b8 | None | False                  | 819c7472-b14f-4867-b894-b68758c6d398 | c69ba987-e66a-4381-8c8a-ceff5f652f0e |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+----------+--------------------------------------+--------------------------------------+------+------------------------+--------------------------------------+--------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server volume set --delete-on-termination 339acd3a-41e3-45b9-8dbf-1d7dcc1bd8bc 1bd2c131-7961-4eeb-84ff-4990917bb9b8
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alternatively, you can set this property when creating the instance. Unfortunately doing this requires using the
&lt;code&gt;--block-device&lt;/code&gt; option to specify the BDM rather than the &lt;code&gt;--boot-from-volume&lt;/code&gt; alias. The equivalent of the
previous command using &lt;code&gt;--boot-from-volume&lt;/code&gt; would be:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ image_id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;openstack image show cirros-0.6.2-x86_64-disk -f value -c id&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.small --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --block-device uuid&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;image_id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;,source_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;image,destination_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;volume,delete_on_termination&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;true,boot_index&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;0,volume_size&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/aside&gt;

&lt;h3 id=&#34;ephemeral-disks&#34;&gt;Ephemeral disks&lt;/h3&gt;
&lt;p&gt;Ephemeral disks are so called because they are associated with a single instance and only exist for the lifetime of that
instance. Therefore, as you may guess, these disks can only be provided by Nova. Like root disks, the size of the
ephemeral disk is configured in GB via a flavor property, &lt;code&gt;OS-FLV-EXT-DATA:ephemeral&lt;/code&gt;. None of the flavors provided in a
default DevStack install provide for ephemeral storage, so to demonstrate this we need to create our own flavor which
we&amp;rsquo;re going to call &lt;code&gt;m1.ephemeral&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack flavor create --id &lt;span style=&#34;color:#ae81ff&#34;&gt;99&lt;/span&gt; --vcpus &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; --ram &lt;span style=&#34;color:#ae81ff&#34;&gt;512&lt;/span&gt; --disk &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; --ephemeral &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt; m1.ephemeral
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once created, we can look at the flavor and ensure that the &lt;code&gt;OS-FLV-EXT-DATA:ephemeral&lt;/code&gt; property has been set to the
relevant size (in this case, &lt;code&gt;10&lt;/code&gt; or 10GB):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack flavor show m1.ephemeral -f value -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;OS-FLV-EXT-DATA:ephemeral&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we create a instance using this flavor, we will get a root disk that is 20GB in size &lt;strong&gt;and&lt;/strong&gt; a new, additional disk
that is 10GB in size:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.ephemeral --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once again, we can confirm this by SSH&amp;rsquo;ing into the machine:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ lsblk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vda     252:0    &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;   5G  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; disk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-vda1  252:1    &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;   5G  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; part /
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;-vda15 252:15   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;   8M  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; part
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vdb     252:16   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  10G  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; disk /mnt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You&amp;rsquo;ll note that the disk is already mounted for us. This isn&amp;rsquo;t actually an OpenStack doing this for us. Rather, it&amp;rsquo;s
part of &lt;code&gt;cloud-init&lt;/code&gt;, which is included in the Cirros images. If you were using an image that didn&amp;rsquo;t include
&lt;code&gt;cloud-init&lt;/code&gt; or were to attach multiple ephemeral disks, you&amp;rsquo;d need to handle this mounting yourself.&lt;/p&gt;
&lt;p&gt;You may also note that there&amp;rsquo;s an &lt;code&gt;--ephemeral&lt;/code&gt; option available for the &lt;code&gt;openstack server create&lt;/code&gt; command. This option
allows you to change both the layout of the ephemeral storage and the filesystem used on them. For example, say that
instead of having a single 10GB disk, I wanted to have an 8GB disk formatted as ext4 and a 2GB disk formatted as XFS, I
could invoke OSC like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.ephemeral --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --ephemeral size&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;8,format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ext4 --ephemeral size&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;2,format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;xfs &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can see that these are available in the machine using &lt;code&gt;lsblk&lt;/code&gt; again and confirm their filesystem types using &lt;code&gt;blkid&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ lsblk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vda     252:0    &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  20G  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; disk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-vda1  252:1    &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  20G  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; part /
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;-vda15 252:15   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;   8M  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; part
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vdb     252:16   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;   8G  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; disk /mnt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vdc     252:32   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;   2G  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; disk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ blkid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/dev/vdb: LABEL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ephemeral0&amp;#34;&lt;/span&gt; UUID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;a34015c1-be25-4757-8d17-cc82285b12b2&amp;#34;&lt;/span&gt; BLOCK_SIZE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;4096&amp;#34;&lt;/span&gt; TYPE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ext4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/dev/vdc: LABEL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ephemeral1&amp;#34;&lt;/span&gt; UUID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0cf5d85b-0357-44fc-9549-6f71720af8ba&amp;#34;&lt;/span&gt; BLOCK_SIZE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;512&amp;#34;&lt;/span&gt; TYPE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;xfs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/dev/vda15: SEC_TYPE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;msdos&amp;#34;&lt;/span&gt; UUID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;AE31-5342&amp;#34;&lt;/span&gt; BLOCK_SIZE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;512&amp;#34;&lt;/span&gt; TYPE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;vfat&amp;#34;&lt;/span&gt; PARTUUID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;05ecb6a9-6cb3-4697-b819-25c6cee5bd9a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/dev/vda1: LABEL&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cirros-rootfs&amp;#34;&lt;/span&gt; UUID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;f1511162-06fb-4482-9dab-9a0c76633fb2&amp;#34;&lt;/span&gt; BLOCK_SIZE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;4096&amp;#34;&lt;/span&gt; TYPE&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ext3&amp;#34;&lt;/span&gt; PARTUUID&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;df2f017d-edcc-4371-81c7-fcfa0c5c1b09&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When configuring ephemeral disks this way, the total size of all disks does not have to add up to the size indicted by
the flavor&amp;rsquo;s &lt;code&gt;OS-FLV-EXT-DATA:ephemeral&lt;/code&gt; property (meaning you could choose only to configure e.g. the 2GB volume above)
but it cannot exceed the size indicated in the flavor. For example, if I repeated the above command but using single
20GB disk (i.e. 10GB larger than the 10GB value specified for the &lt;code&gt;m1.ephemeral&lt;/code&gt; flavor we created previously), the
request will fail:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.ephemeral --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --ephemeral size&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BadRequestException: 400: Client Error &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; url: http://10.0.108.50/compute/v2.1/servers, Ephemeral disks requested are
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;larger than the instance type allows. If no size is given in one block device mapping, flavor ephemeral size will be
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;used.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, as we noted at the top, ephemeral disks can only be provisioned by Nova. If you attempt to create an ephemeral
disk using &lt;code&gt;destination_type=remote&lt;/code&gt;, what you have is no longer an ephemeral disk (in the Nova sense of the term)
but rather a volume. Which is a nice segue to&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;volumes&#34;&gt;Volumes&lt;/h3&gt;
&lt;p&gt;Volumes are not a disk type but rather the name given to the primary resource type provided by Cinder. As noted
previously, a Cinder volume can be used as the backing device for the root disk, but it can also be used to provide
additional disks to the instance (but not ephemeral disks - an ephemeral disk ceases to be an ephemeral disk once it&amp;rsquo;s
no longer provisioned by Nova). For example, say we wanted to use a standard Nova-provisioned block device for our
root disk but attach two additional volumes provisioned by Cinder, we could run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ vol_a_id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;openstack volume create --size &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; test-volume-a -f value -c id&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ vol_b_id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;openstack volume create --size &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; test-volume-b -f value -c id&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.small --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --block-device uuid&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;vol_a_id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;,source_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;volume &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --block-device uuid&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;vol_b_id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;,source_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;volume &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can examine these in the guest:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ lsblk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vda     252:0    &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  20G  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; disk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-vda1  252:1    &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;  20G  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; part /
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;-vda15 252:15   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;   8M  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; part
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vdb     252:16   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;   5G  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; disk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vdc     252:32   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;   5G  &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; disk
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Instead of pre-creating the volume with Cinder, we could also let Nova do this for us. This avoids an extra call to
Cinder (at least from us - Nova simply makes the call on our behalf), at the expense of some fine grained configuration
for the volume. We could modify the above command like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.small --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --block-device source_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;blank,destination_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;volume,volume_size&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --block-device source_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;blank,destination_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;volume,volume_size&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unlike the block devices provisioned by Nova, it&amp;rsquo;s also possible to attach additional block devices to an existing
instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack volume create --size &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; test-volume-c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server add volume test-server test-volume-c
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Likewise, you can remove devices as long as they&amp;rsquo;re not used for the root disk:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server remove volume test-server test-volume-c
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, Cinder volumes can be attached to multiple instances at the same time. As discussed in the &lt;a href=&#34;https://docs.openstack.org/cinder/latest/admin/volume-multiattach.html&#34;&gt;Cinder
documentation&lt;/a&gt;, this requires the use of a clustered or multi-attach creation of a special &lt;em&gt;volume type&lt;/em&gt;
with the &lt;code&gt;multiattach&lt;/code&gt; property set to &lt;code&gt;&amp;lt;is&amp;gt; True&lt;/code&gt;. Fortunately, the reference LVM driver configured by default in a
DevStack deployment supports this, so we can demo creating the volume type, volume, and instances:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack volume type create --multiattach multiattach
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ vol_id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;openstack volume create --size &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; --type multiattach test-volume -f value -c id&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.small --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --block-device uuid&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;vol_id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;,source_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;volume &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server-a
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.small --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --block-device uuid&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;vol_id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;,source_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;volume &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server-b
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we log in to these two instances and mount the volume (after partitioning and formatting it), we&amp;rsquo;ll be able to create
a file in one and see it appear in the other:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;❯ openstack server ssh test-server-a -- -l cirros

# create partitions using fdisk since parted is not available in cirros images
$ sudo fdisk /dev/vdb
$ sudo mkfs.ext4 /dev/vdb1

$ lsblk
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
vda     252:0    0  20G  0 disk
|-vda1  252:1    0  20G  0 part /
`-vda15 252:15   0   8M  0 part
vdb     252:16   0   5G  0 disk
`-vdb1  252:17   0   5G  0 part
$ mkdir test
$ sudo mount /dev/vdb1 test
$ sudo touch test/foo
$ exit

❯ openstack server ssh test-server-b -- -l cirros

$ mkdir test
$ sudo mount /dev/vdb1 test  # you may need to reboot to pick up the changes to this disk for this to work
$ ls test
$ ls disk/
foo
&lt;/code&gt;&lt;/pre&gt;
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;&lt;p&gt;If &lt;code&gt;parted&lt;/code&gt; was available in the Cirros image used, we could avoid the interactive use of &lt;code&gt;fdisk&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo parted /dev/vdb mklabel gpt
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo parted /dev/vdb mkpart primary ext4 0% 100%
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo parted /dev/vdc print
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/aside&gt;

&lt;h3 id=&#34;swap-disks&#34;&gt;Swap disks&lt;/h3&gt;
&lt;p&gt;The final type of disk is the swap disk. Swap disks are very like ephemeral disks, in that they&amp;rsquo;re exclusively managed
by Nova and configured via a flavor property called &lt;code&gt;swap&lt;/code&gt;. Unlike the &lt;code&gt;disk&lt;/code&gt; and &lt;code&gt;OS-FLV-EXT-DATA:ephemeral&lt;/code&gt; properties
though, the &lt;code&gt;swap&lt;/code&gt; property is a size in MB, not GB. Once again, the default DevStack configuration does not include
flavors with swap enabled so we need to configure these ourselves. Lets do that, creating a flavor called &lt;code&gt;m1.swap&lt;/code&gt; with
2048 MB of swap:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack flavor create --id &lt;span style=&#34;color:#ae81ff&#34;&gt;98&lt;/span&gt; --vcpus &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; --ram &lt;span style=&#34;color:#ae81ff&#34;&gt;512&lt;/span&gt; --disk &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt; --swap &lt;span style=&#34;color:#ae81ff&#34;&gt;2048&lt;/span&gt; m1.swap
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once created, we can look at the flavor and ensure that the &lt;code&gt;swap&lt;/code&gt; property has been set to the relevant size (in this
case, &lt;code&gt;1024&lt;/code&gt; or 1024MB):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack flavor show m1.swap -f value -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;swap&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1024&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we create a instance using this flavor, we will get a root disk that is 20GB in size &lt;strong&gt;and&lt;/strong&gt; a additional disk
that is 1024MB in size and formatted as a swap disk:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.swap --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Inspecting the guest itself, we see the disk present and that it has an fstype of &lt;code&gt;swap&lt;/code&gt;, as expected:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo lsblk -f
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME    FSTYPE FSVER LABEL         UUID                                 FSAVAIL FSUSE% MOUNTPOINTS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vda
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-vda1  ext3         cirros-rootfs f1511162-06fb-4482-9dab-9a0c76633fb2   18.4G     0% /
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;-vda15 vfat                       AE31-5342
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vdb     swap                       6f7adada-a19f-47e1-915c-20570535a619
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat /proc/meminfo | grep -i swap
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SwapCached:            &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SwapTotal:             &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SwapFree:              &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, unlike ephemeral disks, &lt;code&gt;cloud-init&lt;/code&gt; does not mount this additional disk for us. If you want that, you&amp;rsquo;ll need
to do so manually:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo swapon /dev/vdb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo lsblk -f
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME    FSTYPE FSVER LABEL         UUID                                 FSAVAIL FSUSE% MOUNTPOINTS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vda
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|-vda1  ext3         cirros-rootfs f1511162-06fb-4482-9dab-9a0c76633fb2   18.4G     0% /
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;-vda15 vfat                       AE31-5342
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vdb     swap                       6f7adada-a19f-47e1-915c-20570535a619
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat /proc/meminfo | grep -i swap
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SwapCached:            &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SwapTotal:       &lt;span style=&#34;color:#ae81ff&#34;&gt;1048572&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SwapFree:        &lt;span style=&#34;color:#ae81ff&#34;&gt;1048572&lt;/span&gt; kB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Like ephemeral disk, there&amp;rsquo;s also a &lt;code&gt;--swap&lt;/code&gt; option for the &lt;code&gt;openstack server create&lt;/code&gt; command that you can use to
override the default swap size. Once again you cannot exceed the total size given in the flavor, but you also can&amp;rsquo;t
specify the option multiple times to divide the swap into different disks. For example, if we wanted to configure a
smaller swap disk size of, say, 512MB, we could do:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.swap --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --swap &lt;span style=&#34;color:#ae81ff&#34;&gt;512&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Attempting to use something larger than the size indicated in the &lt;code&gt;swap&lt;/code&gt; property of the flavor will result in an error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.swap --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --swap &lt;span style=&#34;color:#ae81ff&#34;&gt;2048&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BadRequestException: 400: Client Error &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; url: http://10.0.108.50/compute/v2.1/servers, Swap drive requested is larger
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;than instance type allows.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;block-device-mappings-bdms&#34;&gt;Block Device Mappings (BDMs)&lt;/h2&gt;
&lt;p&gt;Finally, we get to the final piece of the block storage puzzle: Block Device Mappings, or BDMs. BDMs are how Nova
describes mapping of block devices to instances. BDMs are specified during instance creation using the
&lt;code&gt;block_device_mapping_v2&lt;/code&gt; field and are objects with a number of well known fields.&lt;/p&gt;

&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;The term &amp;ldquo;BDM&amp;rdquo; can also be used to refer to the (Python) objects used internally in Nova to manage mappings. If you&amp;rsquo;re
interested in a deeper dive into this particular topic, my colleague Lee Yarwood wrote a good overview a few years ago
which you can find &lt;a href=&#34;https://blog.yarwood.me.uk/2021/01/20/openstack_nova_bdm/&#34;&gt;here&lt;/a&gt;.&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;Both the &lt;a href=&#34;https://docs.openstack.org/nova/latest/user/block-device-mapping.html&#34;&gt;Nova user docs&lt;/a&gt; and the &lt;a href=&#34;https://docs.openstack.org/api-ref/compute/?expanded=create-server-detail#create-server&#34;&gt;Nova API Reference docs&lt;/a&gt; provide a good overview of these
fields, but there are a few in particular worth discussing here in light of the above.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;destination_type&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This field, which has been referenced earlier in this article, determines what service manages the block devices and
therefore where the block device resides. This value can either be &lt;code&gt;local&lt;/code&gt; (meaning managed by Nova) or &lt;code&gt;remote&lt;/code&gt;
(managed by Cinder).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;source_type&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This indicates the source of the block devices. This value can one of &lt;code&gt;blank&lt;/code&gt;, &lt;code&gt;image&lt;/code&gt;, &lt;code&gt;snapshot&lt;/code&gt;, or &lt;code&gt;volume&lt;/code&gt;, and
the docs describe all of these in detail. We&amp;rsquo;ll explore some different use cases for these shortly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;boot_index&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This is an integer value that indicates the order that the VM will use when attempting to boot from disks. When
attaching a volume as a root disk (i.e. boot from volume), you will use a &lt;code&gt;boot_index&lt;/code&gt; of &lt;code&gt;0&lt;/code&gt; to indicate that the
guest OS should boot from that volume from.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that knowledge in hand, we can look at a few of the examples previously from the perspective of the BDMs used
during instance creation. We&amp;rsquo;ll do this using the &lt;code&gt;openstack server create&lt;/code&gt; command with the &lt;code&gt;--debug&lt;/code&gt; flag, which
allows us to see the raw requests and responses issued to the server.&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s look a root disks. If we create a &amp;ldquo;standard&amp;rdquo; instance using a local root disk, then the
&lt;code&gt;block_device_mapping_v2&lt;/code&gt; field can be (and, if using OSC, will be) empty:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.small --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --debug &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;flavorRef&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;imageRef&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9acb21b3-0516-459a-9b0a-6357e66ff74a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is because Nova automatically creates the BDM for us, making it unnecessary to specify. If we want to use boot from
volume instead, placing our root disk on a volume, we will need to specify a BDM:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.small --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --boot-from-volume &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; --debug &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;flavorRef&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;block_device_mapping_v2&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;uuid&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9acb21b3-0516-459a-9b0a-6357e66ff74a&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;boot_index&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;source_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;destination_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;volume&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;volume_size&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;imageRef&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(&lt;code&gt;9acb21b3-0516-459a-9b0a-6357e66ff74a&lt;/code&gt; is the ID of the &lt;code&gt;cirros-0.6.2-x86_64-disk&lt;/code&gt; image we created the server with,
and it&amp;rsquo;s passed via the &lt;code&gt;uuid&lt;/code&gt; field of the BDM rather than via the &lt;code&gt;imageRef&lt;/code&gt; field)&lt;/p&gt;
&lt;p&gt;Next, let&amp;rsquo;s look at ephemeral disks. As with root disks, you can simply use a relevant flavor and omit the
&lt;code&gt;block_device_mapping_v2&lt;/code&gt; field and Nova will automatically do the right thing. If you wanted to divide the ephemeral
disk into multiple devices though, you&amp;rsquo;d use a different variation of this field. For example, our prior example of an
8GB ext4 ephemeral disk and a 2GB XFS disk would look like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.ephemeral --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --ephemeral size&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;8,format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ext4 --ephemeral size&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;2,format&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;xfs &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;flavorRef&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;99&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;block_device_mapping_v2&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;uuid&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9acb21b3-0516-459a-9b0a-6357e66ff74a&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;boot_index&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;source_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;destination_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;local&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;delete_on_termination&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;boot_index&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;-1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;source_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;blank&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;destination_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;local&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;delete_on_termination&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;volume_size&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;8&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;guest_format&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ext4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;boot_index&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;-1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;source_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;blank&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;destination_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;local&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;delete_on_termination&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;volume_size&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;guest_format&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;xfs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;imageRef&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9acb21b3-0516-459a-9b0a-6357e66ff74a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yes, things are starting to get lengthy&amp;hellip;&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll skip over volumes for a moment and move onto swap volumes. Yet again, if you don&amp;rsquo;t want to do anything bar use the
swap configured in the flavor then you can omit the &lt;code&gt;block_device_mapping_v2&lt;/code&gt; field, but you&amp;rsquo;ll need to specify it if
you wish to use a different size:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.swap --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --swap &lt;span style=&#34;color:#ae81ff&#34;&gt;512&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;flavorRef&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;98&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;block_device_mapping_v2&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;uuid&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9acb21b3-0516-459a-9b0a-6357e66ff74a&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;boot_index&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;source_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;destination_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;local&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;delete_on_termination&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;boot_index&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;-1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;source_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;blank&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;destination_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;local&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;guest_format&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;swap&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;volume_size&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;512&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;delete_on_termination&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;imageRef&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9acb21b3-0516-459a-9b0a-6357e66ff74a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And finally there are volumes. As discussed above, there are huge variety of combinations available here and we&amp;rsquo;re only
going to look at a few of those we previously discussed. Firstly, let&amp;rsquo;s look at our example of using two precreated
volumes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ vol_a_id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;openstack volume create --size &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; test-volume-a -f value -c id&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ vol_b_id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;openstack volume create --size &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; test-volume-b -f value -c id&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.small --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --block-device uuid&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;vol_a_id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;,source_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;volume &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --block-device uuid&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;vol_b_id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;,source_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;volume &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;flavorRef&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;block_device_mapping_v2&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;uuid&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9acb21b3-0516-459a-9b0a-6357e66ff74a&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;boot_index&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;source_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;destination_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;local&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;delete_on_termination&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;uuid&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;668d9851-b878-4fe5-a244-67585c963a09&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;source_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;volume&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;destination_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;volume&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;uuid&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ed7c9976-9fe6-4ada-93cb-4e60bc2a0a05&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;source_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;volume&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;destination_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;volume&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;imageRef&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9acb21b3-0516-459a-9b0a-6357e66ff74a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now compare this to our example of letting Nova create the volumes for us:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --flavor m1.small --image cirros-0.6.2-x86_64-disk --network private --key-name test-key &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --block-device source_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;blank,destination_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;volume,volume_size&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --block-device source_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;blank,destination_type&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;volume,volume_size&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    test-server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;flavorRef&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;block_device_mapping_v2&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;uuid&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9acb21b3-0516-459a-9b0a-6357e66ff74a&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;boot_index&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;source_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;destination_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;local&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;delete_on_termination&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;source_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;blank&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;destination_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;volume&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;volume_size&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;5&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;source_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;blank&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;destination_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;volume&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;volume_size&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;5&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;imageRef&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9acb21b3-0516-459a-9b0a-6357e66ff74a&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are loads of other combinations available here, from creating volumes from snapshots to tagging created volumes,
but this should be sufficient to demonstrate the general &amp;ldquo;feel&amp;rdquo; of BDMs.&lt;/p&gt;
&lt;h2 id=&#34;final-thoughts&#34;&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;The main takeaway from this article should be that if you want to understand block devices in OpenStack, you&amp;rsquo;d be well
placed to understand BDMs. While they are terse, they do expose the most important aspects of block devices in
OpenStack, such as their differing sources and variety of ways that they can be configured. Does that mean that this
article is written backwards and should open with a piece on BDMs? Probably, but what fun would that be.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Availability Zones in Openstack and Openshift (Part 2)</title>
      <link>https://that.guru/blog/availability-zones-in-openstack-and-openshift-part-2/</link>
      <pubDate>Fri, 03 May 2024 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/availability-zones-in-openstack-and-openshift-part-2/</guid>
      <description>
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;This is part two of two. If you&amp;rsquo;re looking for part one, you can find it
&lt;a href=&#34;https://that.guru/blog/availability-zones-in-openstack-and-openshift-part-1&#34;&gt;here&lt;/a&gt;.&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;After seeing a few too many availability zone-related issues popping up in OpenShift clusters of late, I&amp;rsquo;ve decided it
might make sense to document the situation with OpenStack AZs on OpenShift (and, by extension, Kubernetes). This is the
second part of two. &lt;a href=&#34;https://that.guru/blog/availability-zones-in-openstack-and-openshift-part-1&#34;&gt;The first part&lt;/a&gt; provided some background on what AZs are and how you can configure them,
while this part will examine how AZs affect OpenShift and Kubernetes components such as the OpenStack Machine API
Provider, the OpenStack Cluster API Provider, and the Cinder and Manila CSI drivers.&lt;/p&gt;
&lt;h2 id=&#34;the-line-up&#34;&gt;The line up&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a couple of OpenStack-specific components we need to be aware of in a typical OpenShift-on-OpenStack (a.k.a.
ShiftStack) deployment. My former colleague Michał Dulko &lt;a href=&#34;https://dulek.github.io/2022/07/14/capo-mapo-cloud-provider.html&#34;&gt;provided a good overview of many of these on his
blog&lt;/a&gt; but to (re-)summarise, you&amp;rsquo;ve got:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cloud Provider OpenStack (CPO)&lt;/li&gt;
&lt;li&gt;Machine API Provider OpenStack (MAPO)&lt;/li&gt;
&lt;li&gt;Cluster API Provider OpenStack (CAPO)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to these three components, there are two others to consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cinder CSI Driver&lt;/li&gt;
&lt;li&gt;Manila CSI Driver&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Today we&amp;rsquo;re going to take a look at three of these five components - CPO, MAPO, and the Cinder CSI Driver - and explore
how availability zones - both Compute and Block Storage - impact them.&lt;/p&gt;
&lt;h2 id=&#34;cloud-provider-openstack&#34;&gt;Cloud Provider OpenStack&lt;/h2&gt;
&lt;p&gt;In contrast to a favoured programming language of mine 🐍, Kubernetes operates on very much batteries &lt;em&gt;not&lt;/em&gt; included
model. It does not provide out-of-the-box support for such important things as block storage, networking, or ingress. To
resolve this, you normally run Kubernetes on top of another platform - be that AWS, vSphere, GCE, or in our case
OpenStack - and add additional components that provide integration between your Kubernetes cluster and said platform and
its APIs. The cloud-provider interface provides one part of the integration puzzle here, managing the lifecycle of
&lt;code&gt;Node&lt;/code&gt;s (including their removal from the cluster if the underlying instance is deleted), &lt;code&gt;Service&lt;/code&gt;s of type
&lt;code&gt;LoadBalancer&lt;/code&gt;, and routes.&lt;/p&gt;

&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;If you&amp;rsquo;re interested, &lt;a href=&#34;https://medium.com/@m.json/the-kubernetes-cloud-controller-manager-d440af0d2be5&#34;&gt;this blog from Mikael Johansson&lt;/a&gt; provides a far more thorough overview of this
component.&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;The OpenStack CCM uses Compute AZ information for the underlying instance to label the corresponding &lt;code&gt;Node&lt;/code&gt;. It sets two
labels, the &lt;a href=&#34;https://kubernetes.io/docs/reference/labels-annotations-taints/#topologykubernetesiozone&#34;&gt;&lt;code&gt;topology.kubernetes.io/zone&lt;/code&gt;&lt;/a&gt; label and the legacy
&lt;a href=&#34;https://kubernetes.io/docs/reference/labels-annotations-taints/#failure-domainbetakubernetesiozone&#34;&gt;&lt;code&gt;failure-domain.beta.kubernetes.io/zone&lt;/code&gt;&lt;/a&gt; label. You can see this if you retrieve the labels
for a &lt;code&gt;Node&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc get Node -o jsonpath&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{.items[*].metadata.labels}&amp;#39;&lt;/span&gt; | jq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;beta.kubernetes.io/arch&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;amd64&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;beta.kubernetes.io/instance-type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ci.m1.xlarge&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;beta.kubernetes.io/os&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;linux&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failure-domain.beta.kubernetes.io/region&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;regionOne&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failure-domain.beta.kubernetes.io/zone&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nova&amp;#34;&lt;/span&gt;,  &lt;span style=&#34;color:#75715e&#34;&gt;# &amp;lt;--- !!! here !!!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kubernetes.io/arch&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;amd64&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kubernetes.io/hostname&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stephenfin-5ps6d-master-0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kubernetes.io/os&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;linux&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;node-role.kubernetes.io/control-plane&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;node-role.kubernetes.io/master&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;node.kubernetes.io/instance-type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ci.m1.xlarge&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;node.openshift.io/os_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rhcos&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topology.cinder.csi.openstack.org/zone&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nova&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topology.kubernetes.io/region&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;regionOne&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topology.kubernetes.io/zone&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nova&amp;#34;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# &amp;lt;--- !!! and here !!!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;It also sets two corresponding labels - the &lt;a href=&#34;https://kubernetes.io/docs/reference/labels-annotations-taints/#topologykubernetesioregion&#34;&gt;&lt;code&gt;topology.kubernetes.io/region&lt;/code&gt;&lt;/a&gt; label and the legacy
&lt;a href=&#34;https://kubernetes.io/docs/reference/labels-annotations-taints/#failure-domainbetakubernetesioregion&#34;&gt;&lt;code&gt;failure-domain.beta.kubernetes.io/region&lt;/code&gt;&lt;/a&gt; label - but these are sourced from
Keystone-related information.&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;To fetch the AZ information, OpenStack CCM queries the Nova API. You can see that happening
&lt;a href=&#34;https://github.com/openshift/cloud-provider-openstack/blob/release-4.15/pkg/openstack/openstack.go#L411-L463&#34;&gt;here&lt;/a&gt;,
and publishes this information via the &lt;code&gt;GetZoneByProviderID&lt;/code&gt; and &lt;code&gt;GetZoneByName&lt;/code&gt; functions, which form part of the
&lt;a href=&#34;https://github.com/kubernetes/cloud-provider/blob/v0.30.0/cloud.go#L281-L289&#34;&gt;cloud-provider API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Because the labels are defined on &lt;code&gt;Node&lt;/code&gt;s, they are useful for controlling the scheduling of pods, allowing users to
spread pods across multiple AZs. This is discussed in more details in the Kubernetes docs, in &lt;a href=&#34;https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/&#34;&gt;Assigning Pods to
Nodes&lt;/a&gt; and &lt;a href=&#34;https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/&#34;&gt;Pod Topology Spread
Constraints&lt;/a&gt; for example. They&amp;rsquo;re
also used for other topology-related features, such as &lt;a href=&#34;https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/&#34;&gt;Topology Aware
Routing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With regards to configuring these labels, there&amp;rsquo;s currently nothing to stop you modifying the labels in place. You
shouldn&amp;rsquo;t do this, however, since it doesn&amp;rsquo;t change the AZ of the underlying instance and pretty much kills whatever
advantage the topology feature has. If you want to change the AZ of the &lt;code&gt;Node&lt;/code&gt; then you&amp;rsquo;ll need to either migrate it (an
operation that comes with its own issues) or recreate it.&lt;/p&gt;
&lt;h2 id=&#34;machine-api-provider-openstack&#34;&gt;Machine API Provider OpenStack&lt;/h2&gt;
&lt;p&gt;The Machine API Provider OpenStack, or MAPO, is a Machine API provider for the OpenStack platform. The Machine API
allows you to scale up or scale down your cluster based on workload policies or other preferences and functions quite
similarly to the Cluster API, albeit with a different API. You can create &lt;code&gt;Machine&lt;/code&gt;s manually, but its more common to
instead create or modify &lt;code&gt;MachineSet&lt;/code&gt;s (for workers) or &lt;code&gt;ControlPlaneMachineSet&lt;/code&gt;s (for masters). You can find more
information about the Machine API in the &lt;a href=&#34;https://docs.openshift.com/container-platform/4.15/machine_management/index.html&#34;&gt;OpenShift
documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Like OpenStack CCM, MAPO uses AZ information to label resources - this time setting the &lt;code&gt;machine.openshift.io/zone&lt;/code&gt;
label on &lt;code&gt;Machine&lt;/code&gt; resources:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc get -A Machine -o jsonpath&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{.items[*].metadata.labels}&amp;#39;&lt;/span&gt; | jq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;machine.openshift.io/cluster-api-cluster&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stephenfin-5ps6d&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;machine.openshift.io/cluster-api-machine-role&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;master&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;machine.openshift.io/cluster-api-machine-type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;master&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;machine.openshift.io/instance-type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ci.m1.xlarge&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;machine.openshift.io/region&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;regionOne&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;machine.openshift.io/zone&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nova&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# &amp;lt;-- !!! here !!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;It also sets an additional related labels - the &lt;code&gt;machine.openshift.io/region&lt;/code&gt; label - but this is sourced from Keystone
information.&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;Also like OpenStack CCM, MAPO sources this AZ information from the Nova API, as you can see
&lt;a href=&#34;https://github.com/openshift/machine-api-provider-openstack/blob/release-4.15/pkg/machine/actuator.go#L226&#34;&gt;here&lt;/a&gt;
(&lt;code&gt;instanceStatus&lt;/code&gt; is a thin wrapper around a &lt;code&gt;ServerExt&lt;/code&gt; resource used by Gophercloud). They&amp;rsquo;re also editable but again,
editing them won&amp;rsquo;t actually change the AZ on the underlying instance and you&amp;rsquo;ll need to make changes elsewhere to do
this. However, unlike with &lt;code&gt;Node&lt;/code&gt;s, you can configure the AZ of a new or existing &lt;code&gt;Machine&lt;/code&gt; or &lt;code&gt;MachineSet&lt;/code&gt; /
&lt;code&gt;ControlPlaneMachineSet&lt;/code&gt; as part of the object definition and &lt;em&gt;this&lt;/em&gt; change will get reflected in the labels, both of
the &lt;code&gt;Machine&lt;/code&gt; and of the &lt;code&gt;Node&lt;/code&gt;. For example, to define a AZ when creating a new &lt;code&gt;MachineSet&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;machine.openshift.io/v1beta1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;MachineSet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;lt;infrastructure_id&amp;gt;-&amp;lt;role&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;namespace&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;openshift-machine-api&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;template&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;providerSpec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;value&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;availabilityZone&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nova-az0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;rootVolume&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;availabilityZone&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;cinder-az0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;This is described in more details in the &lt;a href=&#34;https://docs.openshift.com/container-platform/4.15/machine_management/creating_machinesets/creating-machineset-osp.html&#34;&gt;OpenShift
documentation&lt;/a&gt;.&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;Alternatively, to define one for a &lt;code&gt;ControlPlaneMachineSet&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;machine.openshift.io/v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ControlPlaneMachineSet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;cluster&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;namespace&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;openshift-machine-api&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;template&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;machines_v1beta1_machine_openshift_io&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;failureDomains&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;OpenStack&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;openstack&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;availabilityZone&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nova-az0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;rootVolume&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;availabilityZone&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;cinder-az0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;availabilityZone&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nova-az1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;rootVolume&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;availabilityZone&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;cinder-az1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;availabilityZone&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nova-az2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;rootVolume&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;availabilityZone&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;cinder-az2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;This is described in more detail in the &lt;a href=&#34;https://docs.openshift.com/container-platform/4.15/machine_management/control_plane_machine_management/cpmso-configuration.html#cpmso-sample-yaml-openstack_cpmso-configuration&#34;&gt;OpenShift
documentation&lt;/a&gt;.&lt;/div&gt;
&lt;/aside&gt;

&lt;h2 id=&#34;cinder-csi-driver&#34;&gt;Cinder CSI Driver&lt;/h2&gt;
&lt;p&gt;The last component we&amp;rsquo;re going to look at here is the Cinder CSI Driver. The Container Storage Interface (CSI) defines a
standardised way to expose arbitrary block and file storage systems to Kubernetes workloads, allowing us to plug in
storage backends for various cloud platforms or networked storage solutions like NFS or SMB. As you might suspect, the
Cinder CSI Driver allows us to plug in storage from the OpenStack Block Storage service, Cinder, and to create
&lt;code&gt;PersistentVolume&lt;/code&gt;s or &lt;code&gt;PersistentVolumeClaim&lt;/code&gt;s that correspond to Cinder volumes.&lt;/p&gt;
&lt;p&gt;Once again, the Cinder CSI driver uses AZ information to label resources and once again it&amp;rsquo;s the &lt;code&gt;Node&lt;/code&gt;s that get the
resulting label. The Cinder CSI driver sets a single label on a node, the &lt;code&gt;topology.cinder.csi.openstack.org/zone&lt;/code&gt;
label:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc get Node -o jsonpath&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{.items[*].metadata.labels}&amp;#39;&lt;/span&gt; | jq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;beta.kubernetes.io/arch&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;amd64&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;beta.kubernetes.io/instance-type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ci.m1.xlarge&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;beta.kubernetes.io/os&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;linux&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failure-domain.beta.kubernetes.io/region&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;regionOne&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failure-domain.beta.kubernetes.io/zone&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nova&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kubernetes.io/arch&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;amd64&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kubernetes.io/hostname&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stephenfin-5ps6d-master-0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kubernetes.io/os&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;linux&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;node-role.kubernetes.io/control-plane&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;node-role.kubernetes.io/master&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;node.kubernetes.io/instance-type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ci.m1.xlarge&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;node.openshift.io/os_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rhcos&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topology.cinder.csi.openstack.org/zone&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nova&amp;#34;&lt;/span&gt;,    &lt;span style=&#34;color:#75715e&#34;&gt;# &amp;lt;--- !!! here !!!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topology.kubernetes.io/region&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;regionOne&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;topology.kubernetes.io/zone&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nova&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unlike the other two components we&amp;rsquo;ve talked about though, the Cinder CSI Driver doesn&amp;rsquo;t fetch AZ information from the
API. Instead, it fetches it from the Metadata API, as you can see
&lt;a href=&#34;https://github.com/openshift/cloud-provider-openstack/blob/release-4.15/pkg/csi/cinder/nodeserver.go#L465-L469&#34;&gt;here&lt;/a&gt;.
That &lt;code&gt;NodeGetInfo&lt;/code&gt; function forms part of the CSI spec and is used by &lt;code&gt;kubelet&lt;/code&gt;, as detailed in the &lt;a href=&#34;https://kubernetes-csi.github.io/docs/node-driver-registrar.html&#34;&gt;Kubernetes
documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now this use of the Metadata service is somewhat of an usual choice: the Metadata service is provided by Nova and the AZ
information it exposes is the AZ of the instance (derived from the host the instance is scheduled to). It&amp;rsquo;s therefore a
Compute AZ so why is being used for a storage-related component? The answer is that we&amp;rsquo;re using it because there&amp;rsquo;s
nothing else to use: as described in &lt;a href=&#34;https://that.guru/blog/availability-zones-in-openstack-and-openshift-part-1&#34;&gt;part 1&lt;/a&gt;, OpenStack doesn&amp;rsquo;t provide any mechanism to associate compute
hosts with storage AZs outside of using the same naming scheme across both compute and block storage AZs. In my
experience, this loose coupling is a very frequent source of bugs. To use the topology feature (which we&amp;rsquo;ll go into more
detail on shortly), you really need to have a common set of AZs for both the Compute and Block Storage services. Until
OCP 4.15, the OpenStack Cinder CSI Driver Operator (i.e. the operator that deploys and manages the lifecycle of the
Cinder CSI Driver in an OpenShift deployment) assumed this to be the case and always enabled the topology feature. This
has &lt;a href=&#34;https://github.com/openshift/openstack-cinder-csi-driver-operator/pull/127&#34;&gt;since changed&lt;/a&gt; but if you&amp;rsquo;re running an
older release then you&amp;rsquo;re likely to encounter this issue if e.g. using multiple Nova AZs and single Cinder AZ.&lt;/p&gt;
&lt;p&gt;Making things even more complicated, migration of the Nova instance corresponding to a &lt;code&gt;Node&lt;/code&gt; can result in an instance
moving between AZs, assuming the Nova instance in question was not created in a specific AZ initially. The CSI driver
will detect this change and will attempt to update the labels on the &lt;code&gt;Node&lt;/code&gt;, resulting in the following rather nasty
error that will require manual intervention to solve.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Received NotifyRegistrationStatus call: &amp;amp;RegistrationStatus{PluginRegistered:false,Error:RegisterPlugin error -- plugin registration failed with err: error updating Node object with CSI driver node info: error updating node: timed out waiting for the condition; caused by: detected topology value collision: driver reported &amp;#34;topology.cinder.csi.openstack.org/zone&amp;#34;:&amp;#34;nova&amp;#34; but existing label is &amp;#34;topology.cinder.csi.openstack.org/zone&amp;#34;:&amp;#34;nova-az3&amp;#34;,}
Registration process failed with error: RegisterPlugin error -- plugin registration failed with err: error updating Node object with CSI driver node info: error updating node: timed out waiting for the condition; caused by: detected topology value collision: driver reported &amp;#34;topology.cinder.csi.openstack.org/zone&amp;#34;:&amp;#34;nova&amp;#34; but existing label is &amp;#34;topology.cinder.csi.openstack.org/zone&amp;#34;:&amp;#34;nova-az3&amp;#34;, restarting registration container.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;However, assuming we know about these issues and work to avoid them, how does one actually use the topology features
provided by the Cinder CSI driver? There are actually two ways. The first is to configure a topology-aware
&lt;code&gt;StorageClass&lt;/code&gt; and use this for a &lt;code&gt;PersistentVolumeClaim&lt;/code&gt;, as seen in the &lt;a href=&#34;https://github.com/kubernetes/cloud-provider-openstack/blob/v1.29.0/examples/cinder-csi-plugin/topology/example.yaml&#34;&gt;examples for the Cinder CSI
Driver&lt;/a&gt;.
For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;storage.k8s.io/v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;StorageClass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;topology-aware-standard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;provisioner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;cinder.csi.openstack.org&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;volumeBindingMode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;WaitForFirstConsumer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;allowedTopologies&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- &lt;span style=&#34;color:#f92672&#34;&gt;matchLabelExpressions&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;key&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;topology.cinder.csi.openstack.org/zone&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;values&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#ae81ff&#34;&gt;az1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;PersistentVolumeClaim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;demo-pvc-with-az&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;accessModes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#ae81ff&#34;&gt;ReadWriteOnce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;resources&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;requests&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;storage&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1Gi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;storageClassName&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;topology-aware-standard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By using this storage class, we ensure that the Cinder volume created for the PVC will request an availability zone of
&lt;code&gt;az1&lt;/code&gt;. This is the standard mechanism promoted by Kubernetes and is also supported by other non-OpenStack CSI drivers
that provide topology support.&lt;/p&gt;
&lt;p&gt;The other mechanism is to specify a Cinder CSI driver-specific parameter, &lt;code&gt;availability&lt;/code&gt;, when creating the storage
class. This is effectively a legacy option that pre-dates topology support in CSI but it&amp;rsquo;s still available:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;storage.k8s.io/v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;StorageClass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;legacy-az&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;provisioner&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;cinder.csi.openstack.org&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;volumeBindingMode&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;WaitForFirstConsumer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;parameters&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;availability&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;az1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;PersistentVolumeClaim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;demo-pvc-with-az&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;accessModes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#ae81ff&#34;&gt;ReadWriteOnce&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;resources&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;requests&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;storage&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1Gi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;storageClassName&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;legacy-az&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With regards to configuring these labels there&amp;rsquo;s currently nothing to stop you modifying the labels in place, just like
the labels OpenStack CCM sets on &lt;code&gt;Node&lt;/code&gt;s, and like that you don&amp;rsquo;t really want to do this since the Cinder CSI driver
effectively owns them. The only time you may wish to do this is if you&amp;rsquo;ve migrated your Nova instance and hit the issue
described above. In this case, you can opt to manually relabel the &lt;code&gt;Node&lt;/code&gt;, taking care to drain any workload from it
first to avoid topology mismatches.&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap up&lt;/h2&gt;
&lt;p&gt;As so concludes this two part series looking at Availability Zones in OpenStack and OpenShift. As you&amp;rsquo;ve hopefully
ascertained, they can be a very useful feature, particularly in larger deployments, but there are more than a few
potential banana skins to be aware of when you start using them for storage. By way of recommendations, I would suggest
either using a single common AZ for you deployment (you can stick to the default of &lt;code&gt;nova&lt;/code&gt;) or a common set of AZs
across both the compute and block storage hosts (e.g. in a two-AZ deployment, you could use &lt;code&gt;az0&lt;/code&gt; and &lt;code&gt;az1&lt;/code&gt; for both
compute and block storage AZs, rather than &lt;code&gt;nova-az0&lt;/code&gt; and &lt;code&gt;nova-az1&lt;/code&gt; for compute AZs and &lt;code&gt;cinder-az0&lt;/code&gt; and &lt;code&gt;cinder-az1&lt;/code&gt;
for block storage AZs). If you insist on sticking with divergent sets of AZs, you should disable the topology feature
and rely on the legacy &lt;code&gt;availability&lt;/code&gt; parameter of the &lt;code&gt;StorageClass&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;I hope this has been useful to someone. If you spot any mistakes or identify things that I should have covered but
didn&amp;rsquo;t, feel free to send me an email and I&amp;rsquo;ll try get things sorted.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>API routing in Openstack</title>
      <link>https://that.guru/blog/routers-in-openstack/</link>
      <pubDate>Wed, 01 May 2024 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/routers-in-openstack/</guid>
      <description>&lt;p&gt;In the Dalamation (2024.2) cycle, we&amp;rsquo;re working on adding OpenAPI schemas for a number of the OpenStack services. As
part of this effort, I&amp;rsquo;ve had to learn more than I would like to know about how various services&amp;rsquo; API machinery works.
The below is a quick summary of how the mapping of URLs (or rather, paths) to API controller methods works in Nova (and
Cinder, Manila and other projects that have copied or inherited Nova&amp;rsquo;s patterns). This is very much inside baseball and
probably not useful outside of OpenStack, since we&amp;rsquo;re using older libraries - namely &lt;a href=&#34;https://pypi.org/project/Routes/&#34;&gt;Routes&lt;/a&gt;, &lt;a href=&#34;https://pypi.org/project/Paste/&#34;&gt;Paste&lt;/a&gt;,
and &lt;a href=&#34;https://pypi.org/project/WebOb/&#34;&gt;WebOb&lt;/a&gt; - that have been mostly superseded by new libraries like Flask, Falcon, or Starlette. Still, maybe
it&amp;rsquo;s useful for someone.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The main entry point for routing in Nova is the &lt;a href=&#34;https://github.com/openstack/nova/blob/29.0.1/nova/api/openstack/compute/routes.py#L846-L884&#34;&gt;&lt;code&gt;APIRouterV21&lt;/code&gt;&lt;/a&gt; class. &lt;code&gt;APIRouterV21&lt;/code&gt; provides mappings
of URLs (or rather, URL paths) to methods of &lt;a href=&#34;https://github.com/openstack/nova/blob/29.0.1/nova/api/openstack/wsgi.py#L378&#34;&gt;&lt;code&gt;Resource&lt;/code&gt;&lt;/a&gt; objects using &lt;code&gt;routes.middleware.RoutesMiddleware&lt;/code&gt;
as the ultimate dispatcher. A &lt;code&gt;Resource&lt;/code&gt; object is a wrapper around some &lt;a href=&#34;https://github.com/openstack/nova/blob/29.0.1/nova/api/openstack/wsgi.py#L750&#34;&gt;&lt;code&gt;Controller&lt;/code&gt;&lt;/a&gt; objects: a main
controller and zero or more sub-controllers. If you look at &lt;a href=&#34;https://github.com/openstack/nova/blob/29.0.1/nova/api/openstack/compute/routes.py&#34;&gt;&lt;code&gt;nova/api/openstack/compute/routes.py&lt;/code&gt;&lt;/a&gt; you&amp;rsquo;ll
see a whole load of &lt;code&gt;functools.partial&lt;/code&gt; calls where we create &lt;code&gt;Resource&lt;/code&gt; objects via calls to &lt;code&gt;_create_controller&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;flavor_controller &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; functools&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;partial(_create_controller,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    flavors&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;FlavorsController,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        flavor_access&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;FlavorActionController
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here, &lt;code&gt;flavors.FlavorsController&lt;/code&gt; is the &amp;ldquo;main&amp;rdquo; controller and &lt;code&gt;flavor_access.FlavorActionController&lt;/code&gt; is a &amp;ldquo;sub&amp;rdquo; (or
&amp;ldquo;action&amp;rdquo;/&amp;ldquo;child&amp;rdquo;) controller. The sub-controller extends the main controller by adding new APIs or actions and to the
best of my knowledge it is legacy from the days where we had API extensions.&lt;/p&gt;
&lt;p&gt;These wrapped controllers are then mapped to paths latter in the same file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ROUTE_LIST &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/flavors/&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{id}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;GET&amp;#39;&lt;/span&gt;: [flavor_controller, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;show&amp;#39;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;PUT&amp;#39;&lt;/span&gt;: [flavor_controller, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;update&amp;#39;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;DELETE&amp;#39;&lt;/span&gt;: [flavor_controller, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;delete&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/flavors/&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{id}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;/action&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;: [flavor_controller, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;action&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;APIRouterV21&lt;/span&gt;(base_wsgi&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Router):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;__init__&lt;/span&gt;(self, custom_routes&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;None&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        super()&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;__init__&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; path, methods &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; ROUTE_LIST &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; custom_routes:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;# register route to mapper&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now with that knowledge, you can run this script locally to see the generated path-method mappings:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; nova.api.openstack &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; compute
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; oslo_config &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; cfg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; nova.tests &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; fixtures
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CONF &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cfg&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;CONF
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fixtures&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ConfFixture(CONF)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;setUp()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fixtures&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;RPCFixture(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;nova.test&amp;#39;&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;setUp()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;router &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; compute&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;APIRouterV21()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;count &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; route &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; router&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;map&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;matchlist:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;controller&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; route&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;defaults:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    controller &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; route&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;defaults[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;controller&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; controller&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;wsgi_actions &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; {}:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; action, method &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; controller&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;wsgi_actions&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;items():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        print(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;  action: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;action&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;, method: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;method&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;version_select&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; str(method):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            count &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;useless versioned method count: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;count&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All that this is doing is configuring enough config-related fixtures to allow us to create an &lt;code&gt;APIRouterV21&lt;/code&gt; instance so
that we can iterate through the path-controller mappings it has. If you run this, you&amp;rsquo;ll see a whole load of output
finishing in this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;useless versioned method count: 288
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a count of the number of actions that resolve to &lt;code&gt;version_select&lt;/code&gt; methods. &lt;code&gt;version_select&lt;/code&gt; methods are not the
&amp;ldquo;real&amp;rdquo; method and are instead wrappers around the real methods (potentially plural, depending on amount of
microversioned revisions) that allow us to handle API versioning. This wrapper methods are useless to us in the OpenAPI
work  because we need to get attributes of the real methods - namely, some private attributes we&amp;rsquo;re using to store the
schema used for a given method. The way to find the &amp;ldquo;real&amp;rdquo; method is to look at the &lt;code&gt;versioned_methods&lt;/code&gt; attribute of a
Controller, which contains a mapping of method name to real methods. If you change the above for loop you can see this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;count &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; route &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; router&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;map&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;matchlist:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;controller&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; route&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;defaults:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    controller &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; route&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;defaults[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;controller&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; controller&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;wsgi_actions &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; {}:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; action, method &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; controller&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;wsgi_actions&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;items():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        method_name &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; controller&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;controller&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;wsgi_actions&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(action)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; method_name:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            versioned_methods &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; getattr(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                controller&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;controller, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;versioned_methods&amp;#39;&lt;/span&gt;, {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            )&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(method_name)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; versioned_methods:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                method &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; versioned_methods[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;func
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        print(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;  action: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;action&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;, method: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;method&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;version_select&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; str(method):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            count &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;useless versioned method count: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;count&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now if you run this, you&amp;rsquo;ll get a reduced count:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;useless versioned method count: 224
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;However, it&amp;rsquo;s still not 0. This is because we&amp;rsquo;re not able to resolve to all &amp;ldquo;real&amp;rdquo; methods using only the &amp;ldquo;main&amp;rdquo;
controller alone. To do that, we need the &lt;code&gt;versioned_methods&lt;/code&gt; attribute of the sub-controllers also, or to use the case
of the controllers we gave at the start, the &lt;code&gt;versioned_methods&lt;/code&gt; attribute of both the &lt;code&gt;FlavorsController&lt;/code&gt; controller
and the &lt;code&gt;FlavorActionController&lt;/code&gt; controller. However, we currently have no reference to &lt;code&gt;FlavorActionController&lt;/code&gt; (or any
other sub controller) so we can&amp;rsquo;t do this.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&#34;https://review.opendev.org/c/openstack/nova/+/915732/&#34;&gt;patch I&amp;rsquo;ve proposed&lt;/a&gt; fixes this so that we store the reference to &lt;code&gt;FlavorActionController&lt;/code&gt; (and any other
sub-controller) under &lt;code&gt;Resource.sub_controllers&lt;/code&gt;, thus giving us a mechanism to retrieve &lt;code&gt;versioned_methods&lt;/code&gt; attributes
(and any other attribute we might need later) from these sub-controller. With this patch applied, we can change the for
loop further:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;count &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; route &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; router&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;map&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;matchlist:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;controller&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; route&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;defaults:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    controller &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; route&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;defaults[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;controller&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; controller&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;wsgi_actions &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; {}:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; action, method &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; controller&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;wsgi_actions&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;items():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        main_controller &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; controller&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;controller
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        method_name &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; main_controller&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;wsgi_actions&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(action)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; method_name:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            versioned_methods &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; getattr(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                main_controller, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;versioned_methods&amp;#39;&lt;/span&gt;, {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            )&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(method_name)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; versioned_methods:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                method &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; versioned_methods[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;func
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; sub_controller &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; controller&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;sub_controllers:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            method_name &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; sub_controller&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;wsgi_actions&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(action)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; method_name:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                versioned_methods &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; getattr(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    sub_controller, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;versioned_methods&amp;#39;&lt;/span&gt;, {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                )&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(method_name)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; versioned_methods:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    method &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; versioned_methods[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;func
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        print(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;  action: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;action&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;, method: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;method&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;version_select&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; str(method):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            count &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;useless versioned method count: &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;count&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this done, we finally get a 0 count:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;useless versioned method count: 0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This patch therefore means we&amp;rsquo;ll now be able to inspect elements of the various controller methods. We&amp;rsquo;re planning to
use this as part of the OpenAPI effort to associate a schema with a method so &lt;a href=&#34;https://review.opendev.org/c/openstack/nova/+/915735/&#34;&gt;we can ensure all API methods have
schemas&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Debugging Failed OpenShift-on-OpenStack Deployments</title>
      <link>https://that.guru/blog/debugging-failed-openshift-openstack-deployments/</link>
      <pubDate>Mon, 22 Apr 2024 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/debugging-failed-openshift-openstack-deployments/</guid>
      <description>&lt;p&gt;I deploy OpenShift-on-OpenStack quite regularly these days. Some times these deployments fail and the most common
failure I usually see is a timeout during bootstrapping.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ openshift-install --log-level debug create cluster
DEBUG OpenShift Installer 4.15.10
DEBUG Built from commit 24a827900e76d8f9c79122307415b47a4921bbd7
DEBUG Fetching Metadata...
...
DEBUG Reusing previously-fetched Install Config
INFO Skipping VM console logs gather: no gather methods registered for &amp;#34;openstack&amp;#34;
INFO Pulling debug logs from the bootstrap machine
DEBUG Using SSH_AUTH_SOCK /run/user/1000/keyring/ssh to connect to an existing agent
ERROR Attempted to gather debug logs after installation failure: failed to connect to the bootstrap machine: dial tcp 10.0.212.9:22: connect: connection timed out
ERROR Attempted to gather ClusterOperator status after installation failure: listing ClusterOperator objects: Get &amp;#34;https://api.stephenfin.shiftstack-demo.com:6443/apis/config.openshift.io/v1/clusteroperators&amp;#34;: dial tcp 10.0.214.50:6443: i/o timeout
ERROR Bootstrap failed to complete: timed out waiting for the condition
ERROR Failed to wait for bootstrapping to complete. This error usually happens when there is a problem with control plane hosts that prevents the control plane operators from creating the control plane.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You&amp;rsquo;ve a couple of tools that you can use to validate this. The first of these is to check the serial console.
This will highlight the more egregious issues with your deployment. You can do this with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ openstack console url show stephenfin-5ps6d-bootstrap  &lt;span style=&#34;color:#75715e&#34;&gt;# replace with your own bootstrap server&amp;#39;s name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If this doesn&amp;rsquo;t show anything weird then the next step is to log in to the server and check the status of the &lt;code&gt;bootkube&lt;/code&gt;
service. As is custom with OpenStack, to SSH into a machine you need (a) a floating IP and (b) a security group (or more
accurately a security group rule) that allows SSH access. The Installer automatically assigns a floating IP to the
bootstrap machine so (a) is taken care of. That leaves (b). You like already have an &amp;ldquo;allow SSH&amp;rdquo; security group lying
around and if so, you can use that now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ openstack server add security group stephenfin-5ps6d-bootstrap allow_ssh  &lt;span style=&#34;color:#75715e&#34;&gt;# replace with your own server, SG names&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;&lt;p&gt;If you don&amp;rsquo;t have such a group, creating one is easy. The following ought to do the trick:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ openstack security group create allow_ssh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ openstack security group rule create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --protocol tcp --dst-port &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; --remote-ip 0.0.0.0/0 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    allow_ssh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ openstack security group rule create &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    --protocol icmp --remote-ip 0.0.0.0/0 &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    allow_ssh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;Once you&amp;rsquo;ve allowed SSH traffic you can SSH into the machine.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ openstack server ssh stephenfin-5ps6d-bootstrap -- -l core
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;&lt;code&gt;core&lt;/code&gt; is the default username for Red Hat CoreOS.&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;From here you can follow the directions given in the MOTD and check the &lt;code&gt;bootkube&lt;/code&gt; service first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ journalctl -b -f -u release-image.service -u bootkube.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In my case it appeared the issue was the lack of access to the master nodes:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;s the base image from which all OpenShift Container Platform images inherit.)
Apr 22 14:01:09 stephenfin-5ps6d-bootstrap bootkube.sh[2449]: Check if API and API-Int URLs are reachable during bootstrap
Apr 22 14:01:09 stephenfin-5ps6d-bootstrap bootkube.sh[2449]: Checking if api.stephenfin.shiftstack-demo.com of type API_URL reachable
Apr 22 14:01:09 stephenfin-5ps6d-bootstrap bootkube.sh[2449]: Unable to reach API_URL&amp;#39;s https endpoint at https://api.stephenfin.shiftstack-demo.com:6443/version
Apr 22 14:01:09 stephenfin-5ps6d-bootstrap bootkube.sh[2449]: Unable to validate. https://api.stephenfin.shiftstack-demo.com:6443/version is currently unreachable.
Apr 22 14:01:09 stephenfin-5ps6d-bootstrap bootkube.sh[2449]: Checking if api-int.stephenfin.shiftstack-demo.com of type API_INT_URL reachable
Apr 22 14:01:09 stephenfin-5ps6d-bootstrap bootkube.sh[2449]: Unable to reach API_INT_URL&amp;#39;s https endpoint at https://api-int.stephenfin.shiftstack-demo.com:6443/version
Apr 22 14:01:09 stephenfin-5ps6d-bootstrap bootkube.sh[2449]: Unable to validate. https://api-int.stephenfin.shiftstack-demo.com:6443/version is currently unreachable.
Apr 22 14:01:09 stephenfin-5ps6d-bootstrap bootkube.sh[2449]: bootkube.service complete
Apr 22 14:01:09 stephenfin-5ps6d-bootstrap systemd[1]: bootkube.service: Deactivated successfully.
Apr 22 14:01:09 stephenfin-5ps6d-bootstrap systemd[1]: bootkube.service: Consumed 1min 2.337s CPU time.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The same steps apply for debugging issues with master or worker nodes: add a floating IP, allow SSH access, then SSH
into the machine.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ openstack server add floating ip stephenfin-5ps6d-master-0 10.0.214.101
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ openstack server add security group stephenfin-5ps6d-master-0 allow_ssh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ openstack server ssh stephenfin-5ps6d-master-0 -- -l core
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>Availability Zones in Openstack and Openshift (Part 1)</title>
      <link>https://that.guru/blog/availability-zones-in-openstack-and-openshift-part-1/</link>
      <pubDate>Tue, 22 Aug 2023 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/availability-zones-in-openstack-and-openshift-part-1/</guid>
      <description>
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;This is part one of two. If you&amp;rsquo;re looking for part two, you can find it
&lt;a href=&#34;https://that.guru/blog/availability-zones-in-openstack-and-openshift-part-2&#34;&gt;here&lt;/a&gt;.&lt;/div&gt;
&lt;/aside&gt;


&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;This post has been updated since publication to add additional information about implicit and explicit AZs.&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;After seeing a few too many availability zone-related issues popping up in OpenShift clusters of late, I&amp;rsquo;ve decided it
might make sense to document the situation with OpenStack AZs on OpenShift (and, by extension, Kubernetes). This is the
first of two parts. This part provides some background on what AZs are and how you can configure them, while the &lt;a href=&#34;https://that.guru/blog/availability-zones-in-openstack-and-openshift-part-2&#34;&gt;second
part&lt;/a&gt; examines how AZs affect OpenShift and Kubernetes components such as the OpenStack Machine API Provider,
the OpenStack Cluster API Provider, and the Cinder and Manila CSI drivers.&lt;/p&gt;
&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;
&lt;p&gt;Both the Compute (Nova) and Block Storage (Cinder) services in OpenStack support the concept of Availability Zones (AZs)
and the envisioned use cases is very similar for both. Quoting from the &lt;a href=&#34;https://docs.openstack.org/nova/latest/admin/availability-zones.html&#34;&gt;Nova documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Availability Zones are an end-user visible logical abstraction for partitioning a cloud without knowing the physical
infrastructure. They can be used to partition a cloud on arbitrary factors, such as location (country, datacenter,
rack), network layout and/or power source.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Nova documentation then goes on to specifically note that the AZ feature provides no HA benefit in and of itself -
whatever benefits there are are entirely down to how the deployment is designed - thus it&amp;rsquo;s really just a way to signal
something you&amp;rsquo;ve done in your physical deployment. All of this is equally true of both Nova and Cinder, and in my
experience I&amp;rsquo;ve seen AZs used to demarcate both compute and block storage nodes existing on different racks or in
different datacenters.&lt;/p&gt;

&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;The Networking (Neutron) service also has the concept of Availability Zones. However, I&amp;rsquo;m not at all familiar with how
these work and they&amp;rsquo;re not something I&amp;rsquo;ve ever used. As a result, I&amp;rsquo;m not going to cover them here.&lt;/div&gt;
&lt;/aside&gt;

&lt;h2 id=&#34;configuring-azs-for-hosts&#34;&gt;Configuring AZs for hosts&lt;/h2&gt;
&lt;p&gt;As you might expect, Cinder AZ&amp;rsquo;s are an attribute of the block storage hosts (i.e. hosts running the &lt;code&gt;cinder-volume&lt;/code&gt;
service). As discussed &lt;a href=&#34;#configuration&#34;&gt;later&lt;/a&gt;, you can configure a host&amp;rsquo;s AZ by setting the &lt;code&gt;[DEFAULT] storage_availability_zone&lt;/code&gt; configuration option in &lt;code&gt;cinder.conf&lt;/code&gt;. By comparison, Nova&amp;rsquo;s AZs are not typically configured
via &lt;code&gt;nova.conf&lt;/code&gt; but are actually attributes of host aggregates and can be configured by setting the &lt;code&gt;availability_zone&lt;/code&gt;
metadata key of an aggregate. If a compute host (i.e. a host running the &lt;code&gt;nova-compute&lt;/code&gt; service) belongs to a host
aggregate with the AZ metadata key set then the host will inherit the AZ of that host aggregate. It&amp;rsquo;s only when a host
doesn&amp;rsquo;t belong to a host aggregate - or none of the host aggregates it belongs to have AZ metadata set - that this
information will be sourced from elsewhere, namely the &lt;code&gt;[DEFAULT] default_availability_zone&lt;/code&gt; config option described
&lt;a href=&#34;#configuration&#34;&gt;below&lt;/a&gt;. Unlike Cinder&amp;rsquo;s config option, this is not intended to differ by host and should be set to the
same value across all compute nodes. Nova will prevent you adding a host to more than one aggregate with AZ metadata set
since a host can only belong to one AZ.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack aggregate create --zone nova-az1 foo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack aggregate create --zone nova-az2 bar
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack aggregate add host foo stephenfin-devstack
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack aggregate add host bar stephenfin-devstack
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ConflictException: 409: Client Error &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; url: http://10.0.109.204/compute/v2.1/os-aggregates/13/action, Cannot add host to aggregate 13. Reason: One or more hosts already in availability zone&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;s&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;nova-az1&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In addition, if a host has instances on it, the Nova will also prevent you from modifying the AZ metadata of an
aggregate it already belongs to - since this would break the AZ constraint placed on any of the existing instances:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server show test-server -f value -c OS-EXT-AZ:availability_zone -c OS-EXT-SRV-ATTR:host
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nova-az1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;stephenfin-devstack
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack aggregate show foo -f value -c availability_zone -c hosts
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nova-az1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;stephenfin-devstack&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack aggregate set --zone nova-az2 foo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BadRequestException: 400: Client Error &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; url: http://10.0.109.204/compute/v2.1/os-aggregates/12, Cannot update aggregate 12. Reason: One or more hosts contain instances in this zone.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;It should also prevent you from adding/removing a host to/from an aggregate when instances are present but this doesn&amp;rsquo;t
currently happen. This is filed as &lt;a href=&#34;https://bugs.launchpad.net/nova/+bug/1907775&#34;&gt;bug #1907775&lt;/a&gt; and has not yet been
resolved.&lt;/div&gt;
&lt;/aside&gt;

&lt;h2 id=&#34;requesting-azs-for-resources-servers-volumes-volume-backups-&#34;&gt;Requesting AZs for resources (servers, volumes, volume backups, &amp;hellip;)&lt;/h2&gt;
&lt;p&gt;Nova allows you to specify an AZ when creating an instance (or &amp;ldquo;server&amp;rdquo;, in OpenStackClient parlance), while Cinder
allows you to specify them when creating a volume, a volume backup, a volume group, or (volume groups&amp;rsquo; deprecated
predecessor) a consistency group. For example, to create an instance (or &amp;ldquo;server&amp;rdquo;) with an explicit compute AZ:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openstack server create --availability-zone compute-az1 ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Likewise, to create a volume and volume backup with an explicit block storage AZ:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openstack volume create --availability-zone volume-az1 ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openstack volume backup create --availability-zone volume-az2 ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, you&amp;rsquo;ll note that these resource types will always have AZ information associated with them, even when an AZ
wasn&amp;rsquo;t specifically requested during creation. This is because, in the absence of specific AZ information, both services
will default to setting the AZ of the resource to the AZ of the host that the resource was created on. Put another way,
if I create instance &lt;code&gt;my-server&lt;/code&gt; with no AZ information and it ends up on host &lt;code&gt;my-host&lt;/code&gt;, then &lt;code&gt;my-server&lt;/code&gt; will inherit
the AZ of &lt;code&gt;my-host&lt;/code&gt;. Block storage resources work in the same way, meaning volume &lt;code&gt;my-volume&lt;/code&gt; will inherit the AZ of the
host it is scheduled to. As a result, there has historically been no way for an end-user to tell if an AZ was explicitly
requested when creating a server or not. In fact, the only way they will find out is if they try to move the server
since Nova will insist of moving the instance to another host within the same AZ (this wouldn&amp;rsquo;t happen for a server that
wasn&amp;rsquo;t explicitly created in an AZ). As we&amp;rsquo;ll touch on in &lt;a href=&#34;https://that.guru/blog/availability-zones-in-openstack-and-openshift-part-2&#34;&gt;part 2&lt;/a&gt;, this has been rather frustrating from an
OpenShift or Kubernetes perspective since Kubernetes&amp;rsquo; topology feature is a hard requirement and it does not like us
changes the AZ-related labels of &lt;code&gt;Node&lt;/code&gt; or &lt;code&gt;Machine&lt;/code&gt; objects, which can happen when you migrate the underlying server
and the server picks up the AZ of the new host. Fortunately, the 2024.1 (Caracal) release of OpenStack introduced a new
field to the &lt;code&gt;GET /servers/{serverID}&lt;/code&gt; response called &lt;code&gt;pinned_availability_zone&lt;/code&gt; which will show the AZ requested
during initial instance creation, if set and it&amp;rsquo;s just a matter of time before we&amp;rsquo;re able to start consuming this in the
various OpenShift and Kubernetes components.&lt;/p&gt;
&lt;h2 id=&#34;combining-nova-and-cinders-az-features&#34;&gt;Combining Nova and Cinder&amp;rsquo;s AZ features&lt;/h2&gt;
&lt;p&gt;Finally, it&amp;rsquo;s worth exploring the interplay of the Nova and Cinder AZ features since this will be particularly relevant
in &lt;a href=&#34;https://that.guru/blog/availability-zones-in-openstack-and-openshift-part-2&#34;&gt;part 2&lt;/a&gt;. In a &lt;a href=&#34;https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/16.2/html-single/hyperconverged_infrastructure_guide/index&#34;&gt;Hyperconverged Infrastructure (HCI)&lt;/a&gt; deployment, where compute and block storage
services run side-by-side on hyperconverged hosts, the compute hosts &lt;em&gt;are&lt;/em&gt; the block storage hosts and there is no
difference between the AZs. In a non-HCI deployment, this is unlikely to be the case but this hasn&amp;rsquo;t prevented people
and applications from frequently munging the two types of AZ, as we will see later. Because this conflation of different
AZ types can happen, the general expectation we would have is that one of the following is true:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;There is only a single compute AZ, a single block storage and they have the same name.&lt;/em&gt; This is the default
configuration if you use &amp;ldquo;stock&amp;rdquo; OpenStack: Nova&amp;rsquo;s default AZ is &lt;code&gt;nova&lt;/code&gt; and Cinder helpfully defaults to the same
value.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;There are multiple compute and block storage AZs, but there is the same number of both and they share the same
name.&lt;/em&gt; For example, both the compute and block storage services have the following AZs defined: &lt;code&gt;AZ0&lt;/code&gt;, &lt;code&gt;AZ1&lt;/code&gt;, and
&lt;code&gt;AZ2&lt;/code&gt;. In this case, users and applications which incorrectly use compute host AZ information to configure the AZ of
volumes and related block storage resources will &amp;ldquo;just work&amp;rdquo;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;There are multiple compute and block storage AZs, and there is either a different number of each or they have
different names.&lt;/em&gt; For example, the compute services have the &lt;code&gt;compute-az0&lt;/code&gt; and &lt;code&gt;compute-az1&lt;/code&gt; AZs defined while the
block storage services have the &lt;code&gt;volume-az0&lt;/code&gt; and &lt;code&gt;volume-az1&lt;/code&gt; AZs defined. In this case, the users and applications
must be very careful to explicitly specify a correct AZ when creating volumes and related block storage resources and
must ensure Nova is configured to allow attaching volumes in other AZs (more of this later too).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;The last case above isn&amp;rsquo;t helped by the fact that neither Nova nor Cinder provide an API to request the correct block
storage AZ for a given compute host. To be fair, such an API would likely be a rather difficult thing to do, given
multiple backends are a thing to be considered. It would be effectively impossible to do automatically, meaning there
would still be initial manual configuration required. The closest analog we have for his today is the &lt;a href=&#34;https://docs.openstack.org/cinder/2023.1/admin/availability-zone-type.html&#34;&gt;Volume Type AZ
feature&lt;/a&gt;, which allows you to indicate the AZs that can be used when creating a volume with a given
volume type (so that e.g. a particular block storage backend that is only available to one rack can&amp;rsquo;t be requested by
volumes hosted by block storage services running on another rack). As the docs for that indicate, this configuration is
entirely deployment specific and therefore totally manual.&lt;/div&gt;
&lt;/aside&gt;

&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap up&lt;/h2&gt;
&lt;p&gt;That concludes part 1 of this OpenShift-centric examination of OpenStack Availability Zones. In this part we focused
almost exclusively on OpenStack itself, looking at what AZs are, how they&amp;rsquo;re configured and used, and the various issues
people are likely to encounter along the way, but in &lt;a href=&#34;https://that.guru/blog/availability-zones-in-openstack-and-openshift-part-2&#34;&gt;part 2&lt;/a&gt; we&amp;rsquo;re going to turn our focus to how OpenStack AZs
are consumed and represented by OpenShift components when an OpenShift cluster is deployed on an OpenStack cloud. Stay
tuned!&lt;/p&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;h3 id=&#34;configuration&#34;&gt;Configuration&lt;/h3&gt;
&lt;p&gt;Since this feature exists across two services, there are two sets of configuration options to be concerned with.&lt;/p&gt;
&lt;p&gt;As of the 2023.1 (Antelope) release, Nova has three relevant configuration options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;[DEFAULT] default_availability_zone&lt;/code&gt; defines the default AZ of each compute host, which can be changed by adding the
host to a host aggregate and setting the special &lt;code&gt;availability_zone&lt;/code&gt; metadata property as described in the &lt;a href=&#34;https://docs.openstack.org/nova/latest/admin/availability-zones.html&#34;&gt;nova
docs&lt;/a&gt;. This option defaults to &lt;code&gt;nova&lt;/code&gt; and as noted in the &lt;a href=&#34;https://docs.openstack.org/nova/latest/admin/availability-zones.html&#34;&gt;nova docs&lt;/a&gt;, the default AZ should never
explicitly requesting this AZ when creating new instances since it will prevent migration of instance between
different hosts in different AZs (which is allowed by default if the AZ was unset during initial creation) as well as
identification of hosts that are missing AZ information. You have been warned.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;[DEFAULT] default_schedule_zone&lt;/code&gt; defines the default AZ that should be assigned to an instance on creation. If this
is unset, the instance will be assigned an implicit AZ of the host it lands on. You might want to use this if you
wanted the majority of instances to go into a &amp;ldquo;generic&amp;rdquo; AZ while special instances can go into specific AZs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;[cinder] cross_az_attach&lt;/code&gt; determines whether volumes are allowed to be attached to an instance if the instance host&amp;rsquo;s
compute AZ differs from that of the volume&amp;rsquo;s block storage AZ. It also determines whether volumes created when
creating a boot-from-volume server have an explicit AZ associated with them or not. This defaults to &lt;code&gt;true&lt;/code&gt; and with
good reason, given the aforementioned caveats around munging of compute and block storage AZs and the need for them to
be identical.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is also the &lt;code&gt;[DEFAULT] internal_service_availability_zone&lt;/code&gt; configuration option, but this has no real impact for
end-users.&lt;/p&gt;
&lt;p&gt;As of the 2023.1 (Antelope) release, Cinder has four relevant configuration options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;[DEFAULT] storage_availability_zone&lt;/code&gt; defines the default AZ of the block storage host. This defaults to &lt;code&gt;nova&lt;/code&gt; and
can be overridden on a per-backend basis using &lt;code&gt;[foo] backend_availability_zone&lt;/code&gt;. Speaking of which&amp;hellip;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;[foo] backend_availability_zone&lt;/code&gt; define the default AZ for a specific backend of the block storage host. &lt;code&gt;foo&lt;/code&gt; should
be the name of the volume backend, as defined in &lt;code&gt;[DEFAULT] enabled_backends&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;[DEFAULT] default_availability_zone&lt;/code&gt; defines the default AZ that should be assigned to a volume on creation. If this
is unset, the volume will be assigned the AZ of the host it lands on (which in turn defaults to &lt;code&gt;[DEFAULT] storage_availability_zone&lt;/code&gt;, per above).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;[DEFAULT] allow_availability_zone_fallback&lt;/code&gt; allows you to ignore an request for an invalid block storage AZ and
instead fallback to the default AZ defined in &lt;code&gt;[DEFAULT] default_availability_zone&lt;/code&gt;. This defaults to &lt;code&gt;false&lt;/code&gt;, though
to be honest &lt;code&gt;true&lt;/code&gt; is probably a sensible value for configurations where e.g. there are multiple compute AZs and a
single volume AZ.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;usage&#34;&gt;Usage&lt;/h3&gt;
&lt;p&gt;Again, since this feature exists across two services, there are two sets of resource types to be concerned with.&lt;/p&gt;
&lt;p&gt;To configure the AZ of a compute host, you configure AZ information for a host aggregate and then add the host to this
aggregate.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack aggregate create --zone nova-az1 foo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack aggregate add host foo stephenfin-devstack
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once this is done, you can request the AZ when creating an instance (or &amp;ldquo;server&amp;rdquo;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server create --availability-zone nova-az1 ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On the other hand, the AZ of a storage host is configured via config and there&amp;rsquo;s no API method to configure it. You can
use it when creating a volume just like creating a server though:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openstack volume create --availability-zone volume-az1 ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or when creating a volume backup:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openstack volume backup create --availability-zone volume-az2 ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Other API libraries like gophercloud also expose these attributes and allow them to be configured, but we won&amp;rsquo;t go into
that here.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Listening to notifications in Openstack</title>
      <link>https://that.guru/blog/notifications-in-openstack/</link>
      <pubDate>Fri, 07 Jul 2023 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/notifications-in-openstack/</guid>
      <description>&lt;p&gt;Another short one. As mostly anyone that has had to maintain an OpenStack cluster will know, many of the OpenStack
services has the ability to report notifications via the message bus. These notifications will be enabled in most
production deployments but DevStack doesn&amp;rsquo;t enable them by default. Fortunately enabling them is pretty painless. If we
wanted to enable the notifications in, say, Keystone, we can do so by configuring the following in
&lt;code&gt;/etc/keystone/keystone.conf&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[oslo_messaging_notifications]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;transport_url&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;rabbit://stackrabbit:***@***:5672/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;messagingv2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These options are provided by the &lt;a href=&#34;https://docs.openstack.org/oslo.messaging/latest/&#34;&gt;oslo.messaging&lt;/a&gt; project, which virtually every OpenStack service
harnesses.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve enabled them though, you what can you do with them? Using the &lt;code&gt;messagingv2&lt;/code&gt; means they&amp;rsquo;re published over the
AMQP message bus (and the message is enveloped, which is the difference to &lt;code&gt;messaging&lt;/code&gt;), however, they&amp;rsquo;re not exposed
via HTTP APIs or similar. We could whip out a telemetry tool like &lt;a href=&#34;https://docs.openstack.org/ceilometer/latest/&#34;&gt;Ceilometer&lt;/a&gt; but that seems overkill for a
quick bit of debugging. Well it turns out &lt;em&gt;oslo.messaging&lt;/em&gt; provides utilities for both creating notifications &lt;strong&gt;and&lt;/strong&gt;
listening to them. Writing a listener is relatively simple:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; json
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; logging
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; oslo_config &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; cfg
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; oslo_messaging
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cfg&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;CONF()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;logging&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;basicConfig(level&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;logging&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;INFO)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LOG &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; logging&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;getLogger()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;URL &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;rabbit://stackrabbit:***@***:5672/&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;NotificationEndpoint&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_notify&lt;/span&gt;(self, ctxt, publisher_id, event_type, payload, metadata):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        LOG&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;info(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;notification received &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; (publisher_id, event_type))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        output &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; json&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;dumps(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;payload&amp;#34;&lt;/span&gt;: payload,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;publisher_id&amp;#34;&lt;/span&gt;: publisher_id,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;event_type&amp;#34;&lt;/span&gt;: event_type,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            indent&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        print(output)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    audit &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; _notify
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    debug &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; _notify
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    info &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; _notify
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    warn &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; _notify
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    error &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; _notify
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    critical &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; _notify
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sample &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; _notify
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    transport &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; oslo_messaging&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_notification_transport(cfg&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;CONF, url&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;URL)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    targets &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [oslo_messaging&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Target(topic&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;notifications&amp;#39;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    endpoints &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [NotificationEndpoint()]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    server &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; oslo_messaging&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get_notification_listener(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        transport,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        targets,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        endpoints,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        executor&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;threading&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    LOG&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;info(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;messaging starting&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    server&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;start()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    LOG&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;info(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;messaging started&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    server&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;wait()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    LOG&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;info(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;exit&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; __name__ &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    main()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;Don&amp;rsquo;t forget to update &lt;code&gt;URL&lt;/code&gt; to match the value of your services&#39;
&lt;a href=&#34;https://docs.openstack.org/oslo.messaging/latest/configuration/opts.html#oslo_messaging_notifications.transport_url&#34;&gt;&lt;code&gt;[oslo_messaging_notifications] transport_url&lt;/code&gt;&lt;/a&gt;. You might also need to modify the target topic or
add additional targets if any of your services override &lt;a href=&#34;https://docs.openstack.org/oslo.messaging/latest/configuration/opts.html#oslo_messaging_notifications.topics&#34;&gt;&lt;code&gt;[oslo_messaging_notifications] topics&lt;/code&gt;&lt;/a&gt;.&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;If you run this and then, say, attempt to authenticate with invalid credentials, you&amp;rsquo;ll see notifications arriving:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;payload&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;typeURI&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://schemas.dmtf.org/cloud/audit/1.0/event&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;eventType&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;activity&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;68c5b24b-89f0-5c93-abe4-5c3d6651fb00&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;eventTime&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2023-07-07T15:52:00.496156+0000&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;action&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;authenticate&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;outcome&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failure&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;observer&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;08d95fde312344debbcc00106b139995&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;typeURI&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;service/security&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;initiator&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;78fab588d9d34900a6c59fc22f3a2049&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;typeURI&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;service/security/account/user&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;address&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;***&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;agent&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;openstacksdk/1.3.0 keystoneauth1/5.2.1 python-requests/2.31.0 CPython/3.11.4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;request_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;req-0126be50-db3a-4975-a814-d717a5fdfdf8&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;user_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;***&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;***&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;target&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fc220ce7-2787-5152-bf81-9943cb8ee24b&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;typeURI&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;service/security/account/user&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;publisher_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;identity.stephenfin-devstack&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;event_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;identity.authenticate&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This can be extremely valuable for debugging since notifications will expose things that aren&amp;rsquo;t necessarily obvious from
logs.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Deploying MetalLB with BGP on Openstack (Part 2)</title>
      <link>https://that.guru/blog/deploying-metallb-on-openstack-part-2/</link>
      <pubDate>Tue, 23 May 2023 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/deploying-metallb-on-openstack-part-2/</guid>
      <description>
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;This is part two of two. If you&amp;rsquo;re looking for part one, you can find it
&lt;a href=&#34;https://that.guru/blog/deploying-metallb-on-openstack-part-1&#34;&gt;here&lt;/a&gt;.&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;As noted &lt;a href=&#34;https://that.guru/blog/deploying-metallb-on-openstack-part-1&#34;&gt;previously&lt;/a&gt;, one of the goals for an upcoming OpenShift release is to formally support
&lt;a href=&#34;https://metallb.universe.tf/&#34;&gt;MetalLB&lt;/a&gt; and the &lt;a href=&#34;https://github.com/metallb/metallb-operator&#34;&gt;MetalLB operator&lt;/a&gt; on the OpenStack platform. In part one of the series,
we configured an environment with OpenStack, OpenShift and BGP software routers. Now, in part two, we&amp;rsquo;re going to focus
on installing and configuring MetalLB itself.&lt;/p&gt;
&lt;h2 id=&#34;install-metallb&#34;&gt;Install MetalLB&lt;/h2&gt;
&lt;p&gt;The first step on the path to using MetalLB is actually installing it. As a reminder, we want to use MetalLB in &lt;em&gt;BGP
mode&lt;/em&gt;. This necessitates things like routers that speak BGP and an OpenStack deployment that is configured to talk to
these routers. These were all discussed in &lt;a href=&#34;https://that.guru/blog/deploying-metallb-on-openstack-part-1&#34;&gt;part one&lt;/a&gt; of this series, and if you followed along with this then
you will currently have a deployment that looks like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://that.guru/media/deploying-metallb-on-openstack-1.png&#34;
    alt=&#34;Image displaying the network topology of VMs in a deployment&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Our deployment configured&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;If this is not the case, you probably want to read that part first. However, assuming it is, we can now proceed with
installation. As a Kubernetes-native project, MetalLB comes with all the usual mechanisms for installation of Kubernetes
components. Plain manifests are provided, as are Helm Charts and an operator, the MetalLB Operator. The various
installation mechanisms are all discussed in the &lt;a href=&#34;https://metallb.universe.tf/installation/&#34;&gt;MetalLB installation guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Because operators are awesome, I opted to use the MetalLB Operator to deploy MetalLB and manage its lifecycle. The
MetalLB Operator is available on OperatorHub at operatorhub.io/operator/metallb-operator but when I was testing, the
&lt;code&gt;main&lt;/code&gt; branch contained a feature I wanted, namely the ability to configure a &lt;a href=&#34;https://github.com/metallb/metallb-operator/pull/342&#34;&gt;&lt;code&gt;loadBalancerClass&lt;/code&gt;&lt;/a&gt;. As a
result, I opted to deploy MetalLB Operator from source. The MetalLB Operator provides a very helpful &lt;code&gt;Make&lt;/code&gt; target to do
this, which you can use:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ git clone https://github.com/metallb/metallb-operator
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ cd metallb-operator
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ make deploy-openshift
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Deployment takes a while but once finished we can validate that everything is running:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc get all -n metallb-system
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Installation complete! Now onto configuration.&lt;/p&gt;
&lt;h2 id=&#34;initial-metallb-configuration&#34;&gt;Initial MetalLB configuration&lt;/h2&gt;
&lt;p&gt;With the MetalLB Operator installed, it&amp;rsquo;s time to &lt;em&gt;configure&lt;/em&gt; MetalLB. By using MetalLB Operator we gain the ability to
manage configuration of MetalLB itself via CRs. First up is the &lt;code&gt;MetalLB&lt;/code&gt; CR. This is primary configuration mechanism
and is the thing that enables MetalLB itself. There should only be one of them, which you can create like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ cat &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt; EOF | oc apply -f -
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;apiVersion: metallb.io/v1beta1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;kind: MetalLB
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    name: metallb
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    namespace: metallb-system
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    loadBalancerClass: &amp;#39;metallb.universe.tf/metallb&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    nodeSelector:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;        kubernetes.io/os: linux
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;        node-role.kubernetes.io/worker: &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are a couple of things to note here. Firstly, we are configuring &lt;code&gt;spec.loadBalancerClass&lt;/code&gt;. This is necessary
because &lt;em&gt;dev-install&lt;/em&gt; deploys Octavia by default and &lt;code&gt;cloud-provider-openstack&lt;/code&gt; is using this for load balancing by
default. By setting this, we have the ability to later configure &lt;code&gt;Service&lt;/code&gt;s to use MetalLB rather than Octavia.
Secondly, we are restricting the speakers to run on worker nodes by configuring &lt;code&gt;spec.nodeSelector&lt;/code&gt; as there&amp;rsquo;s simply no
need to run them on the master nodes.&lt;/p&gt;

&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;The choice of &lt;code&gt;metallb.universe.tf/metallb&lt;/code&gt; as the &lt;code&gt;spec.loadBalancerClass&lt;/code&gt; is totally arbitrary. You can use anything
label-like here so long as you use the same value later when creating &lt;code&gt;Service&lt;/code&gt;s.&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;Once the CR is created, we can validate that it exists:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc get -n metallb-system metallb metallb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Assuming so, you can ensure the &lt;code&gt;loadBalancerClass&lt;/code&gt; attribute is in effect by inspecting the underlying service
containers:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc get -n metallb-system pods
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME                                                  READY   STATUS    RESTARTS      AGE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;controller-7df7bbcffb-8cqzb                           1/1     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;             5m1s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;metallb-operator-controller-manager-c44c967b9-l6rvx   1/1     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;             13h
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;metallb-operator-webhook-server-6fdccfb5c5-k8b2m      1/1     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;13h ago&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;   13h
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;speaker-bg6pq                                         4/4     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;             5m1s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;speaker-q6dmg                                         4/4     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;             5m1s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;speaker-sjmtc                                         4/4     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;             5m1s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;speaker-z9zrr                                         4/4     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;             5m1s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc get -n metallb-system pod controller-7df7bbcffb-8cqzb -o jsonpath&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{.spec.containers[0].args}&amp;#34;&lt;/span&gt; | yq -P
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- --port&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7472&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- --log-level&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;info
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- --cert-service-name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;webhook-service
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- --lb-class&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;metallb.universe.tf/metallb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- --webhook-mode&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;disabled
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc get -n metallb-system pod speaker-bg6pq -o jsonpath&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{.spec.containers[0].args}&amp;#34;&lt;/span&gt; | yq -P
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- --port&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7472&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- --log-level&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;info
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- --lb-class&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;metallb.universe.tf/metallb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This all looks good. With this, the initial configuration of MetalLB is also complete. Now to the next step: configuring
MetalLB for our BGP environment.&lt;/p&gt;
&lt;h2 id=&#34;configuring-metallb-to-talk-to-the-router&#34;&gt;Configuring MetalLB to talk to the router&lt;/h2&gt;
&lt;p&gt;MetalLB in BGP mode requires a few bits of information. It needs a list of IP addresses that it can hand out, it needs
information about the routers that it should peer with, and it needs to be told which IP addresses it can advertise via
BGP. This configuration is all done using CRs, namely the &lt;code&gt;IPAddressPool&lt;/code&gt;, &lt;code&gt;BGPPeer&lt;/code&gt;, and &lt;code&gt;BGPAdvertisement&lt;/code&gt; CRs. First
up, the IP address pools.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt; EOF | oc apply -f -
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;apiVersion: metallb.io/v1beta1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;kind: IPAddressPool
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  namespace: metallb-system
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  name: ipaddresspool
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  addresses:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    - 192.168.50.1-192.168.50.254
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve picked a totally arbitrary IP address range, ensuring it doesn&amp;rsquo;t overlap with any other IP address range on the
network. Obviously if you have specific IP addresses you wish to use, you should configure these instead. I&amp;rsquo;ve also only
configured one. This should be loads for our purposes.&lt;/p&gt;
&lt;p&gt;Next, the BGP peers. While we have multiple leaf routers, our master and worker nodes are all talking to the
&lt;code&gt;rack1-gateway&lt;/code&gt; router. As a result, we really only need to create a BGP peer for this router.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt; EOF | oc apply -f -
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;apiVersion: metallb.io/v1beta2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;kind: BGPPeer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  name: rack1-bgp-peer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  namespace: metallb-system
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  myASN: 64998
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  peerASN: 64999
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  peerAddress: 192.168.10.1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  password: &amp;#34;f00barZ&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;poc-bgp&lt;/code&gt; project we used to configure our BGP software router uses the &lt;code&gt;64999&lt;/code&gt; ASN for all of the leaf routers and
configured a password of &lt;code&gt;f00barZ&lt;/code&gt;. Since we&amp;rsquo;re pairing with one of these leaf routers, &lt;code&gt;rack1-gateway&lt;/code&gt;, we needed to
configure these. We chose the &lt;code&gt;64998&lt;/code&gt; ASN for ourselves.&lt;/p&gt;
&lt;p&gt;Finally, the BGP advertisement. Because MetalLB supports both a BGP and an L2 mode, it is possible that you could have
some IP addresses that are meant to be assigned using BGP and other IP addresses that are meant to be assigned using
ARP. In our case, we are only configuring MetalLB in BGP mode and only have a single IP address pool, which means we can
advertise all IPs via BGP.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt; EOF | oc apply -f -
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;apiVersion: metallb.io/v1beta1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;kind: BGPAdvertisement
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  name: bgpadvertisement
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  namespace: metallb-system
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With those three CRs created, we can validate that they have been in fact created.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc get -n metallb-system ipaddresspool
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME            AUTO ASSIGN   AVOID BUGGY IPS   ADDRESSES
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ipaddresspool   true          false             &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;192.168.50.1-192.168.50.254&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc get -n metallb-system bgppeer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME             ADDRESS        ASN     BFD PROFILE   MULTI HOPS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rack1-bgp-peer   192.168.10.1   &lt;span style=&#34;color:#ae81ff&#34;&gt;64999&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc get -n metallb-system bgpadvertisement
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME               IPADDRESSPOOLS   IPADDRESSPOOL SELECTORS   PEERS
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bgpadvertisement
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Wonderful!&lt;/p&gt;
&lt;h2 id=&#34;dealing-with-port-security-issues&#34;&gt;Dealing with port security issues&lt;/h2&gt;
&lt;p&gt;With the above steps completed, our configuration of MetalLB is complete. However, if you were to create a &lt;code&gt;Service&lt;/code&gt;
with &lt;code&gt;type=LoadBalancer&lt;/code&gt; now, you would find it doesn&amp;rsquo;t actually work. This is because Neutron has MAC spoofing
protection that is enabled by default. The fact that our worker node is advertising IP addresses that neutron does not
know about triggers this protection and results in packets getting dropped as they egress our worker node.&lt;/p&gt;
&lt;p&gt;To work around this issue you have two options: you can disable port security, or you make use of neutron&amp;rsquo;s
&lt;code&gt;allowed-address-pairs&lt;/code&gt; extension to allow additional IPs, subnets, and MAC addresses, other than the fixed IP and MAC
address associated with the port, to act as source addresses for traffic leaving the port/virtual interface. Let&amp;rsquo;s
start with the former.&lt;/p&gt;
&lt;h3 id=&#34;disable-port-security&#34;&gt;Disable port security&lt;/h3&gt;
&lt;p&gt;Disabling port security requires removing any existing allowed address pairs, removing any security groups, and finally
disabling port security in general. If you you opt to do this, you will need to do this it for all worker node ports. As
we only only have one worker node here, there is only one port to worry about, but you can trivially script the removal
of port security for a larger number of ports using &lt;em&gt;openstackclient&lt;/em&gt; or something like Ansible. For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ports&lt;span style=&#34;color:#f92672&#34;&gt;=(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    stephenfin-qfnvm-worker-0-97fkv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; port in &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;ports[@]&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    openstack port set --no-allowed-address &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$port&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    openstack port set --no-security-group &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$port&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    openstack port set --disable-port-security &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$port&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;I&amp;rsquo;ve used a static list of ports here. You can find this list of ports by filtering on the &lt;code&gt;openshiftClusterID=foo&lt;/code&gt; tag,
where &lt;code&gt;foo&lt;/code&gt; is the name &lt;code&gt;openshift-installer&lt;/code&gt; (or rather, Terraform) assigned to the cluster. Don&amp;rsquo;t forget to skip the
ingress and API ports!&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;This is definitely the simpler option, though you will obviously be reliant on something else to provide network
security. Let&amp;rsquo;s look at the alternative option.&lt;/p&gt;
&lt;h3 id=&#34;configure-allowed-address-pairs&#34;&gt;Configure allowed address pairs&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;allowed-address-pairs&lt;/code&gt; extension can be used to allow egress traffic from a VM with an IP outside of the one
configured on the neutron port. From the docs:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;allowed-address-pairs&lt;/code&gt; extension adds an &lt;code&gt;allowed_address_pairs&lt;/code&gt;
attribute to ports. The value of &lt;code&gt;allowed_address_pairs&lt;/code&gt; is an array of
allowed address pair objects, each having an &lt;code&gt;ip_address&lt;/code&gt; and a
&lt;code&gt;mac_address&lt;/code&gt;. The set of allowed address pairs defines IP and MAC address
that the port can use when sending packets if &lt;code&gt;port_security_enabled&lt;/code&gt; is
&lt;code&gt;true&lt;/code&gt; (see the &lt;code&gt;port-security&lt;/code&gt; extension). Note that while the
&lt;code&gt;ip_address&lt;/code&gt; is required in each allowed address pair, the &lt;code&gt;mac_address&lt;/code&gt;
is optional and will be taken from the port if not specified.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you inspect the ports assigned to the master and worker nodes, you&amp;rsquo;ll note that we already have some allowed address
pairs defined. OpenShift on OpenStack uses this feature to enable load balancing of the ingress and API VIPs and we can
opt to use it for load balancing of services also. Unfortunately, there is no easy way to create allowed address pairs
for all IP addresses in a given subnet, nor to create them in a manner where they apply to all hosts. As a result,
applying this will be tedious and scalability may well become a concern, particularly where there is a large number of
worker nodes or a large range of IP addresses (via &lt;code&gt;IPAddressPool&lt;/code&gt;). Since we only have one node and will only create
one example, we can at least try it out.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack port set --allowed-address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;ip-address&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.50.1 stephenfin-qfnvm-worker-0-97fkv-0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you wanted to create multiple services, you would need to create an allowed address pair for each and every IP
address specified in the &lt;code&gt;IPAddressPool&lt;/code&gt;(s).&lt;/p&gt;

&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;The upcoming Bobcat release of neutron adds a new &lt;code&gt;allowedaddresspairs-atomic&lt;/code&gt; extension, which provides new
&lt;code&gt;add_allowed_address_pairs&lt;/code&gt; and &lt;code&gt;remove_allowed_address_pairs&lt;/code&gt; member actions. Once released, you could use this to bulk
update the allowed-address-pairs in an atomic manner, which would be helpful if you wanted to write a tool to automate
the configuration of allowed address pairs where there are large numbers of possible IP addresses. You will still have
to specify all possible IP addresses individually, however.&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;This is the more involved option but either option should work. In any case, with port security issues mitigated, we are
finally in a position to validate behavior.&lt;/p&gt;
&lt;h2 id=&#34;testing-it-out&#34;&gt;Testing it out&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s create a simple &amp;ldquo;Hello, world&amp;rdquo; example to test this out. We&amp;rsquo;ll use the &lt;code&gt;e2e-test-images/agnhost&lt;/code&gt; image to do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc new-project test-metallb
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc create deployment hello-node --image&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;k8s.gcr.io/e2e-test-images/agnhost:2.33 -- /agnhost serve-hostname
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ cat  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt; EOF | oc apply -f -
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;apiVersion: v1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;kind: Service
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  name: test-frr
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  selector:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    app: hello-node
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  ports:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;    - port: 80
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;      protocol: TCP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;      targetPort: 9376
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  loadBalancerClass: metallb.universe.tf/metallb
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  type: LoadBalancer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should look very familiar if you&amp;rsquo;ve ever worked with services. In fact, there&amp;rsquo;s nothing unusual here aside from our
use of &lt;code&gt;spec.type=LoadBalancer&lt;/code&gt; and the declaration of &lt;code&gt;spec.loadBalancerClass&lt;/code&gt;. The former ensure we actually use a
load balancer while the latter ensures that the load balancer used is MetalLB rather than Octavia.&lt;/p&gt;
&lt;p&gt;Once created, inspect the service to find the IP address assigned:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ oc get service test-frr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME       TYPE           CLUSTER-IP       EXTERNAL-IP    PORT&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;S&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;        AGE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;test-frr   LoadBalancer   172.30.130.128   192.168.50.1   80:32519/TCP   2m13s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From this, we can see that the service has been assigned IP &lt;code&gt;192.168.50.1&lt;/code&gt;. If we &lt;code&gt;curl&lt;/code&gt; this, we should get something
back. Let&amp;rsquo;s test it out.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ curl 192.168.50.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hello-node-855787d74c-fkbt5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And it works. Good job, people!&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;In this post, we deployed MetalLB via the MetalLB Operator, configured it a minimal manner, and worked around the port
security issues that using an external routing solution with neutron presents. As you can see though, port security
issues aside, the actual process of deploying and configuring MetalLB is rather effortless.&lt;/p&gt;
&lt;p&gt;In a future post, I plan to outline some of the steps I used to debug and resolve issues I had deploying this initial
configuration (there were a few). For now, I hope this was helpful to someone.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Deploying MetalLB with BGP on Openstack (Part 1)</title>
      <link>https://that.guru/blog/deploying-metallb-on-openstack-part-1/</link>
      <pubDate>Mon, 22 May 2023 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/deploying-metallb-on-openstack-part-1/</guid>
      <description>
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;This is part one of two. If you&amp;rsquo;re looking for part two, you can find it
&lt;a href=&#34;https://that.guru/blog/deploying-metallb-on-openstack-part-2&#34;&gt;here&lt;/a&gt;.&lt;/div&gt;
&lt;/aside&gt;

&lt;p&gt;One of the goals for an upcoming OpenShift release is to formally support &lt;a href=&#34;https://metallb.universe.tf/&#34;&gt;MetalLB&lt;/a&gt; and the &lt;a href=&#34;https://github.com/metallb/metallb-operator&#34;&gt;MetalLB
operator&lt;/a&gt; on the OpenStack platform. While MetalLB is mainly targeted at bare metal deployments, it
also has value on some on-prem platforms such as OpenStack; for example, if you can&amp;rsquo;t or don&amp;rsquo;t want to deploy the
OpenStack Load Balancing service (Octavia). I&amp;rsquo;ve been investigating how this would work and this post consists of my
testing notes, along with some asides to help flesh things out. I took a few shortcuts, particularly when it comes to
initial deployment, so I don&amp;rsquo;t know how broadly useful this will be. However, there are very few blogs talking about
MetalLB &lt;strong&gt;in BGP mode&lt;/strong&gt; on OpenStack so I imagine there&amp;rsquo;s &lt;em&gt;something&lt;/em&gt; of use here.&lt;/p&gt;
&lt;p&gt;One thing to note from the get-go is that this focuses on using MetalLB as a load balancer for &lt;strong&gt;applications&lt;/strong&gt; or data
plane - that is, &lt;code&gt;Service&lt;/code&gt; instances with &lt;code&gt;type=LoadBalancer&lt;/code&gt;. Like OpenShift on bare metal, OpenShift on OpenStack uses
&lt;em&gt;keepalived&lt;/em&gt; and &lt;em&gt;HAProxy&lt;/em&gt; to load balance the API and ingress VIPs (which you can see in action by inspecting the pods
in &lt;code&gt;openshift-openstack-infra&lt;/code&gt; namespace). There are no current plans to provide a mechanism for using MetalLB to load
balance the control plane.&lt;/p&gt;
&lt;p&gt;This is the first part of two and focuses on deploying OpenStack, configuring a BGP environment, before deploying an
OpenShift cluster. The end result should look something like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://that.guru/media/deploying-metallb-on-openstack-1.png&#34;
    alt=&#34;Image displaying the network topology of VMs in a deployment&#34;&gt;&lt;figcaption&gt;
      &lt;h4&gt;Our proposed deployment&lt;/h4&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This is likely the most involved section to do from scratch owing to the variety and varying complexity of options
available for configuring OpenStack, BGP, and OpenShift. It is also heavily dependent on the hardware you have available
to you. As a result, you may wish to ignore this part entirely and figure out your own mechanism for getting an
environment that looks like the above.&lt;/p&gt;
&lt;h2 id=&#34;openstack&#34;&gt;OpenStack&lt;/h2&gt;
&lt;p&gt;Before we even start thinking about OpenShift, we need our OpenStack platform to run things on. You may well have an
OpenStack platform already, in which case you can skip this section entirely. Similarly, you may have a preferred
tool or workflow for deploying OpenStack clusters, meaning again you can skip this section entirely and do your own
thing. The important thing is that whatever environment you have must have enough capacity to run 4 small instances for
BGP routing (a flavour with 1GB RAM, 1 vCPU, and 10GB disk will suffice) and 4 much larger instances for OpenShift nodes
(16GB RAM, 4 vCPU and 40GB disk &lt;em&gt;minimum&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;In my case, I was deploying OpenStack from scratch onto a single beefy bare metal machine (A Dell PowerEdge R640 with 2
Intel Xeon Silver 4216 CPUs, 192 GB RAM and 512GB SSD + 2TB HDD). To do so, I used
&lt;a href=&#34;https://github.com/shiftstack/dev-install/&#34;&gt;github.com/shiftstack/dev-install&lt;/a&gt;, an opinionated wrapper around &lt;a href=&#34;https://docs.openstack.org/project-deploy-guide/tripleo-docs/latest/deployment/standalone.html&#34;&gt;TripleO
Standalone&lt;/a&gt; designed for hosting OpenShift clusters, to deploy an OSP 16.2 cloud (OpenStack Train).
&lt;em&gt;dev-install&lt;/em&gt; is available on GitHub:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ git clone https://github.com/shiftstack/dev-install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ cd dev-install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using &lt;em&gt;dev-install&lt;/em&gt; is relatively easy: all it needs is a &lt;code&gt;local_overrides.yaml&lt;/code&gt; file that contains information about
the IP address and hostname of the server, the OSP release you wish to use, and any other overrides necessary. I didn&amp;rsquo;t
need anything special so there were no overrides in my case. This meant my &lt;code&gt;local_overrides.yaml&lt;/code&gt; file looked something
like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;hostname&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;acme&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;public_api&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;10.1.240.35&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;standalone_host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;acme.shiftstack.test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;rhos_release&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;16.2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;clouddomain&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;shiftstack.test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With the &lt;code&gt;local_overrides.yaml&lt;/code&gt; file in place, you can kick off installation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ make config host&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;acme.shiftstack.test
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ make osp_full overrides&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;local_overrides.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Installation should take about 30 minutes and two new entries, &lt;code&gt;standalone&lt;/code&gt; and &lt;code&gt;standalone_openshift&lt;/code&gt;, will be added to
your &lt;code&gt;clouds.yaml&lt;/code&gt; file upon completion.&lt;/p&gt;
&lt;p&gt;Once installation is completed, there is one final step necessary: starting &lt;code&gt;sshuttle&lt;/code&gt;. &lt;em&gt;dev-install&lt;/em&gt; creates a
&lt;code&gt;hostonly&lt;/code&gt; network that is not routable outside the host. As a result, you need something to proxy requests for the
associated &lt;code&gt;hostonly-subnet&lt;/code&gt; subnet to the host and &lt;em&gt;dev-install&lt;/em&gt; opts to use &lt;code&gt;sshuttle&lt;/code&gt; for this. You can start
&lt;code&gt;sshuttle&lt;/code&gt; using the wrapper script provided:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ ./scripts/sshuttle-standalone.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;bgp&#34;&gt;BGP&lt;/h2&gt;
&lt;p&gt;Next, we need to configure a BGP environment. I didn&amp;rsquo;t have access to some ToR switches with BGP support so we
opted to emulate it using &lt;a href=&#34;https://frrouting.org/&#34;&gt;&lt;code&gt;frr&lt;/code&gt;&lt;/a&gt;, a software routing solution. To do this, I used
&lt;a href=&#34;https://github.com/shiftstack/poc-bgp/&#34;&gt;github.com/shiftstack/poc-bgp&lt;/a&gt;, a set of Ansible playbooks which deployed four instances on my new OpenStack
cloud: a spine router instance and three leaf router instances. Once again, there are other software routing solutions
available and you might even have access to real hardware, so if you opt for another approach you could obviously skip
this section (though if you do, you will likely need to modify your MetalLB configuration when we get to that step in
the next post). Assuming you opt to use &lt;code&gt;poc-bgp&lt;/code&gt;, you&amp;rsquo;ll need a CentOS 9 Stream image to exist on the cloud as well as
a key pair so that you can SSH into the instances it creates. You can create the image like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ wget https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-9-20230417.0.x86_64.qcow2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack image create --public --disk-format qcow2 --file CentOS-Stream-GenericCloud-9-20230417.0.x86_64.qcow2 centos9-stream
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Similarly, you can create the key pair like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack keypair create --public-key ~/.ssh/id_ed25519.pub default
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once these resources exists, configuration and deployment is otherwise relatively uncomplex.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;❯ git clone https://github.com/shiftstack/poc-bgp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;❯ cd poc-bgp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;❯ cat &amp;lt;&amp;lt; EOF &amp;gt; localvars.yaml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;cloud_name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;standalone_openshift&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;centos9-stream&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;instance_name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;stephenfin-poc-bgp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;external_network&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;hostonly&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;keypair&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;dns_nameservers&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1.1.1.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;flavor&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;m1.tiny&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;❯ make deploy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once deployed you will end up with 4 instances and 7 networks (6 plus the &lt;code&gt;hostonly&lt;/code&gt; network):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack server list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+--------------------------------------+----------------------------------+--------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------+-----------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| ID                                   | Name                             | Status | Networks                                                                                                                                                                   | Image          | Flavor    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+--------------------------------------+----------------------------------+--------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------+-----------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| a3375961-0821-4135-b064-b884460d11c2 | stephenfin-poc-bgp-spine-gateway | ACTIVE | hostonly&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.25.191, 2001:db8::100; stephenfin-poc-bgp-rack1-patch&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.0.1; stephenfin-poc-bgp-rack2-patch&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.0.5; stephenfin-poc-bgp-rack3-patch&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.0.9 | centos9-stream | m1.tiny   |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| f1e3b324-bf60-440e-808a-3e548f571f1a | stephenfin-poc-bgp-rack1-gateway | ACTIVE | stephenfin-poc-bgp-rack1-leaf&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.10.1; stephenfin-poc-bgp-rack1-patch&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.0.2                                                                                     | centos9-stream | m1.tiny   |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 2b6051cb-f98a-4112-8096-c5c96c56f05a | stephenfin-poc-bgp-rack2-gateway | ACTIVE | stephenfin-poc-bgp-rack2-leaf&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.20.1; stephenfin-poc-bgp-rack2-patch&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.0.6                                                                                     | centos9-stream | m1.tiny   |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 2d14cda5-377a-4383-b6e8-feb50455fad0 | stephenfin-poc-bgp-rack3-gateway | ACTIVE | stephenfin-poc-bgp-rack3-leaf&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.30.1; stephenfin-poc-bgp-rack3-patch&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;192.168.0.10                                                                                    | centos9-stream | m1.tiny   |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+--------------------------------------+----------------------------------+--------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------+-----------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack network list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+--------------------------------------+--------------------------------+----------------------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| ID                                   | Name                           | Subnets                                                                    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+--------------------------------------+--------------------------------+----------------------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 19708577-3757-4956-903e-9656229e1286 | stephenfin-poc-bgp-rack1-leaf  | 6152b856-781b-4fc9-9979-e4cfc9e282b8                                       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 2a28f908-e9ec-4fb5-a4cb-09cd5dae8723 | stephenfin-poc-bgp-rack3-patch | 0f15d6ed-0b8a-435e-90d0-83edb2164100                                       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 2cd308e3-8370-425b-af1c-0ce5562c2b36 | stephenfin-poc-bgp-rack1-patch | f22c9d7e-9c7f-4985-be7c-63eb05014544                                       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 3060e6b0-c2c3-4f59-ac13-9d07a7a963f1 | stephenfin-poc-bgp-rack2-leaf  | 824cfd85-f89b-4a07-a330-3c3adb55b0e3                                       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 538a2436-07c5-48f1-8cd0-39931244bcb7 | stephenfin-poc-bgp-rack3-leaf  | 3109bff8-fdd5-4824-ab2d-58184096e35c                                       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 91efea92-eaf8-4146-ac4c-48d3edfedfe4 | hostonly                       | 607ba284-3762-4667-a2fa-2a7f31de6f35, b147f959-3122-4ad9-aaaa-6ff1af41c8df |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| b15da053-0625-4d33-ad6a-036dd76cfc8d | stephenfin-poc-bgp-rack2-patch | 71a6eeef-2c3d-45e2-80a9-efff6e15a289                                       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+--------------------------------------+--------------------------------+----------------------------------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;spine-gateway&lt;/code&gt; instance is connected to the three &lt;code&gt;rackN-gateway&lt;/code&gt; instances via separate patch networks, while the
three &lt;code&gt;rackN-gateway&lt;/code&gt; instances have their own &lt;code&gt;rackN-leaf&lt;/code&gt; leaf network. We&amp;rsquo;re going to use one of the latter as our
machine subnet when installing OpenShift shortly.&lt;/p&gt;
&lt;p&gt;We have some final steps to do here. First, we need to configure the subnets created by &lt;code&gt;poc-bgp&lt;/code&gt; to keep IP address
&amp;lt; &lt;code&gt;.10&lt;/code&gt; free. This is necessary because we are going to use some of these IP addresses for OpenShift VIPs shortly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack subnet set --no-allocation-pool --allocation-pool &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;start=192.168.10.10,end=192.168.10.239&amp;#34;&lt;/span&gt; stephenfin-poc-bgp-rack1-subnet
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack subnet set --no-allocation-pool --allocation-pool &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;start=192.168.20.10,end=192.168.20.239&amp;#34;&lt;/span&gt; stephenfin-poc-bgp-rack2-subnet
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack subnet set --no-allocation-pool --allocation-pool &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;start=192.168.30.10,end=192.168.30.239&amp;#34;&lt;/span&gt; stephenfin-poc-bgp-rack3-subnet
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In addition, we need another instance of &lt;code&gt;sshuttle&lt;/code&gt; to configure traffic for these new networks to route through the
&lt;code&gt;spine-gateway&lt;/code&gt; host. This will look something like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ sshuttle -r cloud-user@&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;GATEWAY_HOST_IP&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt; 192.168.10.0/24 192.168.20.0/24 192.168.30.0/24
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;where &lt;code&gt;${GATEWAY_HOST_IP}&lt;/code&gt; is the IP of the &lt;code&gt;spine-gateway&lt;/code&gt; host (&lt;code&gt;192.168.25.191&lt;/code&gt; in my case).&lt;/p&gt;
&lt;p&gt;With our BGP routers in place, we can move onto the final stage of set up: installing OpenShift.&lt;/p&gt;
&lt;h2 id=&#34;openshift&#34;&gt;OpenShift&lt;/h2&gt;
&lt;p&gt;The last step of initial set up is installing OpenShift. I used &lt;code&gt;openshift-install&lt;/code&gt; to do this, deploying a 4.12
OpenShift cluster on my OpenStack cloud. When deploying OpenShift, you&amp;rsquo;ll want to pay special attention to the
networking configuration. As noted above, we want to use one of the &lt;code&gt;rackN-leaf&lt;/code&gt; networks and I chose &lt;code&gt;rack1-leaf&lt;/code&gt;
arbitrarily. You should use IPs from whatever subnet you choose for your API and Ingress VIPs, picking address in the
&amp;lt; &lt;code&gt;.10&lt;/code&gt; range we previously set aside. This means you should end up with configuration similar to the following in
your &lt;code&gt;install-config.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;openstack&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;machinesSubnet&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;6152b856-781b-4fc9-9979-e4cfc9e282b8 &lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# stephenfin-poc-bgp-rack1-subnet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;apiVIPs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;192.168.10.5&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# from stephenfin-poc-bgp-rack1-subnet, &amp;lt; .10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ingressVIPs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;192.168.10.7&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# from stephenfin-poc-bgp-rack1-subnet, &amp;lt; .10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;networking&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;clusterNetworks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;cidr&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;10.128.0.0&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;/14&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;hostSubnetLength&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;serviceCIDR&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;172.30.0.0&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;/16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;machineNetwork&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;cidr&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;192.168.10.0&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;/24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;cidr&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;192.168.25.0&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;/24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In addition, assuming you don&amp;rsquo;t have a local DNS server configured, you will need to modify your &lt;code&gt;/etc/hosts&lt;/code&gt; file to
specify the hostnames and corresponding IP addresses of your OpenShift cluster. This is described in the
&lt;a href=&#34;https://github.com/openshift/installer/blob/master/docs/user/openstack/README.md&#34;&gt;OpenShift Installer docs&lt;/a&gt;, but in summary you&amp;rsquo;ll want something like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# openshift shiftstack nodes
192.168.10.5 api.stephenfin.openshift.shiftstack.test
192.168.10.7 console-openshift-console.apps.stephenfin.openshift.shiftstack.test
192.168.10.7 integrated-oauth-server-openshift-authentication.apps.stephenfin.openshift.shiftstack.test
192.168.10.7 oauth-openshift.apps.stephenfin.openshift.shiftstack.test
192.168.10.7 prometheus-k8s-openshift-monitoring.apps.stephenfin.openshift.shiftstack.test
192.168.10.7 grafana-openshift-monitoring.apps.stephenfin.openshift.shiftstack.test
# End of openshift nodes
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You should obviously change the hostnames and IP addresses to match whatever you configured in your
&lt;code&gt;install-config.yaml&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Once you have these steps completed, you can kick of installation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openshift-install --log-level debug create cluster
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Wait for that to complete, at which point you should have a fully functioning OpenShift deployment that you can interact
with using &lt;code&gt;oc&lt;/code&gt; or &lt;code&gt;kubectl&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;In this post, we deployed an OpenStack deployment, configured BGP software routers, and deployed OpenShift on OpenStack.
In the next post, we will work to install MetalLB itself. Stay tuned.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;appendix-configuration-files&#34;&gt;Appendix: Configuration files&lt;/h2&gt;
&lt;p&gt;Here are the full configuration files used for my deployment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;dev-install&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;local-overrides.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;hostname&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;acme&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;public_api&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;10.1.240.35&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;standalone_host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;acme.shiftstack.test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;rhos_release&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;16.2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;clouddomain&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;shiftstack.test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;poc-bgp&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;local_vars.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;cloud_name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;standalone_openshift&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;centos9-stream&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;instance_name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;stephenfin-poc-bgp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;external_network&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;hostonly&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;keypair&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;dns_nameservers&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1.1.1.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;flavor&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;m1.tiny&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;openshift-installer&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;install-config.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;baseDomain&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;openshift.shiftstack.test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;stephenfin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;controlPlane&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;master&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;openstack&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;m1.xlarge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;replicas&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;compute&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;worker&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;openstack&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;m1.xlarge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;replicas&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;platform&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;openstack&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;defaultMachinePlatform&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;m1.xlarge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;clusterOSImage&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rhcos-4.12&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;cloud&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;standalone_openshift&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;machinesSubnet&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;6152b856-781b-4fc9-9979-e4cfc9e282b8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;apiVIPs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;192.168.10.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ingressVIPs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;192.168.10.7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;networking&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;clusterNetworks&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;cidr&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;10.128.0.0&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;/14&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;hostSubnetLength&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;serviceCIDR&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;172.30.0.0&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;/16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;machineNetwork&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;cidr&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;192.168.10.0&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;/24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;cidr&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;192.168.25.0&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;/24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;pullSecret&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;lt;redacted&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>Installing OSC With pipx</title>
      <link>https://that.guru/blog/installing-openstackclient-with-pipx/</link>
      <pubDate>Thu, 27 Apr 2023 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/installing-openstackclient-with-pipx/</guid>
      <description>&lt;p&gt;Another one that really belongs in a separate &lt;em&gt;&amp;ldquo;tips &amp;amp; tricks&amp;rdquo;&lt;/em&gt; section of the blog, which unfortunately does not yet exist. I use &lt;a href=&#34;https://docs.openstack.org/python-openstackclient/latest/&#34;&gt;openstackclient (OSC)&lt;/a&gt;
pretty extensively day-to-day. Fedora provides a relatively up-to-date version of the package, but OSC has been evolving very rapidly of late and Fedora&amp;rsquo;s
packagers just can&amp;rsquo;t be that fast 😁. The solution, therefore, is to install from &lt;code&gt;pip&lt;/code&gt;. Installing things globally, even if that&amp;rsquo;s global to the user, is a bad
idea though: there are too many opportunities for dependency updates to break other packages. I want to use a virtualenv. The obvious solution is to use
&lt;a href=&#34;https://pypa.github.io/pipx/&#34;&gt;&lt;code&gt;pipx&lt;/code&gt;&lt;/a&gt;, which is specifically designed for this use case. From the &lt;a href=&#34;https://pypa.github.io/pipx/&#34;&gt;homepage&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;pipx is a tool to help you install and run end-user applications written in Python. It&amp;rsquo;s roughly similar to macOS&amp;rsquo;s &lt;code&gt;brew&lt;/code&gt;, JavaScript&amp;rsquo;s &lt;code&gt;npx&lt;/code&gt;, and Linux&amp;rsquo;s
&lt;code&gt;apt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s closely related to pip. In fact, it uses pip, but is focused on installing and managing Python packages that can be run from the command line directly as
applications.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;pipx&lt;/code&gt; itself is available in the Fedora repos so if Fedora is you distro of choice then you can install it with &lt;code&gt;dnf&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ sudo dnf install pipx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once that&amp;rsquo;s in place, you can install OSC with &lt;code&gt;pipx&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ pipx install python-openstackclient
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unlike &lt;code&gt;openstacksdk&lt;/code&gt;, however, the &lt;code&gt;python-openstackclient&lt;/code&gt; package doesn&amp;rsquo;t provide support for OpenStack services beyond the core ones: Identity (keystone),
Compute (nova), Image (glance), Block Storage (cinder), Network (neutron) and Object Storage (swift). For services like the Share Filesystem-as-a-Service
(manila), Load Balancer-as-a-Service (octavia) or Placement service, you need to install additional packages (&lt;code&gt;python-manilaclient&lt;/code&gt;, &lt;code&gt;python-octaviaclient&lt;/code&gt;, and
&lt;code&gt;osc-placement&lt;/code&gt;, respectively).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ openstack loadbalancer list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;openstack: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;loadbalancer list&amp;#39;&lt;/span&gt; is not an openstack command. See &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;openstack --help&amp;#39;&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Did you mean one of these?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  container create
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  container delete
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  container list
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  container save
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  container set
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  container show
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  container unset
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It took me a beat to figure out but &lt;code&gt;pipx&lt;/code&gt; provides an easy mechanism to do this: the &lt;code&gt;inject&lt;/code&gt; command. For example, to install &lt;code&gt;python-octaviaclient&lt;/code&gt; in the
same virtualenv, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ pipx inject python-openstackclient python-octaviaclient
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can repeat this for additional dependencies:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ pipx inject python-openstackclient osc-placement python-neutronclient python-manilaclient python-ironicclient python-barbicanclient python-designateclient
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ pipx list --include-injected
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;venvs are in /home/stephenfin/.local/pipx/venvs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apps are exposed on your $PATH at /home/stephenfin/.local/bin
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   package python-openstackclient 6.2.0, installed using Python 3.11.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - openstack
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Injected Packages:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - osc-placement 4.1.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - python-barbicanclient 5.5.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - python-designateclient 5.2.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - python-ironicclient 5.1.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - python-manilaclient 4.3.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - python-neutronclient 9.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - python-octaviaclient 3.4.0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With that done, you should have access to &lt;em&gt;all&lt;/em&gt; the commands. 💪&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Playing with OpenStack Nova APIs from a Python Shell</title>
      <link>https://that.guru/blog/interacting-with-nova-from-a-python-shell/</link>
      <pubDate>Wed, 22 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/interacting-with-nova-from-a-python-shell/</guid>
      <description>&lt;p&gt;A quick hack. If you want to call various OpenStack Nova APIs outside the context of a service like &lt;code&gt;nova-compute&lt;/code&gt;, there&amp;rsquo;s a good chance you&amp;rsquo;ll need some
configuration. If you have deployment, you&amp;rsquo;ll likely have a configuration file with all the necessary details. DevStack places its Nova configuration files at
&lt;code&gt;/etc/nova&lt;/code&gt;. Nova provides APIs, which are tiny wrappers around oslo.db functionality, for loading these.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; nova.conf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; nova &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; config
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; config&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;parse_args(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;foo --config-file /etc/nova/nova.conf&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;split())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; CONF &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; nova&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;conf&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;CONF
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With you configuration, you can now do things that require this configuration. For example, let&amp;rsquo;s look at our databases using SQLAlchemy.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from nova.db.main import api
&amp;gt;&amp;gt;&amp;gt; engine = api.get_engine()
&amp;gt;&amp;gt;&amp;gt; import sqlalchemy
&amp;gt;&amp;gt;&amp;gt; sqlalchemy.inspect(engine).has_table(&amp;#39;alembic_version&amp;#39;)
True
&amp;gt;&amp;gt;&amp;gt; sqlalchemy.inspect(engine).has_table(&amp;#39;migrate_version&amp;#39;)
False
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This can be handy to get you out of a hole, or to hack on stuff in a development environment.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Hello, Gophercloud</title>
      <link>https://that.guru/blog/gophercloud-hello-world/</link>
      <pubDate>Thu, 16 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/gophercloud-hello-world/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been playing around with &lt;a href=&#34;https://github.com/gophercloud/gophercloud&#34;&gt;Gophercloud&lt;/a&gt; over the past few days. While it&amp;rsquo;s nowhere near as complete as
&lt;a href=&#34;https://opendev.org/openstack/openstacksdk&#34;&gt;openstacksdk&lt;/a&gt; (which, coincidentally, recently hit the big &lt;a href=&#34;https://pypi.org/project/openstacksdk/1.0.0&#34;&gt;1.0.0 milestone&lt;/a&gt; 🎉) or
legacy Python-based service clients yet, it is clearly a great tool to have in your arsenal and is the library
underlying the &lt;a href=&#34;https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs&#34;&gt;Terraform OpenStack Provider&lt;/a&gt;, OpenStack platform support in
&lt;a href=&#34;https://github.com/openshift/installer&#34;&gt;openshift-install&lt;/a&gt;, and various OpenStack-specific Kubernetes components, among others.&lt;/p&gt;
&lt;p&gt;In the interests of easing ramp-up for anyone else trying to get started with &lt;em&gt;Gophercloud&lt;/em&gt;, here&amp;rsquo;s an simple &amp;ldquo;hello,
world&amp;rdquo; example - listing servers - using both &lt;em&gt;Gophercloud&lt;/em&gt; and &lt;em&gt;openstacksdk&lt;/em&gt;.&lt;/p&gt;

&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;Updated on 2025-06-11 to update examples for Gophercloud v2.&lt;/div&gt;
&lt;/aside&gt;

&lt;h2 id=&#34;gophercloud-go&#34;&gt;Gophercloud (Go)&lt;/h2&gt;
&lt;p&gt;Create a new directory containing a single file, &lt;code&gt;main.go&lt;/code&gt;, and add the following to it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;context&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/gophercloud/utils/v2/openstack/clientconfig&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;opts&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; new(&lt;span style=&#34;color:#a6e22e&#34;&gt;clientconfig&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ClientOpts&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// We could configure the cloud manually but we don&amp;#39;t. Instead we&amp;#39;ll leave it unset causing gophercloud to load the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// cloud from the &amp;#39;OS_CLOUD&amp;#39; environment variable. We could also simplify this further and pass &amp;#39;nil&amp;#39; below instead&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// of generating and passing a &amp;#39;ClientOpts&amp;#39; object but this shows how you _could_ configure things if you so chose.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// opts.Cloud = &amp;#34;devstack-admin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;client&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clientconfig&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewServiceClient&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;TODO&lt;/span&gt;(), &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;compute&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;opts&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;pager&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;servers&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;List&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;client&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;AllPages&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;TODO&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;servers&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;servers&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ExtractServers&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;pager&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;servers:&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;servers&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;  server %d: id=%s\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ID&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now generate the &lt;code&gt;go.mod&lt;/code&gt; file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ go mod init gophercloud-hello-world
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ go mod tidy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, you can run the command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ export OS_CLOUD&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;devstack-admin  &lt;span style=&#34;color:#75715e&#34;&gt;# or another entry from your local &amp;#39;clouds.yaml&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ go run .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should dump something like the following.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;servers:
  server 0: id=395b60b4-73be-4ba4-a8a8-fdaa3fce57d5
&lt;/code&gt;&lt;/pre&gt;
&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;&lt;p&gt;This example also makes use of the &lt;a href=&#34;https://github.com/gophercloud/utils&#34;&gt;gophercloud/utils&lt;/a&gt; library, to simplify authentication and the
creation of clients. &lt;em&gt;gophercloud&lt;/em&gt; itself also provides support for &lt;code&gt;clouds.yaml&lt;/code&gt; files, but its slightly more verbose.
If you wanted to skip &lt;code&gt;utils&lt;/code&gt;, you could rewrite this like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;context&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/gophercloud/gophercloud/v2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/gophercloud/gophercloud/v2/openstack&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/gophercloud/gophercloud/v2/openstack/config&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/gophercloud/gophercloud/v2/openstack/config/clouds&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;TODO&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;ao&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;eo&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;tlsConfig&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clouds&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Parse&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;providerClient&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewProviderClient&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ao&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WithTLSConfig&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;tlsConfig&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;client&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;openstack&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewComputeV2&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;providerClient&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;eo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// rest of code here ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/aside&gt;


&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;&lt;p&gt;If you are working on Gophercloud itself, it can be helpful to use scripts like this to test your changes.
If doing this, you can rely on the &lt;code&gt;replace&lt;/code&gt; directive in &lt;code&gt;go.mod&lt;/code&gt; to ensure your local clone of Gophercloud is used.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;replace&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;github&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gophercloud&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gophercloud&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;v2&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;home&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;user&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gophercloud&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;github&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gophercloud&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;utils&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;v2&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;home&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;user&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;utils&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;More information &lt;a href=&#34;https://thewebivore.com/using-replace-in-go-mod-to-point-to-your-local-module/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;

&lt;h2 id=&#34;openstacksdk-python&#34;&gt;openstacksdk (Python)&lt;/h2&gt;
&lt;p&gt;Create a new directory containing a single file, &lt;code&gt;main.py&lt;/code&gt;, and add the following to it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; openstack
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# We could configure the cloud manually but we don&amp;#39;t. Instead we&amp;#39;ll leave it unset causing openstacksdk to load the&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# cloud from the &amp;#39;OS_CLOUD&amp;#39; environment variable.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# conn = openstack.connect(cloud=&amp;#39;devstack-admin&amp;#39;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    conn &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; openstack&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;connect()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    servers &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; conn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;compute&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;servers()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;servers:&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i, server &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; enumerate(servers):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        print(&lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;  server &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;i&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;: id=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;server&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;id&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; __name__ &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    main()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now create a virtual environment and install the dependencies.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ virtualenv .venv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ source .venv/bin/activate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ pip install openstacksdk
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, you can run the command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ export OS_CLOUD&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;devstack-admin  &lt;span style=&#34;color:#75715e&#34;&gt;# or another entry from your local &amp;#39;clouds.yaml&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;❯ python main.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This should dump identical output to the Go-based script.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;servers:
  server 0: id=395b60b4-73be-4ba4-a8a8-fdaa3fce57d5
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    
    <item>
      <title>API Versioning in Openstack</title>
      <link>https://that.guru/blog/api-versioning-in-openstack/</link>
      <pubDate>Fri, 03 Feb 2023 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/blog/api-versioning-in-openstack/</guid>
      <description>&lt;p&gt;The API versioning schemes in use in OpenStack vary between services and have evolved since the early days of OpenStack.
There are two types of API versioning to consider: the &lt;em&gt;major&lt;/em&gt; version and the &lt;em&gt;minor&lt;/em&gt; version. Today, most OpenStack
services have settled on a single &lt;em&gt;major&lt;/em&gt; API version and have chosen to evolve the API without bumping the &lt;em&gt;major&lt;/em&gt; API
version any further. There are three API &lt;em&gt;minor&lt;/em&gt; versioning schemes in common use.&lt;/p&gt;

&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;This post is based on changes I recently made to the &lt;em&gt;python-openstackclient&lt;/em&gt; documentation, which you can find
&lt;a href=&#34;https://docs.openstack.org/python-openstackclient/latest/contributor/humaninterfaceguide#api-versioning&#34;&gt;here&lt;/a&gt;. I&amp;rsquo;m
duplicating it here in the hopes that it&amp;rsquo;ll be more discoverable.&lt;/div&gt;
&lt;/aside&gt;


&lt;aside class=&#34;admonition note&#34;&gt;
  &lt;div class=&#34;admonition-content&#34;&gt;Updated on 2025-06-11 to better describe the API versioning policies of Glance and Keystone.&lt;/div&gt;
&lt;/aside&gt;

&lt;h2 id=&#34;per-release-versions&#34;&gt;Per-release versions&lt;/h2&gt;
&lt;p&gt;This is used by the Image service (glance) and DNS service (designate). All changes to the API during a given release
cycle are gathered into a single new API version. As such, the API version will increase at most once per release.
You can continue to request older versions.&lt;/p&gt;
&lt;p&gt;For example, consider the Image (glance) API.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Release&lt;/th&gt;
          &lt;th&gt;Supported 2.x API versions&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Grizzly&lt;/td&gt;
          &lt;td&gt;2.0 - 2.1&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Havana&lt;/td&gt;
          &lt;td&gt;2.0 - 2.2&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Kilo&lt;/td&gt;
          &lt;td&gt;2.0 - 2.3&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&amp;hellip;&lt;/td&gt;
          &lt;td&gt;&amp;hellip;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In theory, this means the API is purely additive and the new version can be used as a signal that an API addition is
available. Glance takes this a step further and includes or excludes API versions depending on whether an optional
feature is enabled or not.&lt;/p&gt;
&lt;h2 id=&#34;single-version&#34;&gt;Single version&lt;/h2&gt;
&lt;p&gt;This is used by the Identity service (keystone). It is similar to the per-release versions but unlike those, only a
single API version is exposed. Like those, however, this version can be used as signal that a feature is available.
Once again, this API schema is really intended to be purely additive, since there&amp;rsquo;s no way to opt into old behavior.
Keystone, for example, has never removed APIs or made non-additive changes like changing the type of a field or removing
it.&lt;/p&gt;
&lt;h2 id=&#34;microversions&#34;&gt;Microversions&lt;/h2&gt;
&lt;p&gt;This is used by multiple services including the Compute service (nova), Block Storage service (cinder), and Shared
Filesystem service (manila). Each change to the API will result in a new API version. As such, the API version can
increase multiple times per release. You can continue to request older versions.&lt;/p&gt;
&lt;p&gt;For example, consider the Compute (nova) API.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Release&lt;/th&gt;
          &lt;th&gt;Supported 2.x API versions&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Kilo&lt;/td&gt;
          &lt;td&gt;2.1 - 2.3&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Liberty&lt;/td&gt;
          &lt;td&gt;2.1 - 2.12&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Mitaka&lt;/td&gt;
          &lt;td&gt;2.1 - 2.25&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&amp;hellip;&lt;/td&gt;
          &lt;td&gt;&amp;hellip;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Unlike the previous examples, this API versioning schema allows for practically any change, including changing the type
of a field, adding and removing new fields, and adding or removing new APIS. If you want the old behavior, you simply
request an older microversion.&lt;/p&gt;
&lt;h2 id=&#34;extensions&#34;&gt;Extensions&lt;/h2&gt;
&lt;p&gt;This is used by the Networking service (neutron). It&amp;rsquo;s a versioning scheme that doesn&amp;rsquo;t use API versions. Instead, it
exposes a list of available extensions. An extension can add, remove or modify features and vendor-specific
functionality to the API. This can include API resources/routes as well as new fields in API requests and responses. If
you want to depend on a feature added by an extension, you should check if the extension is present.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Zero-Downtime Upgrades With SQLAlchemy and Alembic</title>
      <link>https://that.guru/talks/zero-downtime-upgrades-with-alembic-and-sqlalchemy/</link>
      <pubDate>Sun, 13 Nov 2022 00:00:00 +0000</pubDate>
      
      <guid>https://that.guru/talks/zero-downtime-upgrades-with-alembic-and-sqlalchemy/</guid>
      <description>&lt;p&gt;This talk was delivered at &lt;a href=&#34;https://python.ie/pycon-2022/schedule/&#34;&gt;PyCon Ireland 2022&lt;/a&gt;. As the name would suggest,
I aimed to describe how to implement a database upgrade pattern using
SQLAlchemy + Alembic that would allow you to evolve you database schema without
incurring downtime.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Alembic is a database migrations tool written by the author of SQLAlchemy.
Alembic is easy to get started with an provides a number of sensible defaults
out-of-the-box. However, like SQLAlchemy itself, when you look under the hood
you find a seriously capable engine capable of powering all sorts of database
schema migrations. It can even auto-generate the migration files themselves!&lt;/p&gt;
&lt;p&gt;In this presentation, we seek to explore some of these advanced features by
implementing a pattern - the expand-contract pattern - that can allow for near
zero-downtime database upgrades.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;More information is available on the &lt;a href=&#34;https://python.ie/pycon-2022/schedule/&#34;&gt;Python Ireland&lt;/a&gt; website.&lt;/p&gt;

&lt;script async class=&#34;speakerdeck-embed&#34; data-id=&#34;1114ae54fe09427c98a6cff38c9041f8&#34; data-ratio=&#34;1.77777777777778&#34; src=&#34;//speakerdeck.com/assets/embed.js&#34;&gt;&lt;/script&gt;


</description>
    </item>
    
  </channel>
</rss>
