Web + Mobile Blog / Berlin http://sebastianviereck.de PHP Freelancer Thu, 10 Oct 2019 09:04:36 +0000 de hourly 1 http://wordpress.org/?v=3.5.1 PHP csv Datei mit Umlauten erstellen für Excel http://sebastianviereck.de/php-csv-datei-umlaute-erstellen-excel/?utm_source=rss&utm_medium=rss&utm_campaign=php-csv-datei-umlaute-erstellen-excel http://sebastianviereck.de/php-csv-datei-umlaute-erstellen-excel/#comments Thu, 10 Oct 2019 08:54:59 +0000 Sebastian Viereck http://sebastianviereck.de/?p=4096-de Weiterlesen ]]> Um eine csv-Datei zu erstellen, in der die Umlaute richtig kodiert sind, muss man in seinem Projekt, welches im Normalfall UTF-8 kodiert ist, die Umlaute nach UTF-16LE kodieren. Diese Kodierung kann von Windows und Mac angezeigt werden.

$file = fopen('file.csv', 'w');
foreach ($rows as $row) {
 $row = array_map(function($cell){
 return mb_convert_encoding($cell, 'UTF-16LE', 'UTF-8');
 }, $row);
 fputcsv($file, $row, ';');
}
fclose($file);
]]>
http://sebastianviereck.de/php-csv-datei-umlaute-erstellen-excel/feed/ 0
Monolog Logging für AWS Cloudwatch Logs konfigurieren http://sebastianviereck.de/monolog-logging-fuer-aws-cloudwatch-logs-konfigurieren/?utm_source=rss&utm_medium=rss&utm_campaign=monolog-logging-fuer-aws-cloudwatch-logs-konfigurieren http://sebastianviereck.de/monolog-logging-fuer-aws-cloudwatch-logs-konfigurieren/#comments Mon, 30 Sep 2019 15:49:07 +0000 Sebastian Viereck http://sebastianviereck.de/?p=4087-de Weiterlesen ]]> Damit die Logs schön formatiert aus einer Symfony 4 Anwendung in AWS Cloudwatch ankommen, muss man Monolog folgendermaßen konfigurieren:

# config/services.yaml
Monolog\Formatter\JsonFormatter:
    calls:
        - [includeStacktraces]

und

# config/packages/prod/monolog.yaml
monolog:
  handlers:
    main:
      type:  stream
      level: error
      path:  '%kernel.logs_dir%/error.log'
      formatter: Monolog\Formatter\JsonFormatter

Danach muss man der Cloudwatch Daemon konfigurieren:

# /etc/awslogs/awslogs.conf
[general]
# Path to the CloudWatch Logs agent's state file. The agent uses this file to maintain
# client side state across its executions.
state_file = /var/lib/awslogs/agent-state

[/var/www/html/var/log/error.prod.log]
datetime_format = [%Y-%m-%d H:%M:%S]
file = /var/www/html/var/log/error.log
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = test_group_name/error_log

und man erhält wunderbare (aggregierte) ErrorLog Informationen in Cloudwatch Logs Insight:

 

 

]]>
http://sebastianviereck.de/monolog-logging-fuer-aws-cloudwatch-logs-konfigurieren/feed/ 0
11 AWS Cloudformation Experten Tricks http://sebastianviereck.de/11-cloudformation-experts-tricks/?utm_source=rss&utm_medium=rss&utm_campaign=11-cloudformation-experts-tricks http://sebastianviereck.de/11-cloudformation-experts-tricks/#comments Thu, 26 Sep 2019 15:06:31 +0000 Sebastian Viereck http://sebastianviereck.de/?p=4071-de Weiterlesen ]]> Bei meiner Arbeit mit Cloudfromation habe ich viel nützliche Tipps gesammelt, die ich gern teilen will.

1. Eine IDE mit Autocomplete verwenden

Für die Jetbrains IDEs wie PHPStorm, Webstorm oder IntelliJ gibt es ein sehr gutes AWS Cloudfromation Plugin namens AWS Cloudfromation von Leonid Shalupov:

