1 of 34

Welcome!

Let’s get started…

Kurtis Holsapple

Owner/Operator of Open Function Computers, LLC

kurtis@openfunctioncomputers.com

@ofcopdx@lapubell��https://github.com/lapubellhttps://github.com/open-function-computers-llc

2 of 34

Let me tell you a story...

Oh, you want changes? Ok, let’s find out some things...

  • Where is this app hosted?
  • Who has access to the source code?
  • Where is the source control repo?
  • Is the previous developer still making changes?
  • Why did the previous developer stop working on this app?
  • Any other surprises we should know about?

3 of 34

What we found: 🤦

  • App hosted on Apache/mod_php by PHP 5.4 on 32 bit linux VM (CentOS 5)
  • Prod application not under version control
  • Changes deployed via FTP/SSH
  • SSH root access authenticated via password, not SSH keys
  • No real tests, only boilerplate tests that came with the application framework
  • Application configuration set by string matching on domain, not working correctly
  • All debug stack traces were being displayed in browser
  • Password hashing not secure (MD5 hashes)
  • So much application logic coupled to the server
    • Static asset reading/writing on the app server filesystem
    • Emails sent via local sendmail
    • Custom qmail binary to write emails to the app DB instead of the default /var/spool/mail location
    • PDF generation done with system calls to WKHTMLTOPDF (again, custom compiled)
  • Outdated/EOL versions galore
    • Can’t use Letsencrypt, outdated OpenSSL system version
    • MySQL 5.0
    • PHP 5.4
    • App Framework Yii 1.1.8 (latest release is 1.1.21)
    • … and so much more

Server issues

App issues

Possible Abstractions

  • App hosted on Apache/mod_php by PHP 5.4 on 32 bit linux VM (CentOS 5)
  • Prod application not under version control
  • Changes deployed via FTP/SSH
  • SSH root access authenticated via password, not SSH keys
  • No real tests, only boilerplate tests that came with the application framework
  • Application configuration set by string matching on domain, not working correctly
  • All debug stack traces were being displayed in browser
  • Password hashing not secure (MD5 hashes)
  • So much application logic coupled to the server
    • Static asset reading/writing on the app server filesystem
    • Emails sent via local sendmail
    • Custom qmail binary to write emails to the app DB instead of the default /var/spool/mail location
    • PDF generation done with system calls to WKHTMLTOPDF (again, custom compiled)
  • Outdated/EOL versions galore
    • Can’t use Letsencrypt, outdated OpenSSL system version
    • MySQL 5.0
    • PHP 5.4
    • App Framework Yii 1.1.8 (latest release is 1.1.21)
    • … and so much more

4 of 34

What we found: 🤦

Server issues

App issues

Possible Abstractions

5 of 34

Let’s get to work! 🔨

  • Step 1: Work local!
    • Get app code to development machine: scp user@server:/var/www/ .
    • Start using version control: git init
    • Serve it: php -S localhost:8000 (or whatever port you want)
    • Dive in!
    • 🤞
  • Step 2: Debug local/dev environment
    • Fix any FATAL errors - php version, $_ENV, etc
    • Set up remote connections (db server, static assets server, etc)
  • Step 3: Modernize and test
    • Update stuff and start abstracting
    • Minio (self hosted Amazon S3 compatible object storage)
    • MailCatcher (local SMTP development service)
    • WKHTMLTOPDF-AAS (docker image to generate PDF files via HTTP API)

6 of 34

Except, no.

7 of 34

so many issues...

  • Older versions of the framework can’t run on PHP 7.2+
  • Can’t update framework because of numerous UI issues
  • Can’t update system PHP without really getting into the internals of their current VM, no easy rollback in case something goes terribly wrong
  • Can’t move the application until we find all the ways it’s tied to the system configuration
  • and more...

8 of 34

How should we move forward? 🤔

There is a lot to consider.�Rebuild vs. refactor?

Ditch the project vs. continue down the rabbit hole?

Budget and timeline constraints?

9 of 34

If we can’t easily fix it, can we avoid it?

10 of 34

Server issues

11 of 34

