<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Miguel Cabrerizo on Medium]]></title>
        <description><![CDATA[Stories by Miguel Cabrerizo on Medium]]></description>
        <link>https://medium.com/@doncicuto?source=rss-a280a5ff12a4------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*X5GKPGz8xKkJvVqsau7UmQ.png</url>
            <title>Stories by Miguel Cabrerizo on Medium</title>
            <link>https://medium.com/@doncicuto?source=rss-a280a5ff12a4------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 22 Jun 2026 18:01:46 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@doncicuto/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Why did I end up using RDP for Linux remote assistance?]]></title>
            <link>https://doncicuto.medium.com/why-did-i-end-up-using-rdp-for-linux-remote-assistance-ba2987579f2c?source=rss-a280a5ff12a4------2</link>
            <guid isPermaLink="false">https://medium.com/p/ba2987579f2c</guid>
            <category><![CDATA[rmm]]></category>
            <category><![CDATA[uem]]></category>
            <category><![CDATA[rdp]]></category>
            <category><![CDATA[self-hosted]]></category>
            <category><![CDATA[remote-assistance]]></category>
            <dc:creator><![CDATA[Miguel Cabrerizo]]></dc:creator>
            <pubDate>Sat, 05 Apr 2025 06:59:23 GMT</pubDate>
            <atom:updated>2025-04-05T06:59:23.742Z</atom:updated>
            <content:encoded><![CDATA[<p>OpenUEM has been created to offer an IT inventory manager with a clean and concise user interface. As a sysadmin, offering remote assistance is part of the job.</p><p>In the two weeks sprint for the new OpenUEM release, I’ve been working on the Linux agent for OpenUEM as it was on the top of the roadmap and several users have suggested including it ASAP.</p><p>OpenUEM is going to have a Debian/Ubuntu agent hopefully next week, and one of the things I wanted to offer was remote assistance sharing the user’s desktop.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Vaxmu8CrLJgqVnJKJsWTPg.png" /><figcaption>Remote Assistance for Debian/Ubuntu agents</figcaption></figure><p>OpenUEM wants to use existing technologies and offer a way for orgs without the budget to acquire proprietary solutions so the first choice for remote desktop was VNC as I was already using it for Windows agents.</p><p>Soon I learned that things were not going to be easy as, in recent years, Linux distributions have been using display servers that use <a href="https://en.wikipedia.org/wiki/Wayland_(protocol)">Wayland</a> replacing the aging X11 display servers.</p><p>OpenUEM Linux agents installed on endpoints that still use X11 will have remote assistance based on X11VNC and VNC, and those that use Wayland and Gnome will use <a href="https://github.com/GNOME/gnome-remote-desktop">Gnome Remote Desktop</a> with… RDP.</p><p>Wait, is not <a href="https://en.wikipedia.org/wiki/Remote_Desktop_Protocol">RDP</a> a protocol often related to Microsoft? Well, yes, it is.</p><p>The reason behind using Gnome Remote Desktop is that with Wayland few choices are out there that could offer VNC. Gnome Remote Desktop indeed offers VNC support for your Linux systems, but then I <a href="https://unix.stackexchange.com/questions/792951/supporting-vnc-on-wayland-debian-trixie">found</a> that for <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1075863">Debian</a> and <a href="https://bugs.launchpad.net/ubuntu/+source/gnome-remote-desktop/+bug/1987159">Ubuntu</a>, the VNC support was not included with the packages. So, to avoid future problems for other Linux agents (OpenSUSE, Arch, Fedora…) I finally decided to change VNC for RDP. Following this decision, KRDP will be tested for KDE Plasma desktops.</p><p>That’s why you’ll have to used RDP clients like <a href="https://remmina.org/">Remmina</a>, <a href="https://www.freerdp.com/">XFreeRDP</a> or Windows Remote Desktop to open RDP files that will be generated by OpenUEM which will be also responsible for configuring the RDP service with digital certificates and starting the service for you automatically.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s0A9TeeE5FFHQSByn25xJA.png" /><figcaption>RDP session opened with Remmina</figcaption></figure><p>Please visit <a href="https://openuem.eu">OpenUEM’s project site</a> to know more about this free, open-source and self-hosted solution for your org to manage your endpoints.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ba2987579f2c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why OpenUEM?]]></title>
            <link>https://doncicuto.medium.com/why-openuem-3a03317bb981?source=rss-a280a5ff12a4------2</link>
            <guid isPermaLink="false">https://medium.com/p/3a03317bb981</guid>
            <category><![CDATA[uem]]></category>
            <category><![CDATA[inventory-management]]></category>
            <category><![CDATA[mdm]]></category>
            <category><![CDATA[winget]]></category>
            <category><![CDATA[rmm]]></category>
            <dc:creator><![CDATA[Miguel Cabrerizo]]></dc:creator>
            <pubDate>Thu, 20 Mar 2025 09:09:46 GMT</pubDate>
            <atom:updated>2025-04-10T07:45:07.684Z</atom:updated>
            <content:encoded><![CDATA[<p>After presenting <a href="https://medium.com/@doncicuto/what-is-openuem-3f99a50a49a5">what’s OpenUEM</a> is time to answer another question, why OpenUEM?</p><p>OpenUEM has features that could categorize it as:</p><ul><li>An IT assets inventory</li><li>A unified endpoint management tool (UEM)</li><li>A remote monitoring and management tool (RMM)</li><li>A mobile device management tool (MDM)</li></ul><p>There are many tools out there that do those things, private or open source, so <strong>why another tool</strong>?</p><p>Well, why another car model, why another IA, why another programming language? Because there are different points of view and ways to approach a similar need.</p><p><strong>OpenUEM tries to offer a new way to answer the question</strong> that we, as sysadmins, face every day: <strong>how can I do my job easier?</strong></p><p>I have been a sysadmin for several years and the networks I’ve managed can be considered small to medium-sized. The organizations that I worked with either had no budget, so you were on your own, or were forced to buy expensive tools that were underused and too big for real needs.</p><p><strong>OpenUEM is an open-source project that you can use for free</strong>. OpenUEM is <strong>based on open-source or free tools and protocols that are battle-tested</strong> or backed up by companies. You can use <a href="https://openuem.eu/docs/Console/computers#210-remote-assistance">VNC for remote assistance</a>, <a href="https://openuem.eu/docs/Console/computers#24-logical-disks">SFTP to transfer files</a>, Windows information is gathered thanks to WMI, <a href="https://openuem.eu/docs/Console/profiles">Windows apps and settings are managed using Winget</a>, Linux apps are installed using Flatpak… <strong>All managed by OpenUEM web console and its agents</strong> (Linux agents are coming soon!).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tNOt2OC0Qieto4H8h7_8HA.png" /><figcaption>OpenUEM Console</figcaption></figure><p>If you are the IT administrator of a small company, you may not have spare equipment to install a management tool. If in the future your network grows, you may be concerned about how to migrate the functionality.</p><p><strong>OpenUEM can be installed in a humble desktop machine</strong> with <a href="https://openuem.eu/docs/Installation/Server/windows">Windows 10 Home</a>, <a href="https://openuem.eu/docs/Installation/Server/linux">Debian/Ubuntu Linux</a> or any <a href="https://openuem.eu/docs/Installation/Server/docker">Docker powered environment</a>. If you run a medium-sized or large company, you can use beefier machines and share the load as OpenUEM has <a href="https://openuem.eu/docs/Introduction/architecture">been designed to have distributed components</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/978/1*B-YaoFQHp1dweKdfcx1-jA.png" /><figcaption>OpenUEM Architecture</figcaption></figure><p>Many tools offer a lot of information and features about your endpoints, either you’re overwhelmed with the information provided, that you may not need, or the interface is too complex and needs a course from the company that created the software.</p><p><strong>OpenUEM has a simple UI with concise information about your endpoints and what you can do with them</strong>. <a href="https://openuem.eu">Docs</a> are ready if you need a little help, and you can visit our <a href="https://discord.com/invite/UQNBuNej5u">Discord’s channel</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zOClE9gsL2ry7G0oTttjLw.png" /><figcaption>OpenUEM Computer’s view</figcaption></figure><p>So, <strong>go ahead and try OpenUEM</strong>, help me to shape the project and to improve this project so it can help you to administer your network easily and effortlessly.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3a03317bb981" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What is OpenUEM?]]></title>
            <link>https://doncicuto.medium.com/what-is-openuem-3f99a50a49a5?source=rss-a280a5ff12a4------2</link>
            <guid isPermaLink="false">https://medium.com/p/3f99a50a49a5</guid>
            <category><![CDATA[rmm]]></category>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[sysops]]></category>
            <category><![CDATA[sysadmin]]></category>
            <category><![CDATA[uem]]></category>
            <dc:creator><![CDATA[Miguel Cabrerizo]]></dc:creator>
            <pubDate>Tue, 25 Feb 2025 06:51:27 GMT</pubDate>
            <atom:updated>2025-04-10T05:47:59.334Z</atom:updated>
            <content:encoded><![CDATA[<p>OpenUEM is an open-source tool that allows you to manage your IT assets thanks to its agents and a clean and concise web user interface.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gmIULFi7HDI0Q_a0ALDASw.png" /></figure><p>Ok, I feel a little bad about self-promotion but, as <a href="https://github.blog/open-source/maintainers/5-tips-for-promoting-your-open-source-project/">GitHub suggests me</a>, I’ve invested some time to create a new open-source project, and I’d like to get feedback about the project and how to improve it, so I think that the best way is to show it here.</p><p>I’ve created <a href="https://openuem">OpenUEM</a>, yet another inventory tool, to keep track of my IT assets using agents installed on my endpoints (for now Windows and Debian based distributions) and have some <a href="https://openuem.eu/docs/Introduction/features">features </a>that are important to me like remote file browsing, getting Windows Update and Antivirus status, deploying software via WinGet and Flatpak, remote assistance with VNC from the browser or RDP from remote desktop clients… using existing tools, protocols and libraries to avoid re-inventing the wheel. OpenUEM could be classified as a Remote Monitoring and Managing tool (RMM) or as a Unified Endpoint Management (UEM) tool.</p><p>In the past I used OCS Inventory, a nice open-source tool but I wanted something different with more features, that would make tasks easier, and I decided to create my own self-hosted solution with a clean interface (thanks to <a href="https://franken-ui.dev/">FrankenUI </a>and <a href="https://htmx.org/">HTMX</a>) and a backend created with Go.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*84n4WtNi3lt8znItKPjFRw.png" /></figure><p>OpenUEM can be installed using <a href="https://openuem.eu/docs/Installation/Server/docker">Docker</a>, <a href="https://openuem.eu/docs/Installation/Server/windows">Windows </a>installers and <a href="https://openuem.eu/docs/Installation/Server/linux">Debian/Ubuntu</a> packages hosted in my repository. The only requirement is to have a Postgres database and a DNS service in your LAN.</p><p>I’m preparing more features (automated tasks, remote code execution, RBAC…), but I’d like to create a <a href="https://openuem.eu/docs/Introduction/roadmap">roadmap </a>with those that admins, using other tools, would like to see in OpenUEM if the project is interesting for them.</p><p>I’d love to see your comments and suggestions either here or in the project’s discussions section, and of course if you test it, please any bug report or issue with its installation would be appreciated (a lot).</p><p>Like any other new project, the hard part is getting users to feel interested, visit the project and decide to have a try, so enough of this shameful self-promotion, thanks for reading!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3f99a50a49a5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Connect our Drone CI pipeline containers with other Docker containers]]></title>
            <link>https://doncicuto.medium.com/connect-our-drone-ci-pipeline-containers-with-other-docker-containers-40c7a721c4ff?source=rss-a280a5ff12a4------2</link>
            <guid isPermaLink="false">https://medium.com/p/40c7a721c4ff</guid>
            <category><![CDATA[drone-ci]]></category>
            <category><![CDATA[docker]]></category>
            <dc:creator><![CDATA[Miguel Cabrerizo]]></dc:creator>
            <pubDate>Tue, 29 Dec 2020 18:02:00 GMT</pubDate>
            <atom:updated>2020-12-29T18:02:00.403Z</atom:updated>
            <content:encoded><![CDATA[<p>Drone CI launches its pipeline containers in isolated networks to avoid security problems. If we found an scenario where we want to connect Drone containers with other containers already running in our Docker engine, this is what we could do.</p><p>1) Create a bridge network in Docker. In my example I use drone as my network name:</p><p>`docker network create -d bridge drone`</p><p>2) Connect a running container, the one that you want to be connected from Drone containers, to your new network. In this example, my container is named as our_container_name.</p><p>`docker network connect drone our_container_name`</p><p>3) Launch your Drone Agent runner using the following env variable (Reference: <a href="https://docs.drone.io/runner/docker/configuration/reference/drone-runner-networks/">https://docs.drone.io/runner/docker/configuration/reference/drone-runner-networks/</a>):</p><p>`DRONE_RUNNER_NETWORKS=drone`</p><p>4) Whenever we want our Drone container to get access to a running container use your container name in your url, for example <a href="http://our_container_name">http://our_container_name</a>. Using names, Docker will perform name resolution and thanks to your shared network Drone containers and your Docker containers will be connected.</p><p>In my tests, I tried to use the default Docker bridge named bridge, but it didn’t worked and in any case you may not want to use the default network to avoid external access, so that’s why I chose to create a new bridge network.</p><p>This discussion may help you: <a href="https://discourse.drone.io/t/drone-docker-agents-on-custom-network/3732">https://discourse.drone.io/t/drone-docker-agents-on-custom-network/3732</a></p><p>Hope it helps</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=40c7a721c4ff" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting Started with DynamoDB in Go (Part 3— Create, Read, Update and Delete an Item)]]></title>
            <link>https://doncicuto.medium.com/getting-started-with-dynamodb-in-go-part-3-create-read-update-and-delete-an-item-9c47e6fc984b?source=rss-a280a5ff12a4------2</link>
            <guid isPermaLink="false">https://medium.com/p/9c47e6fc984b</guid>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[dynamodb]]></category>
            <dc:creator><![CDATA[Miguel Cabrerizo]]></dc:creator>
            <pubDate>Wed, 24 Jan 2018 08:22:09 GMT</pubDate>
            <atom:updated>2018-01-24T08:22:09.575Z</atom:updated>
            <content:encoded><![CDATA[<p>In the third part of this <a href="https://medium.com/@doncicuto/getting-started-with-dynamodb-in-go-part-1-a25c5522edd4">tutorial</a> for DynamoDB and Go, where I’m rewriting the Amazon AWS Node.js tutorial for the Go programming language, we’re going to see how to create, read, update and delete an item from our Movies table.</p><p>This post assumes you have a Movies table in your local DynamoDB instance and you have loaded the sample data from a JSON file.</p><p>In my suggested code I’m heavily using the marshal operations that AWS gives me to prepare expressions. In Go we could define an expression like this:</p><pre>ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{<br> “:r”: {<br>   N: aws.String(“0.5”),<br> },<br>},</pre><p>but I prefer to use the marshal operations, for example MarshalMap, to create the map[string]*dynamodb.AttributeValue, as I think the code is clearer and it’s easier to use the <a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_AttributeValue.html">AttributeValues</a>. You have plenty of alternative examples in <a href="https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/using-dynamodb-with-go-sdk.html">Amazon AWS SDK for Go Examples</a> page where the attribute values are defined as above if you prefer that way.</p><p><strong>Step 3.1: Create a new item in our Movies table.</strong></p><p>We’re going to add a new item representing a new movie:</p><pre>{<br>   year: 2015,<br>   title: “The Big New Movie”,<br>   info: { <br>     plot: “Nothing happens at all.”,<br>     rating: 0<br>   }<br>}</pre><p>This is the flow of actions:</p><ul><li>We define a struct for the info and another struct for our movie.</li><li>We create a session for our DynamoDB local server and start a connection.</li><li>We use the utilities that AWS offers to marshal our movie, in this case we use the MarshalMap operation that takes our movie struct and prepares a map of attributevalues that we can use in the PutItem operation.</li><li>We prepare the input for the PutItem operation selecting the Movies table and adding the movie that was marshalled before as the item to be inserted.</li><li>We finally insert the new movie item.</li></ul><p>Here’s the code for our main.go:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b3a1580532e26d2818c4733f5023acbd/href">https://medium.com/media/b3a1580532e26d2818c4733f5023acbd/href</a></iframe><p>I run it</p><pre>go run main.go</pre><p>If the item is inserted we’ll see the following message</p><pre>We have inserted a new item!</pre><p><strong>Step 3.2: Read an item</strong></p><p>Now we’re going to read the item that we’ve just inserted. When we created the table we define two keys.</p><ul><li>Year is our partition key.</li><li>Title is our sort key.</li></ul><p>You may review the <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html">AWS DynamoDB core concepts article</a> if you don’t remember what is a partition key and a sort key.</p><p>We’re going to use both keys to get the item from our table as it was a composite primary key.</p><p>Here’s the flow:</p><ul><li>We define a struct for the movie to be retrieved. The type for the info field has been defined as interface{}, that way I can expect arbitrary data for the movie info. Also I define the info field to be omitted in the JSON object if it’s empty.</li><li>We create a session for our DynamoDB local server and start a connection.</li><li>We prepare a key struct to be marshalled using MarshalMap. The marshalled key is added to key field inside a GetItemInput struct.</li><li>We retrieve the item using the input.</li><li>We get a GetItemOutput that contains an Item field. We unmarshall the item using UmarshallMap and store the content in a Movie struct.</li><li><em>Note:</em> the info field may contain arbitrary data so I can use the method described in the JSON and Go Blog post to retrieve data. If we know what is going to be inside the info field we could define a struct for the info and we could avoid that logic. I feel it was right for this tutorial assuming that we don’t know what’s inside the info field.</li></ul><p>Here’s the code for our main.go</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7911802be0bbe48cda23133b4fb24ab1/href">https://medium.com/media/7911802be0bbe48cda23133b4fb24ab1/href</a></iframe><p>I run it again</p><pre>go run main.go</pre><p>And here’s the result</p><pre>year: 2015<br>title: The Big New Movie<br>rating : 0<br>plot : Nothing happens at all.</pre><p><strong>Step 3.3: Update an Item</strong></p><p>In this step we want to update the previous Item with the following information:</p><pre>{<br>   year: 2015,<br>   title: “The Big New Movie”,<br>   info: { <br>      plot: “Everything happens all at once.”,<br>      rating: 5.5,<br>      actors: [“Larry”, “Moe”, “Curly”]<br>   }<br>}</pre><p>Here’s the flow:</p><ul><li>We define a struct for the key of the movie item to be updated.</li><li>We define a struct that contains which fields are going to be updated. The struct contains json mappings with a name started with a colon, in AWS we use those tokens as placeholders for the info to be updated. For example rating will use :r and plot will use :p. You have more information in the <a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html.">API reference</a>.</li><li>We also create two structs to be used when we unmarshal the data returned by the update operation.</li><li>We create a session for our DynamoDB local server and start a connection.</li><li>We prepare a key struct to be marshalled using MarshalMap. The marshalled key is added to key field inside an UpdateItemInput struct and is used to select which item must be updated.</li><li>We prepare a movieUpdate struct to be marshalled using MarshalMap. The marshalled update info will be added to an UpdateItemInput struct.</li><li>The UpdateItem operation requires the key for the item to be updated and the updated info. Also the UpdateExpression specifies what’s the mapping between the info fields and the tokens prefixed by a colon, similar to a SET clause in SQL. The ReturnValues set to UPDATED_NEW instructs DynamoDB to return only the values that have been updated.</li><li>The UpdateItem operation returns an UpdatedItemOutput which contains an Attributes field with the updated information. We use the UnmarshallMap operation using a MovieInfoUpdated struct to store the unmarshalled fields. Then we can print the new values.</li></ul><p>Here’s the code for our main.go</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/89ecf36c5595da72962762474f7349a0/href">https://medium.com/media/89ecf36c5595da72962762474f7349a0/href</a></iframe><p>And here’s the output for the updated info.</p><pre>Updated plot: Everything happens all at once.<br>Updated rating: 5.5<br>Updated actors: [Larry Moe Curly]</pre><p><strong>Step 3.4: Increment an Atomic Counter</strong></p><p>According to the Node.js tutorial, we are going to increment the rating for a movie using a counter.</p><p>Here’s the flow:</p><ul><li>We define a struct for the key of the movie item to be updated.</li><li>We define a struct that contains the increment for the movie reating field. The struct contains a json mapping with a name started with a colon :val, in AWS we use those tokens as placeholders.</li><li>We also create two structs to be used when we unmarshal the data returned by the update operation.</li><li>We create a session for our DynamoDB local server and start a connection.</li><li>We prepare a key struct to be marshalled using MarshalMap. The marshalled key is added to key field inside an UpdateItemInput struct and is used to select which item must be updated.</li><li>We prepare a MovieRatingInc struct to be marshalled using MarshalMap with the number to be used in the increment operation.</li><li>The UpdateItem operation requires the key for the item to be updated and the updated info. Also the UpdateExpression specifies that rating is going to be incremented by the value we’ve set earlier.</li><li>The UpdateItem operation returns an UpdatedItemOutput which contains an Attributes field with the updated information. We use the UnmarshallMap operation using a MovieInfoUpdated struct to store the unmarshalled fields. Then we can print the new values.</li></ul><p>Here’s the code for our main.go</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1b455a79a48cfe4750b09205c879f461/href">https://medium.com/media/1b455a79a48cfe4750b09205c879f461/href</a></iframe><p>And here’s the output for the updated info, ratings have been increased by 1.</p><pre>Updated rating: 6.5</pre><p><strong>Step 3.5: Update an Item (Conditionally)</strong></p><p>We’re going to update an item from our Movies table. If a movie has more than three actors we will remove the first actor, so we’re going to select a condition as we would use a WHERE clause in SQL.</p><p>Here’s the flow:</p><ul><li>We define a struct for the key of the movie item to be updated.</li><li>We define a struct that contains which is the number of actors to be checked in the condition. The struct contains a json mapping with a name started with a colon :num, in AWS we use those tokens as placeholders.</li><li>We also create two structs to be used when we unmarshal the data returned by the update operation.</li><li>We create a session for our DynamoDB local server and start a connection.</li><li>We prepare a key struct to be marshalled using MarshalMap. The marshalled key is added to key field inside an UpdateItemInput struct and is used to select which item must be updated.</li><li>We prepare a MovieActorsCondition struct to be marshalled using MarshalMap with the number to be used when the number of actors in a movie is checked.</li><li>The UpdateItem operation requires the key for the item to be updated and the updated info. The UpdateExpression defines that we want to remove the first item in the actorrs array. The ConditionExpression specifies that the item will be updated only if the number of actors (size) is greater than 3.</li><li>The UpdateItem operation returns an UpdatedItemOutput which contains an Attributes field with the updated information. We use the UnmarshallMap operation using a MovieInfoUpdated struct to store the unmarshalled fields. Then we can print the new value.</li></ul><p>Here’s the code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dd794537b8dceee2767653500fcf397a/href">https://medium.com/media/dd794537b8dceee2767653500fcf397a/href</a></iframe><p>When we run the code we’ll check that the condition fails as we have only three actors:</p><pre>ConditionalCheckFailedException: The conditional request failed<br> status code: 400, request id: 3d6f2674–7de9–4a8c-ae6e-dfb98b49b691</pre><p>We modify the main.go and change the condition, this time we’ll check size(info.actors) &gt;= 3</p><p>Now when we run the code, we get the updated actors array where the first actor has been removed:</p><pre>Actors updated: [Moe Curly]</pre><p><strong>Step 3.6: Delete an Item</strong></p><p>In this final step we’re going to delete an Item if a condition is met. We’re going to delete an Item if the movie’s rating is lower than 5</p><p>Here’s the flow:</p><ul><li>We define a struct for the key of the movie item to be updated.</li><li>We define a struct that contains which is the rating to be checked in the condition. The struct contains a json mapping with a name started with a colon :val, in AWS we use those tokens as placeholders.</li><li>We also create two structs to be used when we unmarshal the data returned by the update operation.</li><li>We create a session for our DynamoDB local server and start a connection.</li><li>We prepare a key struct to be marshalled using MarshalMap. The marshalled key is added to key field inside a DeletetemInput struct and is used to select which item must be removed.</li><li>We prepare a MovieRatingCondition struct to be marshalled using MarshalMap with the rating to be used in the condition.</li><li>The DeleteItem operation requires the key for the item to be deleted. The ConditionExpression specifies that the item will be removed only if the rating is lower than or equal to 5.0.</li></ul><p>Here’s the code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/deae1294ff4076a0e4264926b53907c0/href">https://medium.com/media/deae1294ff4076a0e4264926b53907c0/href</a></iframe><p>When we run the code our movie has a rating of 6.5 so it’s not deleted:</p><pre>ConditionalCheckFailedException: The conditional request failed<br> status code: 400, request id: 07d86ea1–5d42–4016–9b7e-47a4b1fa0f82</pre><p>If we change the condition so the movie is deleted if the rating is lower than 10, now the item will be deleted.</p><pre>The item has been deleted</pre><p>This concludes the third part of the tutorial. In the next part we’re going to query and scan the data.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9c47e6fc984b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting Started with DynamoDB in Go (Part 2 — Load sample data)]]></title>
            <link>https://doncicuto.medium.com/getting-started-with-dynamodb-in-go-part-2-load-sample-data-61da941e557a?source=rss-a280a5ff12a4------2</link>
            <guid isPermaLink="false">https://medium.com/p/61da941e557a</guid>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[dynamodb]]></category>
            <dc:creator><![CDATA[Miguel Cabrerizo]]></dc:creator>
            <pubDate>Mon, 22 Jan 2018 17:08:36 GMT</pubDate>
            <atom:updated>2018-01-24T08:22:59.888Z</atom:updated>
            <content:encoded><![CDATA[<p>In the second part of this <a href="https://medium.com/@doncicuto/getting-started-with-dynamodb-in-go-part-1-a25c5522edd4">tutorial</a> for DynamoDB and Go where I’m rewriting the Amazon AWS Node.js tutorial for the<a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.html"> Go programming language</a>, I’m adding some data to our Movies table.</p><p>We’ll start downloading the sample file <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/samples/moviedata.zip">provided by Amazon AWS</a> to the directory where our main.go file lives. In the following line I download the zip file using wget, unzip it and remove the file in my Linux machine:</p><pre>wget -O moviedata.zip <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/samples/moviedata.zip">https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/samples/moviedata.zip</a>; unzip moviedata.zip; rm moviedata.zip</pre><p>We’ll now have a moviedata.json file where Amazon AWS is giving us some movies that can be added to our table. This is the JSON structure for one of the movies where year is the partition key and title is used as a sort key, the rest of the information is stored in the info attribute.</p><pre>{<br> “year”: 2013,<br> “title”: “Rush”,<br> “info”: {<br>   “directors”: [“Ron Howard”],<br>   “release_date”: “2013–09–02T00:00:00Z”,<br>   “rating”: 8.3,<br>   “genres”: [<br>     “Action”,<br>     “Biography”,<br>     “Drama”,<br>     “Sport”<br>   ],<br>   “image_url”: “<a href="http://ia.media-imdb.com/images/M/MV5BMTQyMDE0MTY0OV5BMl5BanBnXkFtZTcwMjI2OTI0OQ@@._V1_SX400_.jpg">http://ia.media-imdb.com/images/M/MV5BMTQyMDE0MTY0OV5BMl5BanBnXkFtZTcwMjI2OTI0OQ@@._V1_SX400_.jpg</a>&quot;,<br>   “plot”: “A re-creation of the merciless 1970s rivalry between Formula One rivals James Hunt and Niki Lauda.”,<br>   “rank”: 2,<br>   “running_time_secs”: 7380,<br>   “actors”: [<br>     “Daniel Bruhl”,<br>     “Chris Hemsworth”,<br>     “Olivia Wilde”<br>   ]<br> }<br>}</pre><p>In our main.go file I assume that you’ve created a table in your local DynamoDB as explained in the first part of the tutorial. Now we’ll use Go to read the json file and add the sample data to our Movies table. This is the flow:</p><ul><li>Define a structure that will be used to parse the JSON objects inside the moviedata.json file. The JSON objects have a year which is an integer, a title which is a string and info which is an object. As the info object can have arbitrary attributes as the type for info as explained in the <a href="https://blog.golang.org/json-and-go">JSON and Go blog post</a>.</li><li>Open the JSON file.</li><li>Use the JSON decoder to unmarshal the contents of the moviedata.json file.</li><li>Create a session and a DynamoDB service connection as explained in the first part of <a href="https://medium.com/@doncicuto/getting-started-with-dynamodb-in-go-part-1-a25c5522edd4">this tutorial</a>.</li><li>Loop throught the movies objects parsed from the JSON file.</li><li>For each movie we can use the <a href="https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/dynamodbattribute/#MarshalMap">MarshalMap</a> function from the dynamodbattribute library which helps us to create the map of AttributeValues that Amazon AWS expect as the item to be inserted in the table using the PutItem operation.</li><li>Create a <a href="https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/#DynamoDB.PutItem">PutItem</a> input with the map of AttributeValues which represents the movie and its attributes like year, title and info. Also we specify the name of the table.</li><li>Finally put the item using the input we’ve just created. This operation will create the item in the table. In <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html">DynamoDB’s terminology</a> is a group of attributes that is uniquely identifiable among all of the other items.</li></ul><p>This would be the source code for the main.go file that would populate our table with the sample data.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f9c2419564f5ea751522737f5b4afea4/href">https://medium.com/media/f9c2419564f5ea751522737f5b4afea4/href</a></iframe><p>Now before running our main.go, please run the go get command to download all the required packages.</p><pre>go get</pre><p>And finally go run your main.go</p><pre>go run main.go</pre><p>If the import operation is successful we’ll see a message with the number of records imported:</p><pre>We have processed 4609 records</pre><p>In the <a href="https://medium.com/@doncicuto/getting-started-with-dynamodb-in-go-part-3-create-read-update-and-delete-an-item-9c47e6fc984b">next part of this tutorial</a> we’ll see how we can perform CRUD operations now that our table has some sample data.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=61da941e557a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting Started with DynamoDB in Go (Part 1 — Creating a Table)]]></title>
            <link>https://doncicuto.medium.com/getting-started-with-dynamodb-in-go-part-1-a25c5522edd4?source=rss-a280a5ff12a4------2</link>
            <guid isPermaLink="false">https://medium.com/p/a25c5522edd4</guid>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[dynamodb]]></category>
            <dc:creator><![CDATA[Miguel Cabrerizo]]></dc:creator>
            <pubDate>Mon, 22 Jan 2018 07:57:25 GMT</pubDate>
            <atom:updated>2018-01-22T17:09:14.138Z</atom:updated>
            <content:encoded><![CDATA[<p>Amazon offers some <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.html">DynamoDB tutorials</a> for popular languages like Java, Javascript, Python, Node.js, .NET, PHP and Ruby but not for Go, at least at the moment of writing this post.</p><p>In order to help you discover how you can use Go with DynamoDB I’m rewriting the Node.js tutorial for Go.</p><p>The first prerequisite is downloading and running DynamoDB locally in your computer as explained by <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html">Amazon AWS</a>. It’s great that Amazon AWS gives you the chance to run DynamoDB in your local machine so you can learn how to use it for free.</p><p>I’ve started my DynamoDB using the following java command. DynamoDB will use port 8000 by default but you can use a different port if you want.</p><pre>java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb<br>Initializing DynamoDB Local with the following configuration:<br>Port: 8000<br>InMemory: false<br>DbPath: null<br>SharedDb: true<br>shouldDelayTransientStatuses: false<br>CorsParams: *<br></pre><p>If you’re starting with Go please review the <a href="https://golang.org/doc/code.html">How to Write Code</a> article about where you should store your source code. In this post I’m creating my main.go file inside my $GOPATH/src/github.com/doncicuto/dynamodb_tutorial path.</p><p>Also if it’s the first time you use DynamoDB you may start reading the following <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html">AWS article</a> about the core components of DynamoDB.</p><p><strong>Step 1. Create a Table</strong></p><p>Once we have our DynamoDB instance working locally you can copy and paste the following program into the main.go. The code has the following flow:</p><ul><li>An Amazon configuration struct is created assigning the local endpoint which points to the default port 8000. Region is required but not used in this local example so you can use <a href="https://docs.aws.amazon.com/general/latest/gr/rande.html">any of the available regions</a>, for example us-west-2.</li><li>A new Amazon AWS session is created.</li><li>We create a connection to DynamoDB service using the session we’ve just created.</li><li>Then we create the DynamoDB table definition where two attributes are used for describing a movie: a year and a title. Year will be our partition key and title will be our sort key. We also specify our initial read and write throughput settings. Please read the following Amazon AWS article for more information about DynamoDB Tables management.</li><li>Finally we create the table using our table definition.</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/828bcc498f48b44681e487225bf58372/href">https://medium.com/media/828bcc498f48b44681e487225bf58372/href</a></iframe><p>Now before running our main.go, please run the go get command to download the official <a href="https://github.com/aws/aws-sdk-go">Amazon AWS go sdk</a> (Note that Amazon is preparing a <a href="https://aws.amazon.com/es/blogs/developer/aws-sdk-for-go-2-0-developer-preview/">AWS SDK for Go 2.0)</a>.</p><pre>go get</pre><p>And finally go run your main.go</p><pre>go run main.go</pre><p>If the operation was successful you’ll see the result of creating the table in your local DynamoDB server.</p><pre><br>{<br> TableDescription: {<br> AttributeDefinitions: [{<br> AttributeName: “Year”,<br> AttributeType: “N”<br> },{<br> AttributeName: “Title”,<br> AttributeType: “S”<br> }],<br> CreationDateTime: 2018–01–22 07:21:17 +0000 UTC,<br> ItemCount: 0,<br> KeySchema: [{<br> AttributeName: “Year”,<br> KeyType: “HASH”<br> },{<br> AttributeName: “Title”,<br> KeyType: “RANGE”<br> }],<br> ProvisionedThroughput: {<br> LastDecreaseDateTime: 1970–01–01 00:00:00 +0000 UTC,<br> LastIncreaseDateTime: 1970–01–01 00:00:00 +0000 UTC,<br> NumberOfDecreasesToday: 0,<br> ReadCapacityUnits: 1,<br> WriteCapacityUnits: 1<br> },<br> TableArn: “arn:aws:dynamodb:ddblocal:000000000000:table/Movies”,<br> TableName: “MoviesTest”,<br> TableSizeBytes: 0,<br> TableStatus: “ACTIVE”<br> }<br>}<br></pre><p>In the <a href="https://medium.com/@doncicuto/getting-started-with-dynamodb-in-go-part-2-load-sample-data-61da941e557a">next part of the tutorial</a> we’ll populate the Movies table.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a25c5522edd4" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>