Cloud Ops Auto Remediation: A Holiday Allegory
Tags: cloudops, devops, spotify, christmasmusic
Published: 2022-12-16 01:59:23

---
title: Cloud Ops Auto Remediation: A Holiday Allegory
published: true
date: 2022-12-07 16:04:45 UTC
tags: cloudOps, DevOps, Spotify, ChristmasMusic
canonical_url: https://unskript.com/cloud-ops-auto-remediation-a-holiday-allegory/
---

Auto remediations <strong>are tools that respond to events with automations able to fix, or remediate, the underlying condition.</strong> Building a demo that features auto remediation fix is hard, because generally modern infrastructure is resilient so keeping it in an error state is difficult. In order to feature an auto-remediation example, we’re going to get a little creative.
<p>
</p>
<div tabindex="0" role="button">
<div><img decoding="async" loading="lazy" role="presentation" src="https://miro.medium.com/max/1400/1*FJ7IGm5Skfq0dPn3TrWlDg.jpeg" alt="" width="700" height="438"></div>
</div>

<h1 id="0e46" data-selectable-paragraph="">A Holiday Auto Remediation</h1>
<p id="2b96" data-selectable-paragraph="">I am writing this post in the first week of December, and let’s face it — holiday music is pretty inescapable this time of year. To describe the auto remediation that we will fix, let’s turn to one of the greatest fiction writers of our time:</p>
<p>
</p>
<div tabindex="0" role="button">
<div><img decoding="async" loading="lazy" src="https://miro.medium.com/max/1400/1*3_lBdiVbEMhhGkSq2YD1aA.jpeg" alt="Stephen King tweets that he dislikes “Holly Jolly Christmas.”" width="700" height="226"></div>
</div>

<p id="391c" data-selectable-paragraph="">As Mr. King has clearly presented — everyone has a least favorite holiday song, and the playing of this song can . During the holiday season, it is pretty common to use playlists generated by other users on Spotify. Wouldn’t it be great if we could auto remediate the playing of our disliked holiday songs automatically — without any intervention?</p>
<p id="95c4" data-selectable-paragraph="">This is a great example of building auto remediation — an xRunBook in unSkript that identifies the song playing, and if there is an “error state” (a song on the blocklist), the RunBook will correct this issue without human intervention.</p>
<h1 id="4cfb" data-selectable-paragraph="">Auto Remediation in Spotify</h1>
<p id="61f1" data-selectable-paragraph="">In this post, we will build an auto remediation RunBook for your Spotify account.</p>
<ol>
<li id="b46a" data-selectable-paragraph="">We will create a Spotify app that connects with unSkript.</li>
<li id="5417" data-selectable-paragraph="">Curate a block list of songs.</li>
<li id="dd15" data-selectable-paragraph="">We will build a xRunBook that checks to see if Spotify is playing.</li>
<li id="bb57" data-selectable-paragraph="">If Spotify is playing a song on the block list, unSkript will automatically remediate the issue by skipping to the next track.</li>
<li id="be91" data-selectable-paragraph="">We can then place this xRunBook on a schedule to run every minute- ensuring that we’ll only hear a few seconds of our least favourite songs (at least when listening on *our* Spotify account). Note: This last step is only possible in the <a href="https://github.com/unskript/Awesome-CloudOps-Automation" target="_blank" rel="noopener ugc nofollow">Open Source Docker build</a>, or in a SAAS install of unSkript. This won’t work in the sandbox <img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f641.png" alt="🙁" style="height: 1em; max-height: 1em;">
</li>
</ol>
<p id="7158" data-selectable-paragraph="">Let’s get started:</p>
<h1 id="7def" data-selectable-paragraph="">Build a Spotify app</h1>
<p id="f843" data-selectable-paragraph="">In order to interface with Spotify, we <a href="https://developer.spotify.com/dashboard/applications" target="_blank" rel="noopener ugc nofollow">create an app</a> at Spotify.</p>
<p id="5e3b" data-selectable-paragraph="">When you create an app, you’ll need to submit a redirect url. I used <a href="https://unskript.com/" target="_blank" rel="noopener ugc nofollow">unskript.com</a> in my example. Once you generate the app, you’ll get a clientId and clientSecret that you will need later to interface with your xRunBook. You can also add your account email as an authorized user of the application:</p>
<p>
</p>
<div tabindex="0" role="button">
<div><img decoding="async" loading="lazy" src="https://miro.medium.com/max/1400/1*5AIO8ckjaDV3amJB0v9_vA.jpeg" alt="Screenshot of the Spotify app" width="700" height="364"></div>
</div>