AWS Cloudfromation Plugin von Leonid Shalupov

Dieses biete Autocomplete für die IDE an und eine automatische Formatüberprüfung, ob Attribute gesetzt werden, die dort nicht erlaubt sind. Auf diesem weg kann man viele Fehler schon vor dem validieren finden und spart viel Zeit.

AWS Cloudfromation Autocomple

2. AWS-CLI Befehle verwenden

Um die Templates in Cloudfromation zu testen und auch zu deployen sollte man am besten die AWS CLI verwenden um viel Zeit zu sparen.

Die wichtigsten Befehle für Cloudformation sind:

### stack anlegen:
#https://docs.aws.amazon.com/cli/latest/reference/cloudformation/create-stack.html
aws cloudformation create-stack  --template-body file://infrastructure/cloudformation.yml --stack-name myteststack

#### template validieren:
aws cloudformation validate-template --template-body file://infrastructure/cloudformation.yml

### status des stacks abrufen:
aws cloudformation describe-stacks --stack-name myteststack

### update stack
aws cloudformation update-stack --template-body file://infrastructure/cloudformation.yml --stack-name myteststack

### delete stack
aws cloudformation delete-stack --stack-name myteststack

## output ändern:
# json, table, text möglich
aws cloudformation describe-stacks --stack-name myteststack --output=text

3. mehrzeiligen Text lesbar schreiben

files:
  /var/www/html/public/index.php:
    content: >-
      <html>
        <body>
          <h1>Welcome to the AWS CloudFormation PHP Sample</h1>
          <p/>
          <?php
            // Print out the current data and time
            print "The Current Date and Time is: <br/>";
            print date("g:i A l, F j Y.");
          ?>
          <?php  phpinfo(); ?>
        </body>
      </html>
    mode: '000600'
    owner: apache
    group: apache

4. Variablen in Strings verwenden

/etc/httpd/conf.d/http-vhost.conf:
  content: !Sub
    - >-
      <Directory "/var/www/html/public">
         Options Indexes FollowSymLinks
         AllowOverride All
         Require all granted
      </Directory>

      <VirtualHost *:80>
         DocumentRoot "/var/www/html/public"
         ServerName "${Domain}"
      </VirtualHost>
    - { Domain: !Ref Domain }

5. Zwei Stacks zum Testen verwenden

Um Zeit zu sparen verwende ich immer 2 Stacks zum Entwickeln, diese werden abwechseln erstellt und gelöscht, weil sonst auf das Löschen des Stacks gewartet werden muss beim Entwickeln.

CLI Befehle:

aws cloudformation create-stack  --template-body file://infrastructure/cloudformation.yml --stack-name myteststack

aws cloudformation delete-stack --stack-name myteststack
aws cloudformation create-stack  --template-body file://infrastructure/cloudformation.yml --stack-name myteststack2

aws cloudformation delete-stack --stack-name myteststack2
aws cloudformation create-stack  --template-body file://infrastructure/cloudformation.yml --stack-name myteststack

....

6. Der Aufbau eines Cloudfromation Templates

Die wichtigste Seite der Cloudformation Dokumentation ist die für den Aufbau eines Cloudformation Templates.

"Resources": {
  "MyInstance": {
    "Type": "AWS::EC2::Instance",
    "Metadata" : {
      "AWS::CloudFormation::Init" : {
        "config" : {
          "packages" : {
            :
          },
          "groups" : {
            :
          },
          "users" : {
            :
          },
          "sources" : {
            :
          },
          "files" : {
            :
          },
          "commands" : {
            :
          },
          "services" : {
            :
          }
        }
      }
    },
    "Properties": {
      :
    }
  }
}

Hier wird u.a. beschrieben, in welcher Reihenfolge die Konfigurationsabschnitte abgearbeitet werden:

  1. packages
  2. groups
  3. users
  4. sources
  5. files
  6. commands
  7. services

