Like many of you, I have an account on our Oracle Cloud "always free" tier that I use for hosting personal projects, most notably my personal blog recursive.codes. After importing a large amount of content recently I noticed that I was starting to be billed a few dollars ($2-4) every month. Since I'm an incredibly cheap person I decided to see what I could do to get that cost down. One of the easiest ways to reduce object storage costs is to reduce the number of bytes being stored, so I decided to write a quick script to do just that.
What?! You don't have an account on the Oracle Cloud "always free" tier yet? What are you waiting for? You can get 2 Autonomous DB instances, 2 VMs, Object Storage, and much more. For FREE!
I will explain the script below, but for those who are wondering it is written using the Groovy programming language. Groovy is an optionally typed, dynamic JVM language (that offers static compilation as well) and I've been using it to write both web applications and for simple scripting tasks for the last 9 years. If you've worked with Gradle or Jenkins, you've probably already written some Groovy and you just might not have known it. If you're a Java user, this script will look familiar to you for the most part. The only tricky bit might be the
each closure which is one of the collection method add-ons to the List class in the GDK. If you're looking to learn more about then you should certainly refer to the documentation.
I usually create a project that is used for common scripts that utilizes a Gradle build file to pull in any necessary dependencies. We can run any Groovy file via Gradle with some simple setup. In this case, my project is for scripts that utilize the OCI Java SDK so I have the following
build.gradle in the project root directory.
Then I add a task for each individual script in the project directory so I can run them individually. Here's the task for my
ResizeImages.groovy script (that resides in the
The script begins with the creation of an auth provider object and an object storage client instance. It's easiest to use a
ConfigFileAuthenticationDetailsProvider, especially if you're already using the OCI CLI locally since you'll have an existing config file to point at.
Confused? Groovy doesn't require the use of semi-colons. You won't miss them, trust me!
Next, declare a few variables to contain your object storage namespace and the name of the bucket you want to operate on.
def can be used to define a variable without declaring it's type ahead of time. You can even change the type later on by assigning a value of a different type!
Now I create the ListObjectsRequest (indicating that we want the "size" field returned along with each item) and pass the listObjectsRequest to the listObjects method on the client. This gives us back a ListObjectsResponse that we'll iterate over next.
Now we can iterate over the response using the
each closure that Groovy adds to
Within the closure, we receive the current list item, in this case, an
ObjectSummary containing information about the object. If the object is larger than 500kb then we'll construct a
GetObjectRequest to retrieve the object, then resize the image by 50%, save a copy locally in case something happens, then craft and send a
PutObjectRequest to overwrite the previous image. Certainly, I could have added more logic to make sure the object was a valid image first, but in this case, I know for a fact that all of the items in my bucket were either JPG or PNG. Here's the fully populated loop.
So what did this do for me? Pictures and graphs often tell a better story than words, so let's look at my bucket metrics for the past 7 days:
As you can see, the total bucket size was reduced from around 205MB to around 71MB. This will easily result in approximately 65% cost savings for me every month. Which means I've got about an extra dollar or two to spend every month. Yeah!!!
Check out the entire script on GitHub!
A few weeks ago, I blogged about a utility that I created that helps you debug your serverless functions in the Oracle Cloud. The code behind that project...
I've worked on many software projects over the last 16 years, and one thing that each of those projects had in common was the existence of an environment...
Working with serverless functions represents a new way of thinking for many developers. Dealing with stateless functions, for example, can be a challenge...