Possible Abstractions

12 of 34

How do we catch only what we want?

New App

Conditional traffic flow

  • Reverse Proxy
  • Middleware
  • Other

Prod App

REQUEST

RESPONSE

?

13 of 34

Do something besides

$response->send()

14 of 34

Two possible solutions

📞

🤝

15 of 34

Either way, we want to log the routes that aren’t caught by the new app and slowly transition them to the new application

16 of 34

📞 Solution

STEP 1:

Instead of showing 404 page, log the requested route

STEP 2:

Request same route from old app

(guzzle, cURL, etc...)

STEP 3:

Return response from old app, even if it’s a 404 there too

17 of 34

📞 Solution

New App Server

Prod App Server

REQUEST:

GET /hello.htm HTTP/1.1

User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)

Host: www.coolapp.biz

Accept-Language: en-us

Accept-Encoding: gzip, deflate

Connection: Keep-Alive

REQUEST:

GET /hello.htm HTTP/1.1

User-Agent: Mozilla/4.0 (compatible;

Host: www.coolapp.biz

Accept-Language: en-us

Accept-Encoding: gzip, deflate

Connection: Keep-Alive

404!

RESPONSE:

<!DOCTYPE html>

<html lang="en-US">

<head>

<title>Hello!</title>

<meta charset="utf-8">

...

RESPONSE:

<!DOCTYPE html>

<html lang="en-US">

<head>

<title>Hello!</title>

<meta charset="utf-8">

...

18 of 34

🚧 AUTH! 🚧

📞 Solution

It’s like security is important or something

19 of 34

PHP session accessed via 🍪

📞 Solution

After authenticating the user on the new app, send the same credentials to the old app. Capture the old app’s cookie, and use it whenever requesting data from the old app.

20 of 34

📞 Solution

New App Server

Prod App Server

REQUEST:

POST /auth/login HTTP/1.1

User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)

Host: www.coolapp.biz

Content-Type: application/x-www-form-urlencoded

Accept-Language: en-us

Accept-Encoding: gzip, deflate

Connection: Keep-Alive

username=root&password=secret

RESPONSE:

<!DOCTYPE html>

<html lang="en-US">

<head>

<title>Hello!</title>

<meta charset="utf-8">

...

RESPONSE:

<!DOCTYPE html>

<html lang="en-US">

<head>

<title>Hello!</title>

<meta charset="utf-8">

...

REQUEST:

POST /auth/login HTTP/1.1

User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)

Host: www.coolapp.biz

Content-Type: application/x-www-form-urlencoded

Accept-Language: en-us

Accept-Encoding: gzip, deflate

Connection: Keep-Alive

username=root&password=secret

🍪

21 of 34

PRO TIP!

📞 Solution

Dockerize that old thing and serve it at a weird port, and now it won’t conflict with the new app running on the same machine with standard ports. Network latency is way smaller if served on the same machine!

22 of 34

🤝 Solution

Need to make sure things run on the same system

23 of 34

🤝 Solution

Research time

7.1!

🎉

24 of 34

We now have our dream environment! Automate it?

🤝 Solution

Server issues

25 of 34

Here’s what we did�(both apps need to be the same language):

🤝 Solution

STEP 1:

Instead of showing 404 page, log the requested route

STEP 2:

Bootstrap old app, handle that response inline

STEP 3:

Return response from old app, even if it’s a 404 there too

26 of 34

🤝 Solution

This line appears to do the heavy lifting

27 of 34

🤝 Solution

28 of 34

We got lucky

🤝 Solution

  • Minimal global namespace collisions
  • Only one Laravel Facade needed renaming
  • No autoloader collisions

29 of 34

Where we started

FTP/SSH🤞

30 of 34

Our Current Scenario

git push

Run tests

31 of 34

One quick note

WRITE BROWSER TESTS!

32 of 34

Fun Stuff

Attributions:

33 of 34

Fun Stuff

I’m not affiliated, paid by, employed by, or in any other way connected�to any of the tools or companies discussed in this talk, but there is this:

34 of 34

Time for Q/A?

Wanna see a demo?