Forge: How to cd into /var/log/nginx when permission is denied by the default user

I have a server on DigitalOcean setup by Forge to host a Laravel¬†power project. Things are good then the site goes down. Hmm, let’s check the logs. Logs are located at /var/log/nginx for access and error but… I can’t cd into nginx. ūüôĀ Big. ol. Frown. Face.

The platform re-emerged and I vowed to return to the issue again. I did, after the thing went down again. Still no cd’ing into nginx. Not even a sudo cd which, after reading an article, is a nonsensical command.

So here’s the solution.

sudo su cd /var/log/nginx

sudo su allows you to run all commands as root. Something I didn’t know how to do with Forge as you get a sudo password but not a root user. Now that we are root we can cd¬†into nginx. All is good.

IMPORTANT!!! Don’t run a command as root unless you have to. sudo su back to your user account (ex: sudo su forge) before going back to hacking your way through ubuntu jungle.

Unit Testing with a real Laravel UploadedFile object

I’ve tried, off and on, to unit test file upload objects in various Laravel projects with no real success. I don’t want to mock it and I don’t want to acceptance test a form. It doesn’t exist yet. I want a real file to so I can make calls over it to make sure I get all the data out I need.¬†That I can detect an image,¬†manipulate it¬†using various packages, see the results and tweak till I’m happy¬†and know that it is working when it goes into the app. In short, I’m TDD’ing the API of an object. If that makes sense.

In any case, after much Googling, testing, documentation look up and reading code I figured it out. Hopefully it helps someone else too.

Here’s the code and a bit of explaination…

/* Get byte size of file by doing the following at bash du -b FILENAMEHERE.JPG */ $file = \Illuminate\Http\UploadedFile::createFromBase( (new Symfony\Component\HttpFoundation\File\UploadedFile( __DIR__ . '/files/img_test_file.jpg', 'img_test_file.jpg', 'image/jpeg', 1993588, null, true )) );

When a file is uploaded to Laravel, a¬†Symfony component creates a UploadedFile object form the $_FILE global. This object changes hands several times and ends up being converted to Laravel’s UploadedFile object. Then it is on to being dropped into the Request object¬†that you can pick up in controllers and such.

What this code does is manually create the Symfony object and then manually converts that over to¬†Laravel’s UploadedFile object. Fun. The arguments you see in the Symfony object instantiation are…

  1. path to the file on disk. I stored it¬†in a folder named¬†“files” in the same directory as the test.
  2. file name.
  3. mime type.
  4. size of the file in bytes.
  5. how I feel inside. Actually it is number of errors. Same thing.
  6. boolean confirming that this is being used for testing.

I hope this makes someones day. I almost laid a golden egg when this emerged from my night of profanity.

Happy coding.

Configuring MailGun with DigitalOcean’s DNS

So, this had me cussing the heavens for about 3 days. If you’ve found this post, you’ll know exactly what I mean. When setting up a MailGun domain, DNS entries are required to verify your domain with the service. The default entries, as provided by MailGun, may work great for other DNS providers however they do not work out-of-the-box with DigitalOcean‘s DNS management. This is how you’ll need to tweak them to get your domain verified.

Note: If you’re going with¬†the subdomain route as advised by MailGun, you do not need to setup a new¬†domain in DigitalOcean (Networking > Domains). You can¬†use your domain name’s DNS records.

mailgun-domain_records

TXT Records

The provided TXT records are required to send mail through MailGun. Each record has a name and a text value. For the rest of this article, “domain.com” is just a placeholder for your domain name and I’ll show both top level (“domain.com”) and subdomain (“mg.domain.com”) implementations.

Record 1
dns-do-txt-rec1

The first record’s name will be something like:

// top level domain.com // subdomain mg.domain.com

Instead, remove the domain name like so:

// top level becomes @ // subdomain becomes mg

Add double quotes to the text value:

// mailgun v=spf1 include:mailgun.org ~all // you'll use "v=spf1 include:mailgun.org ~all"

Save the record.

Record 2
dns-do-txt-rec2

Follow the same pattern for the next record:

// top level // - mailgun mx._domainkey.domain.com // - you'll enter mx._domainkey // subdomain // - mailgun mx._domainkey.mg.domain.com // - you'll enter mx._domainkey.mg

Note: Your string may not include “_domainkey.” Don’t worry, just use whatever MailGun gives you in its place and remove “domain.com”.

Modify the text value by wrapping it in double quotes:

// MailGun k=rsa; p=REALLYLONGSTRINGHERE // You'll Enter "k=rsa; p=REALLYLONGSTRINGHERE"

Text records are done. Almost home.

DNS Tracking Record

On to the tracking cname

dns-do-cname-rec1

// top level // - MailGun email.domain.com // - You'll Enter email // subdomain // - MailGun email.mg.domain.com // - You'll Enter email.mg

The only change you’ll make to this cname’s hostname will be to add a period at the end:

// MailGun mailgun.org // You'll Enter mailgun.org.

That’s it. Just wait for propagation and you’re done. I can confirm that both of these methods (domain and subdomain) work as outlined above.

