<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Operator SDK – Ansible</title>
    <link>/docs/building-operators/ansible/</link>
    <description>Recent content in Ansible on Operator SDK</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    
	  <atom:link href="/docs/building-operators/ansible/index.xml" rel="self" type="application/rss+xml" />
    
    
      
        
      
    
    
    <item>
      <title>Docs: Installation Guide</title>
      <link>/docs/building-operators/ansible/installation/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/ansible/installation/</guid>
      <description>
        
        
        &lt;h2 id=&#34;install-operator-sdk&#34;&gt;Install &lt;code&gt;operator-sdk&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Follow the steps in the &lt;a href=&#34;/docs/installation/&#34;&gt;installation guide&lt;/a&gt; to learn how to install the &lt;code&gt;operator-sdk&lt;/code&gt; CLI tool.&lt;/p&gt;
&lt;h2 id=&#34;additional-prerequisites&#34;&gt;Additional Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/install/&#34;&gt;docker&lt;/a&gt; version 17.03+&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.python.org/downloads/&#34;&gt;python&lt;/a&gt; version 3.8.6+&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.ansible.com/ansible/latest/index.html&#34;&gt;ansible&lt;/a&gt; version v2.9.0+&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://ansible-runner.readthedocs.io/en/latest/install.html&#34;&gt;ansible-runner&lt;/a&gt; version 2.0.2+&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ansible/ansible-runner-http&#34;&gt;ansible-runner-http&lt;/a&gt; version v1.0.0+&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://pypi.org/project/openshift/&#34;&gt;openshift&lt;/a&gt; version v0.12.0+&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kubernetes.io/docs/tasks/tools/install-kubectl/&#34;&gt;kubectl&lt;/a&gt; and access to a Kubernetes cluster of a &lt;a href=&#34;/docs/overview#kubernetes-version-compatibility&#34;&gt;compatible version&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Quickstart for Ansible-based Operators</title>
      <link>/docs/building-operators/ansible/quickstart/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/ansible/quickstart/</guid>
      <description>
        
        
        &lt;p&gt;This guide walks through an example of building a simple memcached-operator powered by &lt;a href=&#34;https://www.ansible.com/&#34;&gt;Ansible&lt;/a&gt; using tools and libraries provided by the Operator SDK.&lt;/p&gt;