<p id="0375" data-selectable-paragraph="">The name and description of my Spotify application gives away *my* reasoning for this app.</p>
<h1 id="6a7d" data-selectable-paragraph="">Building the xRunBook</h1>
<p id="7e2c" data-selectable-paragraph="">NOTE: For full automation, install <a href="https://github.com/unskript/Awesome-CloudOps-Automation" target="_blank" rel="noopener ugc nofollow">unSkript locally using Docker</a>. If you just want to follow along the tutorial, you can use our <a href="https://us.app.unskript.io/" target="_blank" rel="noopener ugc nofollow">free Sandbox</a> to run the xRunBook manually. (If you are using the Sandbox, complete the tutorial.)</p>
<p id="7f0c" data-selectable-paragraph="">Now we are ready to create our xRunBook.</p>
<ul>
<li id="28c0" data-selectable-paragraph="">In Sandbox, Click xRunBook, and then “+Create”, and connect your RunBook to the proxy you created in the tutorial.</li>
<li id="49f4" data-selectable-paragraph="">In Docker, there are instructions to create a new xRunBook in the README file.</li>
</ul>
<p id="44bc" data-selectable-paragraph="">xRunBooks are based on Jupyter Notebooks. Each action is an independent Python application. When the RunBook is executed, each Action is run in order. I have pasted the code for each action below. You’ll need to create a new Action for each code snippet. Do this by Clicking the + Add button at the top, and choosing “Action.”</p>
<p id="a218" data-selectable-paragraph=""><strong>Action 1: Install Spotipy</strong></p>
<p id="b47a" data-selectable-paragraph="">We’re going to use a Python library to interact with Spotify. In your first action:</p>
<pre><span id="0ea3" data-selectable-paragraph="">!pip install spotipy - quiet</span></pre>
<p id="a59d" data-selectable-paragraph=""><strong>Action 2: Add our ClientIds.</strong></p>
<p id="fee2" data-selectable-paragraph="">In the OSS, and Sandbox, there is no built in Secret vault. so we’ll put them here. Make sure the redirect url matches what you placed in your Spotify application/</p>
<pre><span id="3a77" data-selectable-paragraph="">client_id = <span>"&lt;client ID from Spotify&gt;"</span>
client_secret=<span>"&lt;secret from Spotify"</span>
client_redirect=<span>"https://unskript.com"</span></span></pre>
<p id="fea9" data-selectable-paragraph=""><strong>Action 3: Connect to Redis</strong></p>
<p id="f195" data-selectable-paragraph="">Note: not needed for Docker, and will not work for Sandbox, but this will work in unSkript SAAS:</p>
<pre><span id="28c8" data-selectable-paragraph=""><span>import</span> redis
redis = redis.Redis(host=<span>'&lt;redis-host&gt;'</span>, port=<span>6379</span>, db=<span>0</span>)
redis.<span>set</span>(<span>'foo'</span>, <span>'bar'</span>)
<span>True</span>
redis.get(<span>'foo'</span>)
<span>b'bar'</span>
<span>print</span>(redis)</span></pre>
<p id="9e10" data-selectable-paragraph="">Spotipy stores the authentication in a local cache — which is fine in the unSkript Docker instance.</p>
<p id="8730" data-selectable-paragraph="">The Sandbox does not have a local cache, nor a Redis instance, so this xRunBook cannot be run on a schedule as a result.</p>
<p id="1209" data-selectable-paragraph="">In our SAAS version, a Redis database can be attached to the xRunBook to ensure that the credentials are stored locally, and can be reused.</p>
<p id="9414" data-selectable-paragraph=""><strong>Action 4: Find SongIDs</strong></p>
<p id="c758" data-selectable-paragraph="">Let’s do some searches in the Spotify database to extract the songIds we want to add to our blocklist. Here we are searching for songs sung by Mariah Carey:</p>
<pre><span id="73a8" data-selectable-paragraph=""><span>import</span> spotipy
<span>from</span> spotipy.oauth2 <span>import</span> SpotifyClientCredentials

scope = <span>"user-library-read user-modify-playback-state user-read-playback-state"</span>

sp = spotipy.Spotify(auth_manager=SpotifyClientCredentials(client_id=client_id,
                                               client_secret=client_secret))

results = sp.search(q=<span>'mariah carey'</span>, limit=<span>5</span>)
<span>#print(results)</span>
<span>for</span> idx, track <span>in</span> <span>enumerate</span>(results[<span>'tracks'</span>][<span>'items'</span>]):
    <span>print</span>(idx, track[<span>'artists'</span>][<span>0</span>][<span>'name'</span>], <span>" "</span>, track[<span>'name'</span>], <span>" "</span> ,track[<span>'id'</span>])</span></pre>
<p id="d33a" data-selectable-paragraph="">The results for this Action are:</p>
<pre><span id="8994" data-selectable-paragraph=""><span>0</span> Mariah Carey <span>All</span> <span>I</span> Want for Christmas Is You <span>0</span>bYg9bo50gSsH3LtXe2SQn
<span>1</span> Mariah Carey Fantasy <span>6</span>xkryXuiZU360Lngd4sx13
<span>2</span> Mariah Carey Christmas (Baby Please Come Home) <span>3</span>PIDciSFdrQxSQSihim3hN
<span>3</span> Mariah Carey We Belong Together <span>3</span>LmvfNUQtglbTrydsdIqFU
<span>4</span> Mariah Carey Fantasy (feat. O.D.B.) <span>2</span>itAOPLerxnnc8KXHMqPWu</span></pre>
<p id="e795" data-selectable-paragraph="">We want to (ok, I want to) block the song with ID: 0bYg9bo50gSsH3LtXe2SQn.</p>
<p id="4758" data-selectable-paragraph=""><strong>Action 5: Build a block list</strong></p>
<p id="036b" data-selectable-paragraph="">This Action defines the array of songs we want to block.</p>
<pre><span id="5640" data-selectable-paragraph="">songList = [<span>"0bYg9bo50gSsH3LtXe2SQn"</span>, 
            <span>"4iHNK0tOyZPYnBU7nGAgpQ"</span>,
            <span>"0SorhWEyl6wkQ6vYAQt2D0"</span>]</span></pre>