In dieser Reihenfolge sollten auch im Template die Konfigurationsabschnitte definiert werden.

7. Cronjob anlegen in Amazon Linux 2

Hier sind 2 Beispiele, wie man für verschiedene User (root und ec2-user) Crontabs anlegt:

InstallCrontab:
 files:
 /var/spool/cron/root:
 content: !Sub |
 # m h dom mon dow command
 39 1,13 * * * certbot renew --no-self-upgrade > /dev/null 2>&1

 mode: '000600'
 owner: root
 group: root

 /var/spool/cron/ec2-user:
 content: !Sub |
 # m h dom mon dow command
 */5 * * * * /usr/local/bin/aws-scripts-mon/mon-put-instance-data.pl --mem-avail --swap-used --disk-space-avail --disk-path=/ --from-cron > /dev/null 2>&1

 mode: '000600'
 owner: ec2-user
 group: ec2-user

 8. yaml oder json

Cloudformation bietet 2 Formate an, die sich tatsächlich sehr unterscheiden, json und yaml. Ich habe mich für yaml entscheiden, weil da weniger zu schreiben ist und der Syntax besser zu lesen. Allerdings habe ich beim Entiwcklen gemerkt, dass fast alle Fragen auf Stackoverflow in json sind, was einen Nachteil dargestellt hat.

Noch besser ist es allerdings:

9. ein Framework verwenden

Leider endet man immer mit einer riesigen Datei in yaml oder json ohne eine Möglichkeit den Inhalt aufzuteilen oder andere Dateien zu inkludieren.

Deswegn würde ich ein Framework wie lono empfehlen, um den Code einfacher zu halten und übersichtlich.

Die Möglichkeit ein Porjekt auf mehrere Dateien aufzusplitten erleichtert auch die Arbeit mit einem VCS wie GIT.

10. Debugging von EC2 Instanz Fehlern

Leider bekommt man oft die wenig sagende Fehlermeldung:

 "Failed to receive 1 resource signal(s) within the specified duration"

Fehlermeldung in der Cloudwatch Oberfläche

Hier sollte man dann das EC2 System Log aufrufen und nach der richtigen Fehlermeldung suchen nach der Stelle “Cloud-init”:

11. Cloudwatch Alarm erstellen mit CloudWatchMonitoringScripts

Um seine Infrastruktur abzusichern, kann man Cloudwatch Alarme erstellen, die einem z.B. per Email (SNS) benachrichten, wenn die CPU Auslastung zu stark ist oder zu wenig freier RAM-Speicher vorhanden ist oder die Festplatte voll läuft.

Um die Daten für die Festplatte un den RAM zu erhalten, muss man die CloudWatchMonitoringScripts installieren und einen Cronjob einrichten.

Dies kann man mit Cloudfromation wie folgt machen:

InstallAwsCloudwatchAgent:
  commands:
    downloadCloudWatchMonitoringScripts:
      command: "sudo curl -o /tmp/CloudWatchMonitoringScripts-1.2.2.zip  https://aws-cloudwatch.s3.amazonaws.com/downloads/CloudWatchMonitoringScripts-1.2.2.zip"

    unzipCloudWatchMonitoringScripts:
      command: "sudo unzip /tmp/CloudWatchMonitoringScripts-1.2.2.zip -d /usr/local/bin"

  packages:
    yum:
      perl-Switch: []
      perl-DateTime: []
      perl-Sys-Syslog: []
      perl-LWP-Protocol-https: []
      perl-Digest-SHA.x86_64: []
  files:
    /var/spool/cron/root:
      content: !Sub |
        # m h dom mon dow      command
        */5 * * * *   /usr/local/bin/aws-scripts-mon/mon-put-instance-data.pl --mem-avail --swap-used  --disk-space-avail --disk-path=/ --from-cron > /dev/null 2>&1

      mode: '000644'
      owner: root
      group: root

Und man kann dann einen Alarm anlegen:

CPUAlarm:
  Type: AWS::CloudWatch::Alarm
  Properties:
    AlarmName: MyCPUAlarm
    AlarmDescription: CPU alarm for ec2 instance
    AlarmActions:
      - arn:aws:sns:xxx
    MetricName: CPUUtilization
    Namespace: AWS/EC2
    Statistic: Average
    Period: '300'
    EvaluationPeriods: '3'
    Threshold: '50'
    ComparisonOperator: GreaterThanThreshold
    TreatMissingData:  missing
    Dimensions:
      - Name: InstanceId
        Value:
          Ref: WebServerInstance

MemoryAlarm:
  Type: AWS::CloudWatch::Alarm
  Properties:
    AlarmName: MyMemoryAlarm
    AlarmDescription: Memory alarm for ec2 instance
    AlarmActions:
      - arn:aws:sns:xxx
    MetricName: MemoryAvailable
    Namespace: System/Linux
    Statistic: Average
    Period: '300'
    EvaluationPeriods: '3'
    Threshold: '200'
    ComparisonOperator: LessThanOrEqualToThreshold
    TreatMissingData:  missing
    Dimensions:
      - Name: InstanceId
        Value:
          Ref: WebServerInstance

DiskSpaceAlarm:
  Type: AWS::CloudWatch::Alarm
  Properties:
    AlarmName: MyDiskSpaceAlarm
    AlarmDescription: Free Disk Space alarm for ec2 instance
    AlarmActions:
      - arn:aws:sns:xxxx
    MetricName: DiskSpaceAvailable
    Namespace: System/Linux
    Statistic: Average
    Period: '300'
    EvaluationPeriods: '3'
    Threshold: '5'
    ComparisonOperator: LessThanOrEqualToThreshold
    TreatMissingData:  missing
    Dimensions:
      - Name: InstanceId
        Value:
          Ref: WebServerInstance
      - Name: Filesystem
        Value: /dev/xvda1
      - Name: MountPath
        Value: /

 

 

]]>
http://sebastianviereck.de/11-cloudformation-experts-tricks/feed/ 0
Cloudformation reboot einer EC2 Instanz http://sebastianviereck.de/cloudformation-reboot-einer-ec2-instanz/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=cloudformation-reboot-einer-ec2-instanz http://sebastianviereck.de/cloudformation-reboot-einer-ec2-instanz/#comments Wed, 25 Sep 2019 14:38:44 +0000 Sebastian Viereck http://sebastianviereck.de/?p=4068-de Weiterlesen ]]> Damit eine Instanz neu neugestartet wird, nachdem die Einrichtung erfolgt ist, muss man folgende Befehl in die UserData Sektion eintragen im Cloudformation Template:

UserData:
  # is executed as root user
  Fn::Base64:
    !Sub |
      #!/bin/bash -xe
      yum update -y aws-cfn-bootstrap
      /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerInstance --configsets InstallAndRun --region ${AWS::Region}
      /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region}
      reboot
]]>
http://sebastianviereck.de/cloudformation-reboot-einer-ec2-instanz/feed/ 0
AWS Lanbda erstellen eines Route53 A Records Eintrages http://sebastianviereck.de/aws-lanbda-erstellen-eines-route53-records-eintrages/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=aws-lanbda-erstellen-eines-route53-records-eintrages http://sebastianviereck.de/aws-lanbda-erstellen-eines-route53-records-eintrages/#comments Thu, 12 Sep 2019 13:00:34 +0000 Sebastian Viereck http://sebastianviereck.de/?p=4058-de Weiterlesen ]]> Mit Hilfe der folgende Python AWS Lambda Funktion kann man einen A Record in Route53 erstellen/updaten:

import json
import boto3

route53 = boto3.client('route53')

