Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Aws Tool Kit Laravel Package

draw/aws-tool-kit

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Package:

    composer require draw/aws-tool-kit
    

    Ensure your Laravel project uses PHP 8.1+ and Symfony 6.4+ components.

  2. Register Commands: Add the package's commands to Laravel's app/Console/Kernel.php:

    protected $commands = [
        \Draw\AwsToolKit\Command\CloudWatchLogsCommand::class,
        \Draw\AwsToolKit\Command\NewestInstanceRoleCommand::class,
    ];
    
  3. Configure AWS SDK: Publish the package's config (if available) or set AWS credentials in .env:

    AWS_ACCESS_KEY_ID=your-access-key
    AWS_SECRET_ACCESS_KEY=your-secret-key
    AWS_DEFAULT_REGION=us-east-1
    
  4. First Use Case: Download CloudWatch logs for an RDS slow query log:

    php artisan draw:aws:cloud-watch-logs:download \
      /aws/rds/cluster/prod-dbcluster/slowquery \
      prod-1 \
      ./storage/app/logs/slow-query.log
    

    For appending logs to an existing file:

    php artisan draw:aws:cloud-watch-logs:download \
      /aws/rds/cluster/prod-dbcluster/slowquery \
      prod-1 \
      ./storage/app/logs/slow-query.log \
      --fileMode=a+
    

Implementation Patterns

1. CloudWatch Logs Integration

  • Scheduled Log Aggregation: Use Laravel's task scheduling to automate log downloads:

    // app/Console/Kernel.php
    protected function schedule(Schedule $schedule)
    {
        $schedule->command('draw:aws:cloud-watch-logs:download {log-group} {log-stream} {output-path}')
                 ->dailyAt('03:00')
                 ->withoutOverlapping();
    }
    

    Call it dynamically with parameters:

    php artisan schedule:run
    
  • Event-Driven Processing: Extend the package to dispatch events after log download:

    // Extend CloudWatchLogsCommand
    protected function handleDownload()
    {
        // ... existing logic ...
        event(new LogsDownloaded($this->logGroup, $this->logStream, $this->outputPath));
    }
    

    Listen for the event in Laravel:

    // app/Providers/EventServiceProvider.php
    protected $listen = [
        LogsDownloaded::class => [
            HandleLogsDownloaded::class,
        ],
    ];
    
  • Queue-Based Processing: Wrap the command in a job for async execution:

    // app/Console/Commands/DownloadCloudWatchLogsJob.php
    use Draw\AwsToolKit\Command\CloudWatchLogsCommand;
    
    class DownloadCloudWatchLogsJob implements ShouldQueue
    {
        public function handle()
        {
            $command = new CloudWatchLogsCommand();
            $command->handle(
                $this->logGroup,
                $this->logStream,
                $this->outputPath,
                $this->fileMode
            );
        }
    }
    

    Dispatch the job from a controller or another command.


2. Auto-Scaling Cron Coordination

  • Command Guard: Use --aws-newest-instance-role to ensure a command runs only on the newest instance:

    php artisan acme:purge-database --aws-newest-instance-role=prod
    

    Extend your command to support the flag:

    // app/Console/Commands/PurgeDatabaseCommand.php
    protected $newestInstanceRole = null;
    
    protected function handle()
    {
        if ($this->newestInstanceRole && !NewestInstanceRole::isNewest($this->newestInstanceRole)) {
            $this->info('Skipping command: not the newest instance.');
            return;
        }
        // ... rest of the logic ...
    }
    
  • Dynamic Role Assignment: Fetch the instance role dynamically in Laravel's bootstrap/app.php:

    $app->singleton(NewestInstanceRole::class, function ($app) {
        return new NewestInstanceRole(env('AWS_INSTANCE_ROLE'));
    });
    
  • Fallback Mechanism: Implement a fallback for when IMDS is unavailable:

    // app/Services/NewestInstanceRole.php
    public function isNewest(string $role): bool
    {
        try {
            return $this->checkImds($role);
        } catch (ImdsException $e) {
            $this->logWarning('IMDS unavailable, falling back to manual check.');
            return $this->manualCheck($role);
        }
    }
    