<p id="e867" data-selectable-paragraph=""><strong>Action 6: Authenticate the user</strong></p>
<p id="09fd" data-selectable-paragraph="">This requests access for a user at Spotify. We need to read the playback state (is Spotify playing?), and we need permission to modify the state (skip the song!).</p>
<p id="f3ff" data-selectable-paragraph="">We have commented out the Redis cache_handler. If you are using the SAAS version of unSkript — remove the comment.</p>
<pre><span id="e3b1" data-selectable-paragraph=""><span>import</span> spotipy
<span>from</span> spotipy.oauth2 <span>import</span> SpotifyOAuth
<span>import</span> json

scope = <span>"user-library-read user-modify-playback-state user-read-playback-state user-read-recently-played"</span>

spUser = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=client_id,
                                               client_secret=client_secret,
                                               redirect_uri=client_redirect,
                                              <span># cache_handler=spotipy.cache_handler.RedisCacheHandler(redis),</span>
                                               scope=scope,
                                               open_browser=<span>False</span>))</span></pre>
<p id="0f30" data-selectable-paragraph=""><strong>Action 7: Skip the track</strong></p>
<p id="ae40" data-selectable-paragraph="">This step will be interactive. When this action is run, you’ll be asked to visit a url (that does a redirect) and then paste in the redirected url. This url has your authentication token in it. Once this is done, a token is stored locally that is valid for one hour. Every time the xRunBook is run, the token is re-authenticated for another hour.</p>
<pre><span id="617a" data-selectable-paragraph=""><span>#get current track</span>
currentTrack = spUser.current_user_playing_track()

<span>## only test the playback if there is currently a song playing</span>
<span>if</span> currentTrack <span>is</span> <span>not</span> <span>None</span>:
    <span>#</span>
    track = currentTrack[<span>"item"</span>][<span>"uri"</span>]
    <span>print</span>(track)
    <span>#remove 'spotify:track:' from front of string to get the ID</span>
    track = track[<span>14</span>:]
    <span>print</span>(track)

    <span># all i want for christmas is you. spotify:track:0bYg9bo50gSsH3LtXe2SQn</span>
    songs_i_hate = songList

    <span>for</span> song <span>in</span> songs_i_hate:
        <span>print</span>(<span>"song"</span>, song)
        <span>if</span> track == song:
          <span>print</span>(<span>"ahhh save us"</span>)
          spUser.next_track()
          <span>break</span>
        <span>else</span>:
          <span>print</span>(<span>"its all good"</span>)
<span>else</span>:
    <span>print</span>(<span>"the music is off"</span>)</span></pre>
<p id="9b61" data-selectable-paragraph="">This completes the xRunBook creation. Save the RunBook (by closing it, and then selecting Save)</p>
<p id="26bf" data-selectable-paragraph=""><strong>Scheduling the RunBook</strong></p>
<p id="fe91" data-selectable-paragraph="">In the SAAS (and Sandbox), it is possible to schedule your xRunbooks. By scheduling this xRunBook to run every minute — you can ensuyre that you’ll never have to listen to more than 59 seconds of the songs you dislike.</p>
<h1 id="5fbe" data-selectable-paragraph="">A Holiday Allegory</h1>
<p id="7ac0" data-selectable-paragraph="">An Allegory is a metaphor that symbolizes an idea or message. Many stories told at Christmas time are allegories (like Dicken’s a Christmas Carol). In this post, we have used Spotify playlists as an allegory to a Cloud System in distress. By auto-skipping songs, our unSkript RunBook is automatically solving a situation without involving a human (potentially paging them out of a “long winder’s nap.”)</p>
<p id="fc0e" data-selectable-paragraph="">By building a “Skip the horrible track” auto remediation, we show the power of unSkript, and also potentially save the family Christmas by avoiding arguments over the Christmas playlist.</p>
<p id="2c41" data-selectable-paragraph="">Interested in learning more about how unSkript can help you build internal auto remediation tooling for your team? Check out our <a href="https://us.app.unskript.io/signup" target="_blank" rel="noopener ugc nofollow">free trial</a>, star our <a href="https://github.com/unskript/Awesome-CloudOps-Automation" target="_blank" rel="noopener ugc nofollow">GitHub repository</a> of xRunBooks and Actions, or join our <a href="https://communityinviter.com/apps/cloud-ops-community/awesome-cloud-automation" target="_blank" rel="noopener ugc nofollow">Slack Community</a>!</p>