def lambda_handler(event, context):
    print("Received event: " + json.dumps(event, indent=2))
    domain = event['domain']

    route53.change_resource_record_sets(
        HostedZoneId='HostedZoneId',
        ChangeBatch={
            'Comment': 'Update or Insert an A Record',
            'Changes': [
                {
                    'Action': 'UPSERT',
                    'ResourceRecordSet': {
                        'Name': domain,
                        'Type': 'A',
                        'SetIdentifier': domain,
                        'Region': 'region',
                        'ResourceRecords': [
                            {
                                'Value': '1.1.1.1'
                            }
                        ],
                        'TTL': 300
                    }
                }
            ]
        }
    )

 

Dazu muss die Labda Funktion die notwendigen Rechte für Route53 besitzen.

Die Dokumentation ist hier.

Die Funktion kann getestet werden mit:

{
  "domain": "foo.bar.de"
}
]]>
http://sebastianviereck.de/aws-lanbda-erstellen-eines-route53-records-eintrages/feed/ 0
Symfony Switftmailer Mail wird nicht gesendet http://sebastianviereck.de/symfony-switftmailer-mail-wird-nicht-gesendet/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=symfony-switftmailer-mail-wird-nicht-gesendet http://sebastianviereck.de/symfony-switftmailer-mail-wird-nicht-gesendet/#comments Thu, 12 Sep 2019 09:34:00 +0000 Sebastian Viereck http://sebastianviereck.de/?p=4054-de Weiterlesen ]]> Mit dem folgende Befehl kann eine Testmail versendet werden mit Swiftmailer. Falls die Email nicht ankommt, sind die Switftmailer Parameter in config/packages/swiftmailer.yaml wahrscheinlich falsch:

php bin/console swiftmailer:email:send --help

Da die Email mit eine Queue versendet werden, sollte trotzdem in das error_log untersucht werden unter var/log/, darin fand sich bei mir der Grund für mein Versand Problem:

app.ERROR: Exception occurred while flushing email queue: Expected response code 250 but got code "554", with message "554 Message rejected: 
Email address is not verified. The following identities failed the check in region EU-WEST-1: email1, email2

 

]]>
http://sebastianviereck.de/symfony-switftmailer-mail-wird-nicht-gesendet/feed/ 0
AWS Cloudfromation Template YAML Zeilenumbruch http://sebastianviereck.de/aws-cloudfromation-template-yaml-zeilenumbruch/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=aws-cloudfromation-template-yaml-zeilenumbruch http://sebastianviereck.de/aws-cloudfromation-template-yaml-zeilenumbruch/#comments Thu, 12 Sep 2019 08:24:06 +0000 Sebastian Viereck http://sebastianviereck.de/?p=4051-de Weiterlesen ]]> Um einen mehrzeiligen Text in Cloudformation Templates zu platzieren, gibt es eine elegante Lösung – der YAML >- Operator:

/var/www/html/public/index.php:
  content: >-
    <html>
      <body>
        <h1>Welcome to the AWS CloudFormation PHP Sample</h1>
        <p/>
        <?php
          // Print out the current data and time
          print "The Current Date and Time is: <br/>";
          print date("g:i A l, F j Y.");
        ?>
        <?php  phpinfo(); ?>
      </body>
    </html>

Alternativ wird in vielen offiziellen Beispielen das sehr unhandliche Format mit der Join Funktion benutzt:

  /var/www/html/index.php:
    content: !Join
      - ''
      - - |
          <html>
        - |2
            <body>
        - |2
              <h1>Welcome to the AWS CloudFormation PHP Sample</h1>
        - |2
              <p/>
        - |2
              <?php
        - |2
                // Print out the current data and time
        - |2
                print "The Current Date and Time is: <br/>";
        - |2
                print date("g:i A l, F j Y.");
        - |2
              ?>
        - |2
              <?php  phpinfo(); ?>
        - |2
            </body>
        - |
          </html>

 

]]>
http://sebastianviereck.de/aws-cloudfromation-template-yaml-zeilenumbruch/feed/ 0
AWS Opsworks ändert SSH Keys auf EC2 Instanzen http://sebastianviereck.de/aws-opsworks-aendert-ssh-keys-auf-ec2-instanzen/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=aws-opsworks-aendert-ssh-keys-auf-ec2-instanzen http://sebastianviereck.de/aws-opsworks-aendert-ssh-keys-auf-ec2-instanzen/#comments Tue, 10 Sep 2019 07:42:21 +0000 Sebastian Viereck http://sebastianviereck.de/?p=4046-de Weiterlesen ]]> Ich hatte gerade das Problem, dass ich mich nicht mehr mit meinem SSH Key auf meine EC2 Instanz einloggen konnte:

Server refused our key

Ich habe herausgefunden, dass es daran lag, dass ich AWS Opsworks Stacks ausprobiert hatte und genau diesen Key angebeben hatte für den neuen Stack.

Meine Rettung war, dass man sich über die AWS Console auch auf die Instanzen mit SSH verbinden kann ohne das Zertifikat:

Was Opsworks dann getan hat, war die Key von den bestehenden Instanzen zu kopieren und dem root-User, nicht mehr meine ec2-user zuzuteilen.

Dies geschah aber leider auch nicht korrekt, sondern der Key in /root/.ssh/authorized_keys war geändert worden in ein falsches Format durch Opsworks:

command="echo 'Please login as the ec2-user user rather than root user.';echo;sleep 10" xxxxxxxxxxxxxxxxxxxMY SSH Keyxxxxxxxxxxxxxxxxxxx

Um das Login wieder herzustellen, habe ich den Text vor meinem SSH Key entfernt und kopiert nach /home/ec2-user/.ssh/.

Danach müssen noch die passenden Rechte gesetzt werden als ec2-user:

mkdir /home/ec2-user/.ssh
sudo chown -R ec2-user:ec2-user /home/ec2-user/.ssh
chmod 700 /home/ec2-user/.ssh
chmod 600 /home/ec2-user/.ssh/authorized_keys

Danach war das Login wieder möglich. Es sollte nicht vergessen werden, den root SSH Key zu entfernen.

]]>
http://sebastianviereck.de/aws-opsworks-aendert-ssh-keys-auf-ec2-instanzen/feed/ 0
Symfony Sonata Redirect der Root URL in den Adminbereich http://sebastianviereck.de/symfony-sonata-redirect-der-root-url-den-adminbereich/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=symfony-sonata-redirect-der-root-url-den-adminbereich http://sebastianviereck.de/symfony-sonata-redirect-der-root-url-den-adminbereich/#comments Fri, 06 Sep 2019 08:57:19 +0000 Sebastian Viereck http://sebastianviereck.de/?p=4042-de Weiterlesen ]]> Wenn man den User bei der Eingabe im Browser ohne ein Pfad (www.foo.de) zum Adminbereich von Sonata (www.foo.de/admin) weiterleiten will, kann man dies sehr elegant mittels eines Symfony Redirects in der routing.yml tun:

index:
  path: /
  defaults:
    _controller: FrameworkBundle:Redirect:urlRedirect
    path: /admin
    permanent: true
]]>
http://sebastianviereck.de/symfony-sonata-redirect-der-root-url-den-adminbereich/feed/ 0
Windows 10 .svn Ordner löschen http://sebastianviereck.de/windows-10-svn-ordner-loeschen/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=windows-10-svn-ordner-loeschen http://sebastianviereck.de/windows-10-svn-ordner-loeschen/#comments Wed, 04 Sep 2019 08:55:56 +0000 Sebastian Viereck http://sebastianviereck.de/?p=4037-de Weiterlesen ]]> Mit einem einfachen Trick kann man rekursiv alle .svn Ordner finden und löschen.

1. Man verwendet die Windows Explorer Suche mit dem speziellen Syntax:

art:=ordner name: ~.svn

Damit werden nur Ordner gefunden, die den genauen Namen .svn haben. Das Sucher gebnis kann dann einfach gelöscht werden:

]]>
http://sebastianviereck.de/windows-10-svn-ordner-loeschen/feed/ 0