mailgun-do_record_setup

Let me know if you have any questions. Happy MailGunning!

Gnaryly Code – Converting One Bit of Data to Another

I had to convert one set of data to another… and it produced some very gnarly code. So what should we do with code like this?

The Dets

I have a Model called “Customization” which stores details that users provide in order to customize a product. Once that product is paid for and ready to go, the Customization¬†needs to be stored in another model called “Process” in preparation for some time consuming processes behind the scenes.

This conversion from Customization to Process requires knowledge of the the customization, the Product that was customized and all its various relationships, and the format that all this information needs to be reworked into before being saved by the Process model.

Now What?

I could just give the Process model the logic to convert a Customization to a Process but that would have junked up the model, would require that model to know about many other models… quickly turning a maintainable project into something strung together and dependent on each other. Like House of Cards but with far less Spacey.

The Conclusion

I created an adapter class called CustomizationToProcessAdapter, pass it the info it needs, do all the ugly stuff away from prying eyes, and then pass the results back to be saved to Process.

Beautify. Well the code isn’t beautiful… it is quite ugly. But it is contained in something that can be tested and refactored all by itself without breaking anything.

So maybe this TDD stuff is going places…

cause I sure has hell just made a kickass logging trait. Alone I don’t think I could have wrote this straight up as quickly as I did with TDD. Plus, now it is testable for the life of the project. Why the hell haven’t I been doing this all along?!

Here’s a bit of code fo yo ass. Here’s the migration for the logs table:

<?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateLogsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('logs', function (Blueprint $table) { $table->uuid('id'); $table->string('name'); $table->uuid('loggable_id')->nullable(); $table->string('loggable_type')->nullable(); $table->text('body')->nullable(); $table->timestamps(); $table->primary('id'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('logs'); } }
create_logs_table.php

And here the model. Nothing special.

<?php namespace App; class Log extends Base { protected $table = 'logs'; protected $fillable = ['name', 'loggable_id', 'loggable_type', 'body']; public function loggable() { return $this->morphTo(); } }
Log.php

Here is the trait that evolved thanks to TDD

<?php namespace App\Flux\Components; use App\Log; use Carbon\Carbon; trait LoggableTrait { /** * Creating the model relationships to Logs * * @return mixed */ public function logs() { return $this->morphMany(Log::class, 'loggable'); } /** * Log the passed in message by appending to the current log or create a new log entry. * * @param $message * @return $this */ public function log($message) { $name = $this->currentLogName(); $log = $this->logs()->firstOrNew(['name' => $name]); $log->body .= $this->messagePrefix($log->body) . $message; $log->save(); return $this; } /** * Return the current log * * @return mixed */ public function currentLog() { $name = $this->currentLogName(); return $this->logs()->where('name', $name)->first(); } public function clearLogs() { return $this->logs()->delete(); } /** * Return the current log's name build from the current date and model class name. * * @return string */ protected function currentLogName() { return Carbon::now()->format('Y-m-d') . '_' . strtolower(get_class($this)); } /** * Returns the prefix for the message being added to the log * @param $currentLogBody * @return string */ protected function messagePrefix($currentLogBody) { return ($currentLogBody ? "\n" : "") . $this->logDateTimeStamp(); } /** * The prefixed date time stamp that is added before a log message * * @return string */ protected function logDateTimeStamp() { return Carbon::now()->toDateTimeString() . ' '; } }
LoggableTrait.php

And here is the implementation of that trait

<?php namespace App; use App\Flux\Components\LoggableTrait; class Cluster extends Base { use LoggableTrait; protected $table = 'clusters'; protected $fillable = ['name', 'active', 'status_code']; }
Cluster.php

Pretty neat, huh? Here is the test class that brought this Logging feature about.

<?php use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseTransactions; class ClusterLogTest extends TestCase { use DatabaseTransactions; /** @test */ public function a_cluster_can_create_a_new_log_entry() { $logString = "some text here"; $cluster = factory(App\Cluster::class)->create(); $cluster->log($logString); $log = $cluster->currentLog(); $this->assertStringStartsNotWith("\n", $log->body); $this->assertStringEndsWith($logString, $log->body); } /** @test */ public function a_cluster_can_add_to_an_existing_log() { $logString = "some text here"; $logString2 = "some text here2"; $cluster = factory(App\Cluster::class)->create(); $cluster->log($logString); $cluster->log($logString2); $log = $cluster->currentLog(); $this->assertStringEndsWith($logString2, $log->body); } /** @test */ public function a_cluster_can_remove_all_logs() { $logString = "some text here"; $logString2 = "some text here2"; $logString3 = "some text here3"; $cluster = factory(App\Cluster::class)->create(); $cluster->log($logString); $cluster->log($logString2); $cluster->log($logString3); $cluster->clearLogs(); $log = $cluster->currentLog(); $this->assertEmpty($log); } }
ClusterLogTest.php

Am I doing this right? I have no idea. What I do know is that I started out needing the ability to log and now I have a trait I can slap on any model to store logs on. Back in the day I would have extended a class to take on this functionality but this is so much better.

Imma keep at it. This was a great start.