&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Go through the &lt;a href=&#34;/docs/building-operators/ansible/installation&#34;&gt;installation guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make sure your user is authorized with &lt;code&gt;cluster-admin&lt;/code&gt; permissions.&lt;/li&gt;
&lt;li&gt;Have an accessible image registry for various operator images (ex. &lt;a href=&#34;https://hub.docker.com/signup&#34;&gt;hub.docker.com&lt;/a&gt;,
&lt;a href=&#34;https://quay.io/&#34;&gt;quay.io&lt;/a&gt;) and be logged in to your command line environment.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;example.com&lt;/code&gt; is used as the registry Docker Hub namespace in these examples.
Replace it with another value if using a different registry or namespace.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/docs/olm-integration/cli-overview#private-bundle-and-catalog-image-registries&#34;&gt;Authentication and certificates&lt;/a&gt; if the registry is private or uses a custom CA.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;steps&#34;&gt;Steps&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Create a project directory for your project and initialize the project:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;mkdir memcached-operator
&lt;span style=&#34;color:#204a87&#34;&gt;cd&lt;/span&gt; memcached-operator
operator-sdk init --domain example.com --plugins ansible
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Create a simple Memcached API:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk create api --group cache --version v1alpha1 --kind Memcached --generate-role
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Build and push your operator&amp;rsquo;s image:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make docker-build docker-push &lt;span style=&#34;color:#000&#34;&gt;IMG&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;example.com/memcached-operator:v0.0.1&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;olm-deployment&#34;&gt;OLM deployment&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Install &lt;a href=&#34;/docs/olm-integration/tutorial-bundle/#enabling-olm&#34;&gt;OLM&lt;/a&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk olm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Bundle your operator, then build and push the bundle image (defaults to &lt;code&gt;example.com/memcached-operator-bundle:v0.0.1&lt;/code&gt;):&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make bundle &lt;span style=&#34;color:#000&#34;&gt;IMG&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;example.com/memcached-operator:v0.0.1&amp;#34;&lt;/span&gt;
make bundle-build bundle-push
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Run your bundle. If your bundle image is hosted in a registry that is private and/or
has a custom CA, these &lt;a href=&#34;/docs/olm-integration/cli-overview#private-bundle-and-catalog-image-registries&#34;&gt;configuration steps&lt;/a&gt; must be complete.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk run bundle example.com/memcached-operator-bundle:v0.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Create a sample Memcached custom resource:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
memcached.cache.example.com/memcached-sample created
&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;
&lt;li&gt;Uninstall the operator:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk cleanup memcached-operator
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;direct-deployment&#34;&gt;Direct deployment&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Deploy your operator:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make deploy &lt;span style=&#34;color:#000&#34;&gt;IMG&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;example.com/memcached-operator:v0.0.1&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Create a sample Memcached custom resource:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
memcached.cache.example.com/memcached-sample created
&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;
&lt;li&gt;Uninstall the operator:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make undeploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;next-steps&#34;&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;Read the &lt;a href=&#34;/docs/building-operators/ansible/tutorial/&#34;&gt;full tutorial&lt;/a&gt; for an in-depth walkthrough of building an Ansible operator.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Ansible Operator Tutorial</title>
      <link>/docs/building-operators/ansible/tutorial/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/ansible/tutorial/</guid>
      <description>
        
        
        &lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If your project was created with an &lt;code&gt;operator-sdk&lt;/code&gt; version prior to &lt;code&gt;v1.0.0&lt;/code&gt;
please &lt;a href=&#34;/docs/building-operators/ansible/migration&#34;&gt;migrate&lt;/a&gt;, or consult the &lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/v0.19.x/website/content/en/docs/ansible/quickstart.md&#34;&gt;legacy docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Go through the &lt;a href=&#34;/docs/building-operators/ansible/installation&#34;&gt;installation guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make sure your user is authorized with &lt;code&gt;cluster-admin&lt;/code&gt; permissions.&lt;/li&gt;
&lt;li&gt;An accessible image registry for various operator images (ex. &lt;a href=&#34;https://hub.docker.com/signup&#34;&gt;hub.docker.com&lt;/a&gt;,
&lt;a href=&#34;https://quay.io/&#34;&gt;quay.io&lt;/a&gt;) and be logged in to your command line environment.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;example.com&lt;/code&gt; is used as the registry Docker Hub namespace in these examples.
Replace it with another value if using a different registry or namespace.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/docs/olm-integration/cli-overview#private-bundle-and-catalog-image-registries&#34;&gt;Authentication and certificates&lt;/a&gt; if the registry is private or uses a custom CA.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;We will create a sample project to let you know how it works and this sample will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a Memcached Deployment if it doesn&amp;rsquo;t exist&lt;/li&gt;
&lt;li&gt;Ensure that the Deployment size is the same as specified by the Memcached CR spec&lt;/li&gt;
&lt;li&gt;Update the Memcached CR status using the status writer with the names of the CR&amp;rsquo;s pods&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;create-a-new-project&#34;&gt;Create a new project&lt;/h2&gt;
&lt;p&gt;Use the CLI to create a new memcached-operator project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;mkdir memcached-operator
&lt;span style=&#34;color:#204a87&#34;&gt;cd&lt;/span&gt; memcached-operator
operator-sdk init --plugins&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;ansible --domain example.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Among the files generated by this command is a Kubebuilder &lt;code&gt;PROJECT&lt;/code&gt;
file. Subsequent &lt;code&gt;operator-sdk&lt;/code&gt; commands (and help text) run from the
project root read this file and are aware that the project type is
Ansible.&lt;/p&gt;
&lt;p&gt;Next, we will create a &lt;code&gt;Memcached&lt;/code&gt; API.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk create api --group cache --version v1alpha1 --kind Memcached --generate-role
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The scaffolded operator has the following structure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Memcached&lt;/code&gt; Custom Resource Definition, and a sample &lt;code&gt;Memcached&lt;/code&gt; resource.&lt;/li&gt;
&lt;li&gt;A &amp;ldquo;Manager&amp;rdquo; that reconciles the state of the cluster to the desired state
&lt;ul&gt;
&lt;li&gt;A reconciler, which is an Ansible Role or Playbook.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;watches.yaml&lt;/code&gt; file, which connects the &lt;code&gt;Memcached&lt;/code&gt; resource to the &lt;code&gt;memcached&lt;/code&gt; Ansible Role.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&#34;/docs/building-operators/ansible/reference/scaffolding&#34;&gt;scaffolded files reference&lt;/a&gt; and &lt;a href=&#34;/docs/building-operators/ansible/reference/watches&#34;&gt;watches reference&lt;/a&gt; for more detailed information.&lt;/p&gt;
&lt;h3 id=&#34;modify-the-manager&#34;&gt;Modify the Manager&lt;/h3&gt;
&lt;p&gt;Now we need to provide the reconcile logic, in the form of an Ansible
Role, which will run every time a &lt;code&gt;Memcached&lt;/code&gt; resource is created,
updated, or deleted.&lt;/p&gt;
&lt;p&gt;Update &lt;code&gt;roles/memcached/tasks/main.yml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;start&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kubernetes.core.k8s&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;definition&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Deployment&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;apiVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;apps/v1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;{{ ansible_operator_meta.name }}-memcached&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;namespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;{{ ansible_operator_meta.namespace }}&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;replicas&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;{{size}}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;selector&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;          &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;matchLabels&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;            &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;app&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;template&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;          &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;            &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;labels&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;              &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;app&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;          &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;            &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;containers&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;            &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;              &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;command&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;              &lt;/span&gt;- memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;              &lt;/span&gt;- -m=&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;64&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;              &lt;/span&gt;- -o&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;              &lt;/span&gt;- modern&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;              &lt;/span&gt;- -v&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;              &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;docker.io/memcached:1.4.36-alpine&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;              &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;                &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;containerPort&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;11211&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This memcached role will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure a memcached Deployment exists&lt;/li&gt;
&lt;li&gt;Set the Deployment size&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that the tasks in this Ansible role file are what actually defines the behavior of the spec and status of the memcached custom resource.
As Kubernetes allows entry of arbitrary fields when creating resources, we don&amp;rsquo;t need to actually create specific fields in the CRD.
While we won&amp;rsquo;t be doing this in this tutorial, it is recommended to also define these fields in the CRD, so that Kubernetes users
can see the fields that will be used when using the custom resource.
It is also good practice to set default values for variables used in Ansible
Roles, so edit &lt;code&gt;roles/memcached/defaults/main.yml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;# defaults file for Memcached&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;size&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, update the &lt;code&gt;Memcached&lt;/code&gt; sample, &lt;code&gt;config/samples/cache_v1alpha1_memcached.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#204a87;font-weight:bold&#34;&gt;apiVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;cache.example.com/v1alpha1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached-sample&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;size&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The key-value pairs in the Custom Resource spec are passed
to Ansible as extra variables.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The names of all variables in the spec field are converted to
snake_case by the operator before running Ansible. For example,
serviceAccount in the spec becomes service_account in Ansible. You can
disable this case conversion by setting the &lt;code&gt;snakeCaseParameters&lt;/code&gt; option
to &lt;code&gt;false&lt;/code&gt; in your &lt;code&gt;watches.yaml&lt;/code&gt;. It is recommended that you perform some
type validation in Ansible on the variables to ensure that your
application is receiving the expected input.&lt;/p&gt;
&lt;h2 id=&#34;configure-the-operators-image-registry&#34;&gt;Configure the operator&amp;rsquo;s image registry&lt;/h2&gt;
&lt;p&gt;All that remains is to build and push the operator image to the desired image registry.
Your Makefile composes image tags either from values written at project initialization or from the CLI.
In particular, &lt;code&gt;IMAGE_TAG_BASE&lt;/code&gt; lets you define a common image registry, namespace, and partial name
for all your image tags. Update this to another registry and/or namespace if the current value is incorrect.
Afterwards you can update the &lt;code&gt;IMG&lt;/code&gt; variable definition like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;color:#a40000&#34;&gt;-IMG ?= controller:latest
&lt;/span&gt;&lt;span style=&#34;color:#a40000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#00a000&#34;&gt;+IMG ?= $(IMAGE_TAG_BASE):$(VERSION)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once done, you do not have to set &lt;code&gt;IMG&lt;/code&gt; or any other image variable in the CLI. The following command will
build and push an operator image tagged as &lt;code&gt;example.com/memcached-operator:v0.0.1&lt;/code&gt; to Docker Hub:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;make docker-build docker-push
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;run-the-operator&#34;&gt;Run the Operator&lt;/h2&gt;
&lt;p&gt;There are three ways to run the operator:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As a Go program outside a cluster&lt;/li&gt;
&lt;li&gt;As a Deployment inside a Kubernetes cluster&lt;/li&gt;
&lt;li&gt;Managed by the &lt;a href=&#34;/docs/olm-integration/tutorial-bundle/#enabling-olm&#34;&gt;Operator Lifecycle Manager (OLM)&lt;/a&gt; in &lt;a href=&#34;/docs/olm-integration/tutorial-bundle&#34;&gt;bundle&lt;/a&gt; format&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;1-run-locally-outside-the-cluster&#34;&gt;1. Run locally outside the cluster&lt;/h3&gt;
&lt;p&gt;Execute the following command, which installs your CRDs and runs the manager locally:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make install run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;2-run-as-a-deployment-inside-the-cluster&#34;&gt;2. Run as a Deployment inside the cluster&lt;/h3&gt;
&lt;p&gt;By default, a new namespace is created with name &lt;code&gt;&amp;lt;project-name&amp;gt;-system&lt;/code&gt;, ex. &lt;code&gt;memcached-operator-system&lt;/code&gt;, and will be used for the deployment.&lt;/p&gt;
&lt;p&gt;Commonly, Operator authors may need to modify &lt;code&gt;config/rbac&lt;/code&gt; in order to
give their Operator the necessary permissions to reconcile.&lt;/p&gt;
&lt;p&gt;Run the following to customize the manifests and deploy the operator.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make deploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The scaffolded &lt;code&gt;Makefile&lt;/code&gt; uses &lt;a href=&#34;https://kustomize.io/&#34;&gt;&lt;code&gt;kustomize&lt;/code&gt;&lt;/a&gt; to apply custom
configurations and generate manifests from the &lt;code&gt;config/&lt;/code&gt; directory, which are
piped to &lt;code&gt;kubectl&lt;/code&gt;. Run the following command to see the manifests that were
applied to the cluster.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kustomize build config/default
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Verify that the memcached-operator is up and running:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get deployment -n memcached-operator-system
NAME                                    READY   UP-TO-DATE   AVAILABLE   AGE
memcached-operator-controller-manager   1/1     1            1           8m
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;3-deploy-your-operator-with-olm&#34;&gt;3. Deploy your Operator with OLM&lt;/h3&gt;
&lt;p&gt;First, install &lt;a href=&#34;/docs/olm-integration/tutorial-bundle/#enabling-olm&#34;&gt;OLM&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk olm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Bundle your operator, then build and push the bundle image. The &lt;code&gt;bundle&lt;/code&gt; target generates a &lt;a href=&#34;https://github.com/operator-framework/operator-registry/blob/v1.16.1/docs/design/operator-bundle.md#operator-bundle&#34;&gt;bundle&lt;/a&gt;
in the &lt;code&gt;bundle&lt;/code&gt; directory containing manifests and metadata defining your operator.
&lt;code&gt;bundle-build&lt;/code&gt; and &lt;code&gt;bundle-push&lt;/code&gt; build and push a bundle image defined by &lt;code&gt;bundle.Dockerfile&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make bundle bundle-build bundle-push
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, run your bundle. If your bundle image is hosted in a registry that is private and/or
has a custom CA, these &lt;a href=&#34;/docs/olm-integration/cli-overview#private-bundle-and-catalog-image-registries&#34;&gt;configuration steps&lt;/a&gt; must be complete.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk run bundle example.com/memcached-operator-bundle:v0.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Check out the &lt;a href=&#34;/docs/olm-integration/tutorial-bundle&#34;&gt;docs&lt;/a&gt; for a deep dive into &lt;code&gt;operator-sdk&lt;/code&gt;&#39;s OLM integration.&lt;/p&gt;
&lt;h2 id=&#34;create-a-memcached-cr&#34;&gt;Create a Memcached CR&lt;/h2&gt;
&lt;p&gt;Update the sample Memcached CR manifest at &lt;code&gt;config/samples/cache_v1alpha1_memcached.yaml&lt;/code&gt; and define the &lt;code&gt;spec&lt;/code&gt; as the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#204a87;font-weight:bold&#34;&gt;apiVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;cache.example.com/v1alpha1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached-sample&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;size&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Create the CR:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ensure that the memcached operator creates the deployment for the sample CR with the correct size:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get deployment
NAME                                    READY   UP-TO-DATE   AVAILABLE   AGE
memcached-sample                        3/3     3            3           1m
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Check the pods and CR status to confirm the status is updated with the memcached pod names:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get pods
NAME                                  READY     STATUS    RESTARTS   AGE
memcached-sample-6fd7c98d8-7dqdr      1/1       Running   0          1m
memcached-sample-6fd7c98d8-g5k7v      1/1       Running   0          1m
memcached-sample-6fd7c98d8-m7vn7      1/1       Running   0          1m
&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get memcached/memcached-sample -o yaml
apiVersion: cache.example.com/v1alpha1
kind: Memcached
metadata:
  creationTimestamp: &amp;quot;2021-03-17T19:54:42Z&amp;quot;
  generation: 1
  managedFields:
  - apiVersion: cache.example.com/v1alpha1
    fieldsType: FieldsV1
    fieldsV1:
      f:status:
        .: {}
        f:conditions: {}
    manager: ansible-operator
    operation: Update
    time: &amp;quot;2021-03-17T19:54:42Z&amp;quot;
  - apiVersion: cache.example.com/v1alpha1
    fieldsType: FieldsV1
    fieldsV1:
      f:spec:
        .: {}
        f:size: {}
    manager: kubectl
    operation: Update
    time: &amp;quot;2021-03-17T19:54:42Z&amp;quot;
  name: memcached-sample
  namespace: default
  resourceVersion: &amp;quot;1008&amp;quot;
  uid: 4b023125-132a-44e3-80de-20801c7a9268
spec:
  size: 3
status:
  conditions:
  - ansibleResult:
      changed: 0
      completion: 2021-03-17T19:54:54.890394
      failures: 0
      ok: 1
      skipped: 0
    lastTransitionTime: &amp;quot;2021-03-17T19:54:42Z&amp;quot;
    message: Awaiting next reconciliation
    reason: Successful
    status: &amp;quot;True&amp;quot;
    type: Running
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;update-the-size&#34;&gt;Update the size&lt;/h3&gt;
&lt;p&gt;Update &lt;code&gt;config/samples/cache_v1alpha1_memcached.yaml&lt;/code&gt; to change the &lt;code&gt;spec.size&lt;/code&gt; field in the Memcached CR from 3 to 5:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kubectl patch memcached memcached-sample -p &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;{&amp;#34;spec&amp;#34;:{&amp;#34;size&amp;#34;: 5}}&amp;#39;&lt;/span&gt; --type&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;merge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Confirm that the operator changes the deployment size:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get deployment
NAME                                    READY   UP-TO-DATE   AVAILABLE   AGE
memcached-sample                        5/5     5            5           3m
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;cleanup&#34;&gt;Cleanup&lt;/h3&gt;
&lt;p&gt;Run the following to delete all deployed resources:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kubectl delete -f config/samples/cache_v1alpha1_memcached.yaml
make undeploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;next-steps&#34;&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;We recommend reading through the &lt;a href=&#34;/docs/building-operators/ansible/development-tips/&#34;&gt;Ansible development section&lt;/a&gt;
for tips and tricks, including how to run the operator locally.&lt;/p&gt;
&lt;p&gt;In this tutorial, the scaffolded &lt;code&gt;watches.yaml&lt;/code&gt; could be used as-is, but
has additional optional features. See the &lt;a href=&#34;/docs/building-operators/ansible/reference/watches&#34;&gt;watches reference&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For brevity, some of the scaffolded files were left out of this guide.
See &lt;a href=&#34;/docs/building-operators/ansible/reference/scaffolding&#34;&gt;Scaffolding Reference&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This example built a namespaced scope operator, but Ansible operators
can also be used with cluster-wide scope.&lt;/p&gt;
&lt;!--
todo(camilamacedo86): Create an Ansible operator scope document.
https://github.com/operator-framework/operator-sdk/issues/3447
--&gt;
&lt;p&gt;OLM will manage creation of most if not all resources required to run your operator, using a bit of setup from other operator-sdk commands. Check out the &lt;a href=&#34;/docs/olm-integration/tutorial-bundle&#34;&gt;OLM integration guide&lt;/a&gt;.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Ansible Based Operator Testing with Molecule</title>
      <link>/docs/building-operators/ansible/testing-guide/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/ansible/testing-guide/</guid>
      <description>
        
        
        &lt;h2 id=&#34;getting-started&#34;&gt;Getting started&lt;/h2&gt;
&lt;h3 id=&#34;requirements&#34;&gt;Requirements&lt;/h3&gt;
&lt;p&gt;To begin, you should have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The latest version of the &lt;a href=&#34;https://github.com/operator-framework/operator-sdk&#34;&gt;operator-sdk&lt;/a&gt; installed.&lt;/li&gt;
&lt;li&gt;Docker installed and running&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ansible/molecule&#34;&gt;Molecule&lt;/a&gt; &amp;gt;= v3.0&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ansible/ansible&#34;&gt;Ansible&lt;/a&gt; &amp;gt;= v2.9&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/kubernetes-client/python&#34;&gt;The Python Kubernetes client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;An initialized Ansible Operator project, with the molecule directory present.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;  If you initialized a project with a previous version of operator-sdk, you can generate a new dummy project and copy in the &lt;code&gt;molecule&lt;/code&gt; directory. Just be sure to generate the dummy project with the same &lt;code&gt;api-version&lt;/code&gt; and &lt;code&gt;kind&lt;/code&gt;, or some of the generated files will not work without modification. Your top-level project structure should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;```
.
├── config
├── Dockerfile
├── Makefile
├── molecule
├── playbooks
├── PROJECT
├── requirements.yml
├── roles
└── watches.yaml

```
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;The Ansible content specified in &lt;code&gt;requirements.yml&lt;/code&gt; will also need to be installed. You can install them with &lt;code&gt;ansible-galaxy collection install -r requirements.yml&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- TODO(fabianvf, asmacdo): update this section based on the new molecule scaffolding --&gt;
&lt;h3 id=&#34;molecule-scenarios&#34;&gt;Molecule scenarios&lt;/h3&gt;
&lt;p&gt;If you look into the &lt;code&gt;molecule&lt;/code&gt; directory, you will see four directories (&lt;code&gt;default&lt;/code&gt;, &lt;code&gt;test-local&lt;/code&gt;,&lt;code&gt;cluster&lt;/code&gt;, &lt;code&gt;templates&lt;/code&gt;). The &lt;code&gt;default&lt;/code&gt;, &lt;code&gt;test-local&lt;/code&gt;, and &lt;code&gt;cluster&lt;/code&gt; directories contain a set of files that together make up what is known as a molecule &lt;em&gt;scenario&lt;/em&gt;. The &lt;code&gt;templates&lt;/code&gt; directory contains Jinja templates that are used by multiple scenarios to configure the Kubernetes cluster.&lt;/p&gt;
&lt;p&gt;Our molecule scenarios have the following basic structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── molecule.yml
├── prepare.yml
├── converge.yml
└── verify.yml
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;molecule.yml&lt;/code&gt; is a configuration file for molecule. It defines what driver to use to stand up an environment and the associated configuration, linting rules, and a variety of other configuration options. For full documentation on the options available here, see the &lt;a href=&#34;https://molecule.readthedocs.io/configuration/&#34;&gt;molecule configuration documentation&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;prepare.yml&lt;/code&gt; is an Ansible playbook that is run once during the set up of a scenario. You can put any arbitrary Ansible in this playbook. It is used for one-time configuration of your test environment, for example, creating the cluster-wide &lt;code&gt;CustomResourceDefinition&lt;/code&gt; that your Operator will watch.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;converge.yml&lt;/code&gt; is an Ansible playbook that contains your core logic for the scenario. In a normal molecule scenario, this would import and run the associated role. For Ansible Operators, we mostly use this to create the Kubernetes resources necessary to deploy your operator into Kubernetes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below we will walk through the structure and function of each file for each scenario.&lt;/p&gt;
&lt;h4 id=&#34;default&#34;&gt;default&lt;/h4&gt;
&lt;p&gt;The default scenario is intended for use during the development of your Ansible role or playbook, and will run it outside of the context of an operator. You can run this scenario with
&lt;code&gt;molecule test&lt;/code&gt; or &lt;code&gt;molecule converge&lt;/code&gt;. There is no corresponding &lt;code&gt;operator-sdk&lt;/code&gt; command for this scenario.&lt;/p&gt;
&lt;p&gt;The scenario has the following structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;molecule/default
├── molecule.yml
├── prepare.yml
├── converge.yml
└── verify.yml
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;molecule.yml&lt;/code&gt; for this scenario tells molecule to use the docker driver to bring up a Kubernetes-in-Docker container,
and by default exposes the API on the host&amp;rsquo;s port 9443. It also specifies a few inventory and environment
variables which are used in &lt;code&gt;prepare.yml&lt;/code&gt; and &lt;code&gt;converge.yml&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;prepare.yml&lt;/code&gt; ensures that a kubeconfig properly configured to connect to the Kubernetes-in-Docker cluster exists and
is mapped to the proper port, and also waits for the Kubernetes API to become available before allowing testing to begin.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;converge.yml&lt;/code&gt; imports and runs your role or playbook.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;verify.yml&lt;/code&gt; is an Ansible playbook where you can put tasks to verify that the state of your cluster matches what you expect.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;configuration&#34;&gt;Configuration&lt;/h5&gt;
&lt;p&gt;There are a few parameters you can tweak at runtime to change the behavior of your molecule run.
You can change these parameters by setting the environment variable before invoking molecule.&lt;/p&gt;
&lt;p&gt;The options supported by the default scenario are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&#34;left&#34;&gt;Environment variable&lt;/th&gt;
&lt;th align=&#34;left&#34;&gt;Default&lt;/th&gt;
&lt;th align=&#34;left&#34;&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&#34;left&#34;&gt;KUBE_VERSION&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;1.17&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;The Kubernetes version to deploy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&#34;left&#34;&gt;TEST_CLUSTER_PORT&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;9443&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;The port on the host to expose the Kubernetes API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&#34;left&#34;&gt;TEST_OPERATOR_NAMESPACE&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;osdk-test&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;The namespace to run your role against&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&#34;cluster&#34;&gt;cluster&lt;/h4&gt;
&lt;p&gt;The cluster scenario runs an end-to-end test of your operator against an existing cluster.
The operator image needs to be available to the cluster for this scenario to succeed.
This scenario will deploy your CRDs, RBAC, and operator into the cluster,
and then creates an instance of your CustomResource and runs your assertions to make sure the Operator responded properly.&lt;/p&gt;
&lt;p&gt;You can run this scenario with &lt;code&gt;molecule test&lt;/code&gt; or &lt;code&gt;molecule converge&lt;/code&gt;. There is no corresponding &lt;code&gt;operator-sdk&lt;/code&gt; command for this scenario.&lt;/p&gt;
&lt;p&gt;The scenario has the following structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;molecule/default
├── molecule.yml
├── create.yml
├── prepare.yml
├── converge.yml
├── verify.yml
└── destroy.yml
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;molecule.yml&lt;/code&gt; for this scenario uses the delegated driver, and does not spin up any additional infrastructure.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;create.yml&lt;/code&gt; is a no-op, but must be present for the delegated driver to work.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;prepare.yml&lt;/code&gt; ensures the CRD, namespace, and RBAC resources are present in the cluster.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;converge.yml&lt;/code&gt; creates your operator deployment, based on the template in &lt;code&gt;molecule/templates/operator.yaml.j2&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;verify.yml&lt;/code&gt; is an Ansible playbook where you can put tasks to verify that the state of your cluster matches what you expect. By default, it creates a Custom Resource and waits for reconciliation to complete successfully. There is an example assertion present as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;destroy.yml&lt;/code&gt; ensures that the namespace, RBAC resources, and CRD are deleted at the end of the run.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;configuration-1&#34;&gt;Configuration&lt;/h5&gt;
&lt;p&gt;There are a few parameters you can tweak at runtime to change the behavior of your molecule run.
You can change these parameters by setting the environment variable before invoking molecule.&lt;/p&gt;
&lt;p&gt;The options supported by the default scenario are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&#34;left&#34;&gt;Environment variable&lt;/th&gt;
&lt;th align=&#34;left&#34;&gt;Default&lt;/th&gt;
&lt;th align=&#34;left&#34;&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&#34;left&#34;&gt;OPERATOR_IMAGE&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;None&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;&lt;em&gt;Required&lt;/em&gt; The image to use when deploying the operator into the cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&#34;left&#34;&gt;OPERATOR_PULL_POLICY&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;Always&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;The pull policy to use when deploying the operator into the cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&#34;left&#34;&gt;KUBECONFIG&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;~/.kube/config&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;The path to the Kubeconfig for the cluster to test against&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&#34;left&#34;&gt;TEST_OPERATOR_NAMESPACE&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;osdk-test&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;The namespace to run your role against&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&#34;test-local&#34;&gt;test-local&lt;/h4&gt;
&lt;p&gt;The test-local scenario runs a full end-to-end test of your operator that does not require an existing
cluster or external registry, and can run in CI environments that allow users to run privileged containers
(such as Travis).
It brings up a Kubernetes-in-docker cluster, builds your Operator, deploys it into the cluster,
and then creates an instance of your CustomResource and runs your assertions to make sure the Operator responded properly.
You can run this scenario with &lt;code&gt;molecule test -s local&lt;/code&gt;, or with &lt;code&gt;molecule converge -s test-local&lt;/code&gt; which will leave the environment up afterward.&lt;/p&gt;
&lt;p&gt;The scenario has the following structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;molecule/test-local
├── molecule.yml
├── prepare.yml
├── converge.yml
└── verify.yml
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;molecule.yml&lt;/code&gt; for this scenario tells molecule to use the docker driver to bring up a Kubernetes-in-Docker container with the project root mounted, and exposes the API on the host&amp;rsquo;s port 10443. It also specifies a few inventory and environment variables which are used in &lt;code&gt;prepare.yml&lt;/code&gt; and &lt;code&gt;converge.yml&lt;/code&gt;. It is very similar to the default scenario&amp;rsquo;s configuration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;prepare.yml&lt;/code&gt; first runs the &lt;code&gt;prepare.yml&lt;/code&gt; from the default scenario to ensure the kubeconfig is present and the API is up.
It then runs the &lt;code&gt;prepare.yml&lt;/code&gt; from the cluster scenario to configure your cluster&amp;rsquo;s CRDs and RBAC.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;converge.yml&lt;/code&gt; connects to your Kubernetes-in-Docker container, and uses your mounted project root to build your Operator. This makes your Operator available to the cluster without needing to push it to an external registry. Then, it will ensure that a fresh deployment of your Operator is present in the cluster, using the template &lt;code&gt;molecule/templates/operator.yaml.j2&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;verify.yml&lt;/code&gt; will run the &lt;code&gt;verify.yml&lt;/code&gt; from the &lt;code&gt;cluster&lt;/code&gt; scenario, as the main difference between the &lt;code&gt;test-local&lt;/code&gt; and &lt;code&gt;cluster&lt;/code&gt; scenarios is the method of deployment, but not the behavior of the operator.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&#34;configuration-2&#34;&gt;Configuration&lt;/h5&gt;
&lt;p&gt;There are a few parameters you can tweak at runtime to change the behavior of your molecule run.
You can change these parameters by setting the environment variable before invoking molecule.&lt;/p&gt;
&lt;p&gt;The options supported by the default scenario are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&#34;left&#34;&gt;Environment variable&lt;/th&gt;
&lt;th align=&#34;left&#34;&gt;Default&lt;/th&gt;
&lt;th align=&#34;left&#34;&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&#34;left&#34;&gt;KUBE_VERSION&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;1.17&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;The Kubernetes version to deploy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&#34;left&#34;&gt;TEST_CLUSTER_PORT&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;10443&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;The port on the host to expose the Kubernetes API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&#34;left&#34;&gt;TEST_OPERATOR_NAMESPACE&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;osdk-test&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;The namespace to deploy the operator and associated resources&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&#34;converge-vs-test&#34;&gt;converge vs test&lt;/h4&gt;
&lt;p&gt;The two most common molecule commands for testing during development are &lt;code&gt;molecule test&lt;/code&gt; and &lt;code&gt;molecule converge&lt;/code&gt;.
&lt;code&gt;molecule test&lt;/code&gt; performs a full loop, bringing a cluster up, preparing it, running your tasks, and tearing it down.
&lt;code&gt;molecule converge&lt;/code&gt; is more useful for iterative development, as it leaves your environment up between runs. This
can cause unexpected problems if you end up corrupting your environment during testing, but running &lt;code&gt;molecule destroy&lt;/code&gt;
will reset it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;molecule test&lt;/code&gt; performs a full loop, bringing a cluster up, preparing it, running your tasks, and tearing it down.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;molecule converge&lt;/code&gt; is more useful for iterative development, as it leaves your environment up between runs. This can cause unexpected problems if you end up corrupting your environment during testing, but running &lt;code&gt;molecule destroy&lt;/code&gt; will reset it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;writing-tests&#34;&gt;Writing tests&lt;/h2&gt;
&lt;h3 id=&#34;adding-a-task&#34;&gt;Adding a task&lt;/h3&gt;
&lt;p&gt;The default operator that is generated by &lt;code&gt;operator-sdk new&lt;/code&gt; doesn&amp;rsquo;t do anything, so first we will need to add an
Ansible task so that the Operator does something we can verify. For this example, we will create a simple ConfigMap
with a single key.
We&amp;rsquo;ll be adding the task to &lt;code&gt;roles/example/tasks/main.yml&lt;/code&gt;, which should now look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
# tasks file for exampleapp
- name: create Example configmap
  kubernetes.core.k8s:
    definition:
      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: &#39;test-data&#39;
        namespace: &#39;{{ ansible_operator_meta.namespace }}&#39;
      data:
        hello: world
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;adding-a-test&#34;&gt;Adding a test&lt;/h3&gt;
&lt;p&gt;Now that our Operator actually does some work, we can add a corresponding assert to &lt;code&gt;molecule/cluster/verify.yml&lt;/code&gt;.
We&amp;rsquo;ll also add a debug message so that we can see what the ConfigMap looks like.
The file should now look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---

- name: Verify
  hosts: localhost
  connection: local
  tasks:
    - debug: var=cm
      vars:
        cm: &#39;{{ lookup(&amp;quot;kubernetes.core.k8s&amp;quot;, api_version=&amp;quot;v1&amp;quot;, kind=&amp;quot;ConfigMap&amp;quot;, namespace=namespace, resource_name=&amp;quot;test-data&amp;quot;) }}&#39;
    - assert:
        that: cm.data.hello == &#39;world&#39;
      vars:
        cm: &#39;{{ lookup(&amp;quot;kubernetes.core.k8s&amp;quot;, api_version=&amp;quot;v1&amp;quot;, kind=&amp;quot;ConfigMap&amp;quot;, namespace=namespace, resource_name=&amp;quot;test-data&amp;quot;) }}&#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now that we have a functional Operator, and an assertion of its behavior, we can verify that everything is working
by running &lt;code&gt;molecule test -s local&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&#34;the-ansible-assert-and-fail-modules&#34;&gt;The Ansible &lt;code&gt;assert&lt;/code&gt; and &lt;code&gt;fail&lt;/code&gt; modules&lt;/h4&gt;
&lt;p&gt;These modules are handy for adding assertions and failure conditions to your Ansible Operator tests:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.ansible.com/ansible/2.9/modules/assert_module.html&#34;&gt;assert&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.ansible.com/ansible/2.9/modules/fail_module.html&#34;&gt;fail&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Development Tips</title>
      <link>/docs/building-operators/ansible/development-tips/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/ansible/development-tips/</guid>
      <description>
        
        
        &lt;p&gt;This document provides some useful information and tips for a developer
creating an operator powered by Ansible.&lt;/p&gt;
&lt;h2 id=&#34;getting-started-with-the-kubernetes-collection-for-ansible&#34;&gt;Getting started with the Kubernetes Collection for Ansible&lt;/h2&gt;
&lt;p&gt;Since we are interested in using Ansible for the lifecycle management of our
application on Kubernetes, it is beneficial for a developer to get a good
grasp of the &lt;a href=&#34;https://galaxy.ansible.com/kubernetes/core&#34;&gt;Kubernetes Collection for Ansible&lt;/a&gt;.
This Ansible collection allows a developer to either leverage their existing
Kubernetes resource files (written in YAML) or express the lifecycle
management in native Ansible. One of the biggest benefits of using Ansible in
conjunction with existing Kubernetes resource files is the ability to use
Jinja templating so that you can customize deployments with the simplicity of
a few variables in Ansible.&lt;/p&gt;
&lt;p&gt;The easiest way to get started is to install the collection on your local
machine and test it using a playbook.&lt;/p&gt;
&lt;h3 id=&#34;installing-the-kubernetes-collection-for-ansible&#34;&gt;Installing the Kubernetes Collection for Ansible&lt;/h3&gt;
&lt;p&gt;To install the Kubernetes Collection, one must first install Ansible 2.9+.
For example, on Fedora/Centos:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;sudo dnf install ansible
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In addition to Ansible, a user must install the
&lt;a href=&#34;https://github.com/kubernetes-client/python&#34;&gt;Python Kubernetes Client&lt;/a&gt; package:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;pip3 install kubernetes
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, install the Kubernetes Collection from ansible-galaxy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;ansible-galaxy collection install kubernetes.core
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alternatively, if you&amp;rsquo;ve already initialized your operator, you may have a
&lt;code&gt;requirements.yml&lt;/code&gt; file at the top level of your project. This file specifies
Ansible dependencies that need to be installed for your operator to function.
By default it will install the &lt;code&gt;kubernetes.core&lt;/code&gt; collection as well as
the &lt;code&gt;operator_sdk.util&lt;/code&gt; collection, which provides modules and plugins for
operator-specific operations.&lt;/p&gt;
&lt;p&gt;To install the dependent modules from this file, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;ansible-galaxy collection install -r requirements.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;testing-the-kubernetes-collection-locally&#34;&gt;Testing the Kubernetes Collection locally&lt;/h3&gt;
&lt;p&gt;Sometimes it is beneficial for a developer to run the Ansible code from their
local machine as opposed to running/rebuilding the operator each time. To do
this, initialize a new project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;mkdir memcached-operator &lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#204a87&#34;&gt;cd&lt;/span&gt; memcached-operator
operator-sdk init --plugins&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;ansible --domain&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;example.com --group&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;cache --version&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;v1alpha1 --kind&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;Memcached --generate-role
ansible-galaxy collection install -r requirements.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Modify &lt;code&gt;roles/memcached/tasks/main.yml&lt;/code&gt; with desired Ansible logic. For this example
we will create and delete a ConfigMap based on the value of a variable named
&lt;code&gt;state&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;set&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;ConfigMap&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;example-config&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;to&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;{{&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;state&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;}}&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kubernetes.core.k8s&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;api_version&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;v1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;ConfigMap&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;example-config&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;namespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;default&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;state&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;{{ state }}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;ignore_errors&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;alert alert-primary&#34; role=&#34;alert&#34;&gt;
&lt;h4 class=&#34;alert-heading&#34;&gt;Note&lt;/h4&gt;
Setting &lt;code&gt;ignore_errors: true&lt;/code&gt; is done so that deleting a nonexistent
ConfigMap doesn&amp;rsquo;t error out.
&lt;/div&gt;

&lt;p&gt;Modify &lt;code&gt;roles/memcached/defaults/main.yml&lt;/code&gt; to set &lt;code&gt;state&lt;/code&gt; to &lt;code&gt;present&lt;/code&gt; as default.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;state&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;present&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Create an Ansible playbook &lt;code&gt;playbook.yml&lt;/code&gt; in the top-level directory which
includes role &lt;code&gt;memcached&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;hosts&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;localhost&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;roles&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;- memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run the playbook:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ ansible-playbook playbook.yml
 [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match &#39;all&#39;


PLAY [localhost] ***************************************************************************

TASK [Gathering Facts] *********************************************************************
ok: [localhost]

Task [memcached : set ConfigMap example-config to present]
changed: [localhost]

PLAY RECAP *********************************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Check that the ConfigMap was created:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get configmaps
NAME                    STATUS    AGE
example-config          Active    3s
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Rerun the playbook setting &lt;code&gt;state&lt;/code&gt; to &lt;code&gt;absent&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ ansible-playbook playbook.yml --extra-vars state=absent
 [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match &#39;all&#39;


PLAY [localhost] ***************************************************************************

TASK [Gathering Facts] *********************************************************************
ok: [localhost]

Task [memcached : set ConfigMap example-config to absent]
changed: [localhost]

PLAY RECAP *********************************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Check that the ConfigMap was deleted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get configmaps
No resources found in default namespace.
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;using-ansible-inside-an-operator&#34;&gt;Using Ansible inside an Operator&lt;/h2&gt;
&lt;p&gt;Now that we have demonstrated using the Kubernetes Collection, we want to
trigger this Ansible logic when a custom resource changes. In the above
example, we want to map a role to a specific Kubernetes resource that the
operator will watch. This mapping is done in a file called &lt;code&gt;watches.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;custom-resource-file&#34;&gt;Custom Resource file&lt;/h3&gt;
&lt;p&gt;The Custom Resource (CR) file format is Kubernetes resource file. The object
has some mandatory fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;apiVersion&lt;/code&gt;:  The version of the Custom Resource that will be created.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kind&lt;/code&gt;:  The kind of the Custom Resource that will be created&lt;/li&gt;
&lt;li&gt;&lt;code&gt;metadata&lt;/code&gt;:  Kubernetes specific metadata to be created&lt;/li&gt;
&lt;li&gt;&lt;code&gt;spec&lt;/code&gt;:  This is the key-value list of variables which are passed to Ansible.
This field is optional and empty by default.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;annotations&lt;/code&gt;: Kubernetes specific annotations to be appended to the CR. See
the below section for Ansible Operator specific annotations. This field is optional.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;annotations-for-custom-resource&#34;&gt;Annotations for Custom Resource&lt;/h4&gt;
&lt;p&gt;This is the list of CR annotations which will modify the behavior of the operator:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ansible.operator-sdk/reconcile-period&lt;/code&gt;: Specifies the maximum time before a
reconciliation is triggered. Note that at scale, this can reduce
performance, see &lt;a href=&#34;/docs/building-operators/ansible/reference/watches&#34;&gt;watches&lt;/a&gt; reference for more information. This value
is parsed using the standard Go package &lt;a href=&#34;https://golang.org/pkg/time/&#34;&gt;time&lt;/a&gt;. Specifically
&lt;a href=&#34;https://golang.org/pkg/time/#ParseDuration&#34;&gt;ParseDuration&lt;/a&gt; is used which will apply the default
suffix of &lt;code&gt;s&lt;/code&gt; giving the value in seconds.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#204a87;font-weight:bold&#34;&gt;apiVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;cache.example.com/v1alpha1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;example&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;annotations&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;ansible.operator-sdk/reconcile-period&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;30s&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that a lower period will correct entropy more quickly, but reduce
responsiveness to change if there are many watched resources. Typically, this
option should only be used in advanced use cases where
&lt;code&gt;watchDependentResources&lt;/code&gt; is set to &lt;code&gt;False&lt;/code&gt;  and when is not possible to use
the watch feature. E.g To managing external resources that don’t raise
Kubernetes events.&lt;/p&gt;
&lt;h3 id=&#34;testing-an-ansible-operator-locally&#34;&gt;Testing an Ansible Operator locally&lt;/h3&gt;
&lt;p&gt;Once a developer is comfortable working with the above workflow, it will be
beneficial to test the logic inside an operator.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read the &lt;a href=&#34;../tutorial&#34;&gt;Ansible Operator tutorial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install &lt;code&gt;ansible-operator&lt;/code&gt; &lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/c6796de/images/ansible-operator/Pipfile.lock&#34;&gt;dependencies&lt;/a&gt; using &lt;a href=&#34;https://pypi.org/project/pipenv/&#34;&gt;&lt;code&gt;pipenv&lt;/code&gt;&lt;/a&gt;
and their OS prerequisite &lt;a href=&#34;https://github.com/operator-framework/operator-sdk/blob/c6796de/images/ansible-operator/base.Dockerfile#L29&#34;&gt;packages&lt;/a&gt; (these will differ depending on OS) locally.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;run&lt;/code&gt; Makefile target runs the &lt;code&gt;ansible-operator&lt;/code&gt; binary locally, which reads from
&lt;code&gt;./watches.yaml&lt;/code&gt; and uses &lt;code&gt;~/.kube/config&lt;/code&gt; to communicate with a Kubernetes
cluster just as the &lt;code&gt;k8s&lt;/code&gt; modules do. The &lt;code&gt;install&lt;/code&gt; target registers the operator&amp;rsquo;s
&lt;code&gt;Memcached&lt;/code&gt; CustomResourceDefinition (CRD) with the apiserver.&lt;/p&gt;


&lt;div class=&#34;alert alert-primary&#34; role=&#34;alert&#34;&gt;
&lt;h4 class=&#34;alert-heading&#34;&gt;Note&lt;/h4&gt;
You can customize the roles path by setting the environment variable
&lt;code&gt;ANSIBLE_ROLES_PATH&lt;/code&gt; or using the flag &lt;code&gt;ansible-roles-path&lt;/code&gt;. Note that if the
role is not found in &lt;code&gt;ANSIBLE_ROLES_PATH&lt;/code&gt;, then the operator will look for it
in &lt;code&gt;{{current directory}}/roles&lt;/code&gt;.
&lt;/div&gt;

&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ make install run
/home/user/memcached-operator/bin/kustomize build config/crd | kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/memcacheds.cache.example.com created
/home/user/go/bin/ansible-operator run
{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;ts&amp;quot;:1595899073.9861593,&amp;quot;logger&amp;quot;:&amp;quot;cmd&amp;quot;,&amp;quot;msg&amp;quot;:&amp;quot;Version&amp;quot;,&amp;quot;Go Version&amp;quot;:&amp;quot;go1.13.12&amp;quot;,&amp;quot;GOOS&amp;quot;:&amp;quot;linux&amp;quot;,&amp;quot;GOARCH&amp;quot;:&amp;quot;amd64&amp;quot;,&amp;quot;ansible-operator&amp;quot;:&amp;quot;v0.19.0+git&amp;quot;}
{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;ts&amp;quot;:1595899073.987384,&amp;quot;logger&amp;quot;:&amp;quot;cmd&amp;quot;,&amp;quot;msg&amp;quot;:&amp;quot;WATCH_NAMESPACE environment variable not set. Watching all namespaces.&amp;quot;,&amp;quot;Namespace&amp;quot;:&amp;quot;&amp;quot;}
{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;ts&amp;quot;:1595899074.9504397,&amp;quot;logger&amp;quot;:&amp;quot;controller-runtime.metrics&amp;quot;,&amp;quot;msg&amp;quot;:&amp;quot;metrics server is starting to listen&amp;quot;,&amp;quot;addr&amp;quot;:&amp;quot;:8080&amp;quot;}
{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;ts&amp;quot;:1595899074.9522583,&amp;quot;logger&amp;quot;:&amp;quot;watches&amp;quot;,&amp;quot;msg&amp;quot;:&amp;quot;Environment variable not set; using default value&amp;quot;,&amp;quot;envVar&amp;quot;:&amp;quot;ANSIBLE_VERBOSITY_MEMCACHED_CACHE_EXAMPLE_COM&amp;quot;,&amp;quot;default&amp;quot;:2}
{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;ts&amp;quot;:1595899074.9524004,&amp;quot;logger&amp;quot;:&amp;quot;cmd&amp;quot;,&amp;quot;msg&amp;quot;:&amp;quot;Environment variable not set; using default value&amp;quot;,&amp;quot;Namespace&amp;quot;:&amp;quot;&amp;quot;,&amp;quot;envVar&amp;quot;:&amp;quot;ANSIBLE_DEBUG_LOGS&amp;quot;,&amp;quot;ANSIBLE_DEBUG_LOGS&amp;quot;:false}
{&amp;quot;level&amp;quot;:&amp;quot;info&amp;quot;,&amp;quot;ts&amp;quot;:1595899074.9524298,&amp;quot;logger&amp;quot;:&amp;quot;ansible-controller&amp;quot;,&amp;quot;msg&amp;quot;:&amp;quot;Watching resource&amp;quot;,&amp;quot;Options.Group&amp;quot;:&amp;quot;cache.example.com&amp;quot;,&amp;quot;Options.Version&amp;quot;:&amp;quot;v1&amp;quot;,&amp;quot;Options.Kind&amp;quot;:&amp;quot;Memcached&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now that the operator is watching resource &lt;code&gt;Memcached&lt;/code&gt; for events, the creation of a
Custom Resource will trigger our Ansible Role to be executed. Take a look at
&lt;code&gt;config/samples/cache_v1alpha1_memcached.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#204a87;font-weight:bold&#34;&gt;apiVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;cache.example.com/v1alpha1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached-sample&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since &lt;code&gt;spec&lt;/code&gt; is not set, Ansible is invoked with no extra variables. The next
section covers how extra variables are passed from a Custom Resource to
Ansible. This is why it is important to set sane defaults for the operator.&lt;/p&gt;
&lt;p&gt;Create a Custom Resource instance of Memcached with variable &lt;code&gt;state&lt;/code&gt; default to
&lt;code&gt;present&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kubectl create -f config/samples/cache_v1alpha1_memcached.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Check that ConfigMap &lt;code&gt;example-config&lt;/code&gt; was created:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get configmaps
NAME                    STATUS    AGE
example-config          Active    3s
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Modify &lt;code&gt;config/samples/cache_v1alpha1_memcached.yaml&lt;/code&gt; to set &lt;code&gt;state&lt;/code&gt; to
&lt;code&gt;absent&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#204a87;font-weight:bold&#34;&gt;apiVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;cache.example.com/v1alpha1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached-sample&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;state&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;absent&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Apply the changes to Kubernetes and confirm that the ConfiMap is deleted:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kubectl apply -f config/samples/cache_v1alpha1_memcached.yaml
kubectl get configmaps
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;testing-an-ansible-operator-on-a-cluster&#34;&gt;Testing an Ansible Operator on a cluster&lt;/h3&gt;
&lt;p&gt;Now that a developer is confident in the operator logic, testing the operator
inside of a pod on a Kubernetes cluster is desired. Running as a pod inside a
Kubernetes cluster is preferred for production use.&lt;/p&gt;
&lt;p&gt;To build the &lt;code&gt;memcached-operator&lt;/code&gt; image and push it to a registry:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make docker-build docker-push &lt;span style=&#34;color:#000&#34;&gt;IMG&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;example.com/memcached-operator:v0.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Deploy the memcached-operator:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make install
make deploy &lt;span style=&#34;color:#000&#34;&gt;IMG&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;example.com/memcached-operator:v0.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Verify that the memcached-operator is up and running:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-console&#34; data-lang=&#34;console&#34;&gt;$ kubectl get deployment -n memcached-operator-system
NAME                     DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
memcached-operator       1         1         1            1           1m
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;viewing-the-ansible-logs&#34;&gt;Viewing the Ansible logs&lt;/h3&gt;
&lt;p&gt;In order to see the logs from a particular operator you can run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kubectl logs deployment/memcached-operator-controller-manager -n memcached-operator-system
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The logs contain the information about the Ansible run and are useful for
debugging your Ansible tasks. Note that the logs may contain much more
detailed information about the Ansible Operator&amp;rsquo;s internals and its
interactions with Kubernetes as well.&lt;/p&gt;
&lt;p&gt;Also, you can set the environment variable &lt;code&gt;ANSIBLE_DEBUG_LOGS&lt;/code&gt; to &lt;code&gt;True&lt;/code&gt; to
check the full Ansible result in the logs in order to be able to debug it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;config/manager/manager.yaml&lt;/code&gt; and &lt;code&gt;config/default/manager_metrics_patch.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;containers&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;manager&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;env&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;ANSIBLE_DEBUG_LOGS&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;          &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;value&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;True&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;...&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Occasionally while developing additional debug in the Operator logs is nice to have.
Using the memcached operator as an example, we can simply add the
&lt;code&gt;&amp;quot;ansible.sdk.operatorframework.io/verbosity&amp;quot;&lt;/code&gt; annotation to the Custom
Resource with the desired verbosity.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#204a87;font-weight:bold&#34;&gt;apiVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;cache.example.com/v1alpha1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Memcached&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;example-memcached&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;annotations&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;&amp;#34;ansible.sdk.operatorframework.io/verbosity&amp;#34;: &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;4&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;size&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;custom-resource-status-management&#34;&gt;Custom Resource Status Management&lt;/h2&gt;
&lt;p&gt;By default, an Ansible Operator will include the generic output from previous
Ansible run as the &lt;code&gt;status&lt;/code&gt; subresource of a CR. This includes the number of
successful and failed tasks and relevant error messages as shown below:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#204a87;font-weight:bold&#34;&gt;status&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;conditions&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;ansibleResult&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;changed&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;completion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;2018-12-03T13:45:57.13329&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;failures&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;ok&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;skipped&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;lastTransitionTime&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;2018-12-03T13:45:57Z&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;message: &amp;#39;Status code was -1 and not [200]: Request failed&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&amp;lt;urlopen&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;error&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;[&lt;/span&gt;Errno&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;113&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;No&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;route&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;to&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;host&amp;gt;&amp;#39;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;reason&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Failed&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;status&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;True&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Failure&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;lastTransitionTime&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#000&#34;&gt;2018-12-03T13:46:13Z&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;message&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Running&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;reconciliation&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;reason&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Running&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;status&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;True&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Running&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;An Ansible Operator also allows you to supply custom status values with the
&lt;code&gt;k8s_status&lt;/code&gt; Ansible module, which is included in
&lt;a href=&#34;https://galaxy.ansible.com/operator_sdk/util&#34;&gt;operator_sdk.util&lt;/a&gt; collection.
You can update the &lt;code&gt;status&lt;/code&gt; from within Ansible with any key/value pairs as
desired. If you do not want the operator to update the status with Ansible
output, and you want to track the CR status manually from your application,
you can update the &lt;code&gt;watches.yaml&lt;/code&gt; file with &lt;code&gt;manageStatus&lt;/code&gt;, as shown below:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#204a87;font-weight:bold&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;v1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;group&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;api.example.com&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;role&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;manageStatus&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The simplest way to invoke the &lt;code&gt;k8s_status&lt;/code&gt; module is to use its fully
qualified collection name (fqcn), i.e. &lt;code&gt;operator_sdk.util.k8s_status&lt;/code&gt;.  The
following example updates the &lt;code&gt;status&lt;/code&gt; subresource with key &lt;code&gt;memcached&lt;/code&gt; and value &lt;code&gt;bar&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#204a87;font-weight:bold&#34;&gt;operator_sdk.util.k8s_status&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;api_version&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;app.example.com/v1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;{{ ansible_operator_meta.name }}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;namespace&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;{{ ansible_operator_meta.namespace }}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;status&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;foo&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;bar&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Collections can also be declared in the role&amp;rsquo;s &lt;code&gt;meta/main.yml&lt;/code&gt;, which is
included for newly scaffolded Ansible operators.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#204a87;font-weight:bold&#34;&gt;collections&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;- operator_sdk.util&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Declaring collections in the role meta allows you to invoke the
&lt;code&gt;k8s_status&lt;/code&gt; module directly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#204a87;font-weight:bold&#34;&gt;k8s_status&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&amp;lt;snip&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;&amp;gt;
&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;    status:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;foo&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;bar&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;ansible-operator-conditions&#34;&gt;Ansible Operator Conditions&lt;/h3&gt;
&lt;p&gt;An Ansible Operator has a set of conditions that are used during reconciliation.
There are only a few main conditions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Running - the Ansible Operator is currently running the Ansible for
reconciliation.&lt;/li&gt;
&lt;li&gt;Successful - if the run has finished and there were no errors, the Ansible
Operator will be marked as Successful. It will then wait for the next
reconciliation action, either the reconcile period, dependent watches triggers
or the resource is updated.&lt;/li&gt;
&lt;li&gt;Failed - if there is any error during the reconciliation run, the Ansible
Operator will be marked as Failed with the error message from the error that
caused this condition. The error message is the raw output from the Ansible
run for reconciliation. If the Failure is intermittent, often times the
situation can be resolved when the Operator reruns the reconciliation loop.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;extra-vars-sent-to-ansible&#34;&gt;Extra vars sent to Ansible&lt;/h2&gt;
&lt;p&gt;The extra vars that are sent to Ansible are managed by the operator. The &lt;code&gt;spec&lt;/code&gt;
section will pass along the key-value pairs as extra vars.  This is equivalent
to how above extra vars are passed in to &lt;code&gt;ansible-playbook&lt;/code&gt;. The operator also
passes along additional variables under the &lt;code&gt;ansible_operator_meta&lt;/code&gt; field for
the name of the CR and the namespace of the CR.&lt;/p&gt;
&lt;p&gt;For the CR example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#204a87;font-weight:bold&#34;&gt;apiVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;cache.example.com/v1alpha1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Memcached&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;memcached-sample&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;message&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Hello world 2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;newParameter&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;newParam&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The structure passed to Ansible as extra vars is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;&amp;#34;ansible_operator_meta&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
        &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;&amp;lt;cr-name&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
        &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;&amp;#34;namespace&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;&amp;lt;cr-namespace&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
  &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
  &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Hello world 2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
  &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;&amp;#34;new_parameter&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;newParam&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;,&lt;/span&gt;
  &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;&amp;#34;_app_example_com_database&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
     &lt;span style=&#34;color:#a40000&#34;&gt;&amp;lt;Full&lt;/span&gt; &lt;span style=&#34;color:#a40000&#34;&gt;CR&amp;gt;&lt;/span&gt;
   &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
  &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;&amp;#34;_app_example_com_database_spec&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;{&lt;/span&gt;
     &lt;span style=&#34;color:#a40000&#34;&gt;&amp;lt;Full&lt;/span&gt; &lt;span style=&#34;color:#a40000&#34;&gt;CR&lt;/span&gt; &lt;span style=&#34;color:#a40000&#34;&gt;.spec&amp;gt;&lt;/span&gt;
   &lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;message&lt;/code&gt; and &lt;code&gt;newParameter&lt;/code&gt; are set in the top level as extra variables, and
&lt;code&gt;ansible_operator_meta&lt;/code&gt; provides the relevant metadata for the Custom Resource as defined in the
operator. The &lt;code&gt;ansible_operator_meta&lt;/code&gt; fields can be accessed via dot notation in Ansible as so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;debug&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;msg&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;name: {{ ansible_operator_meta.name }}, {{ ansible_operator_meta.namespace }}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
      </description>
    </item>
    
    <item>
      <title>Docs: </title>
      <link>/docs/building-operators/ansible/migration/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/ansible/migration/</guid>
      <description>
        
        
        &lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;The motivations for the new layout are related to bringing more flexibility to users and part of the process to Integrating Kubebuilder and Operator SDK. Because of this integration you may be referred to the Kubebuilder documentation &lt;a href=&#34;https://book.kubebuilder.io/&#34;&gt;https://book.kubebuilder.io/&lt;/a&gt; for more information about certain topics. When using this document just remember to replace &lt;code&gt;$ kubebuilder &amp;lt;command&amp;gt;&lt;/code&gt; with &lt;code&gt;$ operator-sdk &amp;lt;command&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It is recommended that you have your project upgraded to the latest SDK v1.y release version before following the steps in this guide to migrate to the new layout. However, the steps might work from previous versions as well. In this case, if you find an issue which is not covered here then check the previous &lt;a href=&#34;/docs/upgrading-sdk-version/&#34;&gt;Migration Guides&lt;/a&gt; which might help out.&lt;/p&gt;
&lt;h3 id=&#34;what-was-changed&#34;&gt;What was changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;deploy&lt;/code&gt; directory was replaced with the &lt;code&gt;config&lt;/code&gt; directory including a new layout of Kubernetes manifests files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CRD manifests in &lt;code&gt;deploy/crds/&lt;/code&gt; are now in &lt;code&gt;config/crd/bases&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CR manifests in &lt;code&gt;deploy/crds/&lt;/code&gt; are now in &lt;code&gt;config/samples&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Controller manifest &lt;code&gt;deploy/operator.yaml&lt;/code&gt; is now in &lt;code&gt;config/manager/manager.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;RBAC manifests in &lt;code&gt;deploy&lt;/code&gt; are now in &lt;code&gt;config/rbac/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;build/Dockerfile&lt;/code&gt; is moved to &lt;code&gt;Dockerfile&lt;/code&gt; in the project root directory&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;molecule/&lt;/code&gt; directory is now more aligned to Ansible and the new Layout&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;what-is-new&#34;&gt;What is new&lt;/h3&gt;
&lt;p&gt;Scaffolded projects now use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/kubernetes-sigs/kustomize&#34;&gt;kustomize&lt;/a&gt; to manage Kubernetes resources needed to deploy your operator&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Makefile&lt;/code&gt; with helpful targets for build, test, and deployment, and to give you flexibility to tailor things to your project&amp;rsquo;s needs&lt;/li&gt;
&lt;li&gt;Updated metrics configuration using &lt;a href=&#34;https://github.com/brancz/kube-rbac-proxy&#34;&gt;kube-auth-proxy&lt;/a&gt;, a &lt;code&gt;--metrics-bind-address&lt;/code&gt; flag, and &lt;a href=&#34;https://github.com/kubernetes-sigs/kustomize&#34;&gt;kustomize&lt;/a&gt;-based deployment of a Kubernetes &lt;code&gt;Service&lt;/code&gt; and prometheus operator &lt;code&gt;ServiceMonitor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Preliminary support for CLI plugins. For more info see the [plugins design document][plugins-phase1-design-doc]&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;PROJECT&lt;/code&gt; configuration file to store information about GVKs, plugins, and help the CLI make decisions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Generated files with the default API versions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;apiextensions/v1&lt;/code&gt; for generated CRDs (&lt;code&gt;apiextensions/v1beta1&lt;/code&gt; was deprecated in Kubernetes &lt;code&gt;1.16&lt;/code&gt; and will be removed in &lt;code&gt;1.22&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;admissionregistration.k8s.io/v1&lt;/code&gt; for webhooks (&lt;code&gt;admissionregistration.k8s.io/v1beta1&lt;/code&gt; was deprecated in Kubernetes &lt;code&gt;1.16&lt;/code&gt; and will be removed in &lt;code&gt;1.22&lt;/code&gt; )&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;how-to-migrate&#34;&gt;How to migrate&lt;/h2&gt;
&lt;p&gt;The easy migration path is to initialize a new project, re-recreate APIs, then copy pre-v1.0.0 configuration files into the new project.&lt;/p&gt;
&lt;h3 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Go through the &lt;a href=&#34;/docs/building-operators/ansible/installation&#34;&gt;installation guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Make sure your user is authorized with &lt;code&gt;cluster-admin&lt;/code&gt; permissions.&lt;/li&gt;
&lt;li&gt;An accessible image registry for various operator images (ex. &lt;a href=&#34;https://hub.docker.com/signup&#34;&gt;hub.docker.com&lt;/a&gt;,
&lt;a href=&#34;https://quay.io/&#34;&gt;quay.io&lt;/a&gt;) and be logged in to your command line environment.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;example.com&lt;/code&gt; is used as the registry Docker Hub namespace in these examples.
Replace it with another value if using a different registry or namespace.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/docs/olm-integration/cli-overview#private-bundle-and-catalog-image-registries&#34;&gt;Authentication and certificates&lt;/a&gt; if the registry is private or uses a custom CA.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;creating-a-new-project&#34;&gt;Creating a new project&lt;/h3&gt;
&lt;p&gt;In Kubebuilder-style projects, CRD groups are defined using two different flags
(&lt;code&gt;--group&lt;/code&gt; and &lt;code&gt;--domain&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;When we initialize a new project, we need to specify the domain that &lt;em&gt;all&lt;/em&gt; APIs in
our project will share, so before creating the new project, we need to determine which
domain we&amp;rsquo;re using for the APIs in our existing project.&lt;/p&gt;
&lt;p&gt;To determine the domain, look at the &lt;code&gt;spec.group&lt;/code&gt; field in your CRDs in the
&lt;code&gt;deploy/crds&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;The domain is everything after the first DNS segment. Using &lt;code&gt;cache.example.com&lt;/code&gt; as an
example, the &lt;code&gt;--domain&lt;/code&gt; would be &lt;code&gt;example.com&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s create a new project with the same domain (&lt;code&gt;example.com&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;mkdir memcached-operator
&lt;span style=&#34;color:#204a87&#34;&gt;cd&lt;/span&gt; memcached-operator
operator-sdk init --plugins&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;ansible --domain&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;example.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that we have our new project initialized, we need to recreate each of our APIs.
Using our API example from earlier (&lt;code&gt;cache.example.com&lt;/code&gt;), we&amp;rsquo;ll use &lt;code&gt;cache&lt;/code&gt; for the
&lt;code&gt;--group&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;For &lt;code&gt;--version&lt;/code&gt; and &lt;code&gt;--kind&lt;/code&gt;, we use &lt;code&gt;spec.versions[0].name&lt;/code&gt; and &lt;code&gt;spec.names.kind&lt;/code&gt;, respectively.&lt;/p&gt;
&lt;p&gt;For each API in the existing project, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;operator-sdk create api &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --group&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;cache &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --version&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;v1 &lt;span style=&#34;color:#4e9a06&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&lt;/span&gt;    --kind&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;Memcached
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running the above command creates an empty &lt;code&gt;roles/&amp;lt;kind&amp;gt;&lt;/code&gt;. We can copy over the content of our old &lt;code&gt;roles/&amp;lt;kind&amp;gt;&lt;/code&gt; to the new one.&lt;/p&gt;
&lt;h3 id=&#34;migrating-your-custom-resource-samples&#34;&gt;Migrating your Custom Resource samples&lt;/h3&gt;
&lt;p&gt;Update the CR manifests in &lt;code&gt;config/samples&lt;/code&gt; with the values of the CRs in your existing project which are in &lt;code&gt;deploy/crds/&amp;lt;group&amp;gt;_&amp;lt;version&amp;gt;_&amp;lt;kind&amp;gt;_cr.yaml&lt;/code&gt; In our example
the &lt;code&gt;config/samples/cache_v1alpha1_memcached.yaml&lt;/code&gt; will look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#204a87;font-weight:bold&#34;&gt;apiVersion&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;cache.example.com/v1alpha1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;metadata&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached-sample&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;spec&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;# TODO(user): Add fields here&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;size&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;migrating-watchesyaml&#34;&gt;Migrating &lt;code&gt;watches.yaml&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Update the &lt;code&gt;watches.yaml&lt;/code&gt; file with your &lt;code&gt;roles/playbooks&lt;/code&gt; and check if you have custom options in the &lt;code&gt;watches.yaml&lt;/code&gt; file of your existing project. If so, update the new &lt;code&gt;watches.yaml&lt;/code&gt; file to match.&lt;/p&gt;
&lt;p&gt;In our example, we will replace &lt;code&gt;# FIXME: Specify the role or playbook for this resource.&lt;/code&gt; with our previous role and it will look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;# Use the &amp;#39;create api&amp;#39; subcommand to add watches to this file.&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;v1alpha1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;group&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;cache.example.com&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;role&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;#+kubebuilder:scaffold:watch&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: Do not remove the &lt;code&gt;+kubebuilder:scaffold:watch&lt;/code&gt; &lt;a href=&#34;https://book.kubebuilder.io/reference/markers.html?highlight=markers#marker-syntax&#34;&gt;marker&lt;/a&gt;. It allows the tool to update the watches file when new APIs are created.&lt;/p&gt;
&lt;p&gt;Additionally pre-1.0 the &lt;code&gt;reconcilePeriod&lt;/code&gt; parameter was an integer representing the maximum time in seconds before a reconcile would be triggered.
With 1.0, it was changed to a string representing the maximum duration before a reconcile will be triggered. Appending an &lt;code&gt;s&lt;/code&gt; to your &lt;code&gt;reconcilePeriod&lt;/code&gt;
will set the duration unit to seconds and match the old behavior.&lt;/p&gt;
&lt;p&gt;so for example a resource set to requeue every hour:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;# Use the &amp;#39;create api&amp;#39; subcommand to add watches to this file.&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;v1alpha1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;group&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;cache.example.com&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;role&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;reconcilePeriod&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#0000cf;font-weight:bold&#34;&gt;3600&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;#+kubebuilder:scaffold:watch&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;would become&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;# Use the &amp;#39;create api&amp;#39; subcommand to add watches to this file.&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;v1alpha1&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;group&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;cache.example.com&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kind&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;Memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;role&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;memcached&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;reconcilePeriod&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;3600s&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#8f5902;font-style:italic&#34;&gt;#+kubebuilder:scaffold:watch&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and the values &lt;code&gt;60m&lt;/code&gt; and &lt;code&gt;1h&lt;/code&gt; would be equivalent to the &lt;code&gt;3600s&lt;/code&gt; that is used.&lt;/p&gt;
&lt;h3 id=&#34;migrating-your-molecule-tests&#34;&gt;Migrating your Molecule tests&lt;/h3&gt;
&lt;p&gt;If you are using &lt;a href=&#34;https://molecule.readthedocs.io/&#34;&gt;Molecule&lt;/a&gt; in your project will be required to port the tests for the new layout.&lt;/p&gt;
&lt;p&gt;See that default structure changed from:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;├── cluster
│   ├── converge.yml
│   ├── create.yml
│   ├── destroy.yml
│   ├── molecule.yml
│   ├── prepare.yml
│   └── verify.yml
├── default
│   ├── converge.yml
│   ├── molecule.yml
│   ├── prepare.yml
│   └── verify.yml
├── templates
│   └── operator.yaml.j2
└── test-local
    ├── converge.yml
    ├── molecule.yml
    ├── prepare.yml
    └── verify.yml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;├── default
│   ├── converge.yml
│   ├── create.yml
│   ├── destroy.yml
│   ├── kustomize.yml
│   ├── molecule.yml
│   ├── prepare.yml
│   ├── tasks
│   │   └── foo_test.yml
│   └── verify.yml
└── kind
    ├── converge.yml
    ├── create.yml
    ├── destroy.yml
    └── molecule.yml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ensure that the &lt;code&gt;provisioner.host_vars.localhost&lt;/code&gt; has the following &lt;code&gt;host_vars&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;host_vars&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;localhost&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;ansible_python_interpreter&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#39;{{ ansible_playbook_python }}&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;config_dir&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;${MOLECULE_PROJECT_DIRECTORY}/config&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;samples_dir&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;${MOLECULE_PROJECT_DIRECTORY}/config/samples&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;operator_image&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;${OPERATOR_IMAGE&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;-&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;}&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;operator_pull_policy&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;${OPERATOR_PULL_POLICY&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;-&lt;span style=&#34;color:#4e9a06&#34;&gt;&amp;#34;Always&amp;#34;&lt;/span&gt;}&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;kustomize&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt; &lt;/span&gt;${KUSTOMIZE_PATH&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;-kustomize}&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;&lt;/span&gt;...&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For more information read the &lt;a href=&#34;/docs/building-operators/ansible/testing-guide&#34;&gt;Testing with Molecule&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;checking-rbac-permissions&#34;&gt;Checking RBAC Permissions&lt;/h3&gt;
&lt;p&gt;In your new project, roles are automatically generated in &lt;code&gt;config/rbac/role.yaml&lt;/code&gt;.
If you modified these permissions manually in &lt;code&gt;deploy/role.yaml&lt;/code&gt; in your existing
project, you need to re-apply them in &lt;code&gt;config/rbac/role.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;!--
todo(camilamacedo86): Create an Ansible operator scope document.
https://github.com/operator-framework/operator-sdk/issues/3447
--&gt;
&lt;p&gt;New projects are configured to watch all namespaces by default, so they need a &lt;code&gt;ClusterRole&lt;/code&gt; to have the necessary permissions. Ensure that &lt;code&gt;config/rbac/role.yaml&lt;/code&gt; remains a &lt;code&gt;ClusterRole&lt;/code&gt; if you want to retain the default behavior of the new project conventions.&lt;/p&gt;
&lt;p&gt;The following rules were used in earlier versions of ansible-operator to automatically create and manage services and &lt;code&gt;servicemonitors&lt;/code&gt; for metrics collection. If your operator&amp;rsquo;s don&amp;rsquo;t require these rules, they can safely be left out of the new &lt;code&gt;config/rbac/role.yaml&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-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;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;apiGroups&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;- monitoring.coreos.com&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;resources&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;- servicemonitors&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;verbs&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;- get&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;- create&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;apiGroups&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;- apps&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;resourceNames&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;- memcached-operator&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;resources&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;- deployments/finalizers&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;&lt;span style=&#34;color:#204a87;font-weight:bold&#34;&gt;verbs&lt;/span&gt;&lt;span style=&#34;color:#000;font-weight:bold&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;    &lt;/span&gt;- update&lt;span style=&#34;color:#f8f8f8;text-decoration:underline&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;updating-your-serviceaccount&#34;&gt;Updating your ServiceAccount&lt;/h5&gt;
&lt;p&gt;New Ansible projects come with a ServiceAccount &lt;code&gt;controller-manager&lt;/code&gt; in &lt;code&gt;config/rbac/service_account.yaml&lt;/code&gt;.
Your project&amp;rsquo;s RoleBinding and ClusterRoleBinding subjects, and Deployment&amp;rsquo;s &lt;code&gt;spec.template.spec.serviceAccountName&lt;/code&gt;
that reference a ServiceAccount already refer to this new name. When you run &lt;code&gt;make deploy&lt;/code&gt;,
your project&amp;rsquo;s name will be prepended to &lt;code&gt;controller-manager&lt;/code&gt;, making it unique within a namespace,
much like your old &lt;code&gt;deploy/service_account.yaml&lt;/code&gt;. If you wish to use the old ServiceAccount,
make sure to update all RBAC bindings and your manager Deployment.&lt;/p&gt;
&lt;h3 id=&#34;configuring-your-operator&#34;&gt;Configuring your Operator&lt;/h3&gt;
&lt;p&gt;If your existing project has customizations in &lt;code&gt;deploy/operator.yaml&lt;/code&gt;, they need to be ported to
&lt;code&gt;config/manager/manager.yaml&lt;/code&gt;. If you are passing custom arguments in your deployment, make sure to also update &lt;code&gt;config/default/auth_proxy_patch.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that the following environment variables are no longer used.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OPERATOR_NAME&lt;/code&gt; is deprecated. It is used to define the name for a leader election config map. Operator authors should begin using &lt;code&gt;--leader-election-id&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POD_NAME&lt;/code&gt; has been removed. It was used to enable a particular pod to hold the leader election lock when the Ansible operator used the leader for life mechanism. Ansible operator now uses controller-runtime&amp;rsquo;s leader with lease mechanism.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;exporting-metrics&#34;&gt;Exporting metrics&lt;/h3&gt;
&lt;p&gt;If you are using metrics and would like to keep them exported you will need to configure
it in the &lt;code&gt;config/default/kustomization.yaml&lt;/code&gt;. Please see the &lt;a href=&#34;https://book.kubebuilder.io/reference/metrics.html?highlight=metr#metrics&#34;&gt;metrics&lt;/a&gt; doc to know how you can perform this setup.&lt;/p&gt;
&lt;p&gt;The default port used by the metric endpoint binds to was changed from &lt;code&gt;:8383&lt;/code&gt; to &lt;code&gt;:8080&lt;/code&gt;. To continue using port &lt;code&gt;8383&lt;/code&gt;, specify &lt;code&gt;--metrics-bind-address=:8383&lt;/code&gt; when you start the operator.&lt;/p&gt;
&lt;h3 id=&#34;verify-the-migration&#34;&gt;Verify the migration&lt;/h3&gt;
&lt;p&gt;The project can now be deployed on the cluster by running the command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;make deploy &lt;span style=&#34;color:#000&#34;&gt;IMG&lt;/span&gt;&lt;span style=&#34;color:#ce5c00;font-weight:bold&#34;&gt;=&lt;/span&gt;example.com/memcached-operator:v0.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can troubleshoot your deployment by checking the container logs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;kubectl logs deployment.apps/memcached-operator-controller-manager -n memcached-operator-system -c manager
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For further steps regarding the deployment of the operator, creation of custom resources, and cleaning up of resources, see the &lt;a href=&#34;/docs/building-operators/ansible/tutorial/#run-the-operator&#34;&gt;tutorial&lt;/a&gt;.&lt;/p&gt;

      </description>
    </item>
    
    <item>
      <title>Docs: Ansible Based Operator Reference</title>
      <link>/docs/building-operators/ansible/reference/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/docs/building-operators/ansible/reference/</guid>
      <description>
        
        
        
      </description>
    </item>
    
  </channel>
</rss>