3. Service Container Integration

  • Bind AWS SDK Client: Register the AWS SDK client in Laravel's service container:

    // config/aws.php
    'default' => [
        'region' => env('AWS_DEFAULT_REGION'),
        'version' => 'latest',
        'credentials' => [
            'key' => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
        ],
    ];
    

    Bind the client in a service provider:

    // app/Providers/AwsServiceProvider.php
    public function register()
    {
        $this->app->singleton(Aws\S3\S3Client::class, function ($app) {
            return new Aws\S3\S3Client($app['config']['aws.default']);
        });
    }
    
  • Dependency Injection: Inject the AWS client into your commands or services:

    // app/Console/Commands/DownloadCloudWatchLogsCommand.php
    public function __construct(
        private readonly CloudWatchLogsClient $logsClient
    ) {}
    

4. Testing Patterns

  • Mock AWS Services: Use moto for local AWS mocking in tests:

    composer require moto/moto
    

    Example test:

    use Moto\MotoMock;
    use Moto\Aws\CloudWatchLogs;
    
    public function testCloudWatchLogsDownload()
    {
        MotoMock::mock([CloudWatchLogs::class]);
    
        $this->artisan('draw:aws:cloud-watch-logs:download', [
            'logGroup' => '/aws/rds/test',
            'logStream' => 'test-stream',
            'instance' => 'test-1',
            'output' => './tmp/test.log',
        ])->assertExitCode(0);
    
        $this->assertFileExists('./tmp/test.log');
    }
    
  • Unit Test Commands: Test command logic in isolation:

    public function testNewestInstanceRole()
    {
        $command = new NewestInstanceRoleCommand();
        $command->setNewestInstanceRole('prod');
    
        $this->assertFalse($command->isNewestInstance());
        // Mock IMDS response to return true
        $this->partialMock(NewestInstanceRole::class, function ($mock) {
            $mock->shouldReceive('isNewest')->andReturn(true);
        });
    
        $this->assertTrue($command->isNewestInstance());
    }
    

Gotchas and Tips

Pitfalls

  1. AWS Credential Conflicts:

    • Issue: The package may conflict with Laravel's default AWS SDK configuration or other packages like fruitcake/laravel-cors.
    • Fix: Explicitly lock versions in composer.json:
      "require": {
          "aws/aws-sdk-php": "^3.171",
          "guzzlehttp/guzzle": "^7.4"
      }
      
  2. IMDS Unavailability:

    • Issue: The --aws-newest-instance-role flag relies on AWS Instance Metadata Service (IMDS), which can be unavailable or slow.
    • Fix: Implement retry logic with jitter:
      public function isNewestInstance(string $role): bool
      {
          $retries = 3;
          $delay = 100; // ms
      
          for ($i = 0; $i < $retries; $i++) {
              try {
                  return $this->checkImds($role);
              } catch (ImdsException $e) {
                  if ($i === $retries - 1) throw $e;
                  usleep($delay * pow(2, $i));
              }
          }
      }
      
  3. Log Stream Locking:

    • Issue: CloudWatch log streams can be locked by other processes, causing timeouts or failures.
    • Fix: Add exponential backoff to the download command:
      use Symfony\Component\HttpClient\RetryableHttpClient;
      use Symfony\Component\HttpClient\RetryStrategy;
      
      $client = new RetryableHttpClient(
          new RetryStrategy(3, 1000, true, true),
          $httpClient
      );
      
  4. File Permission Issues:

    • Issue: The command may fail to write logs to the specified output path due to permissions.
    • Fix: Ensure the Laravel storage directory is writable:
      chmod -R
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
craftcms/url-validator
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony