Cloud 9 Make Command Line Appear Again

https://github.com/entmike/hanadev/tree/Part3

Overview

In the third part of this series, I will cover creating a basic Vue frontend to consume our backend service that we created in Part 2.

Prerequisites

  • Cloud 9 set up and configured as described in Part 1
  • Backend created as described in Part 2

Update the .env file

In part 2, we made use of theSYSTEM user to perform a quick test of our backend app. In a real world use case, we of course do not want to do this. So we will designate some new environment variables to specify a new application user and password.

                      HXE_MASTER_PASSWORD=HXEHana1            HANA_APP_UID=APPUSER            HANA_APP_PWD=SomeSecretPassword            HANA_SERVER=hxehost:39017            HANA_APP_BACKEND=/backend                  

Update the docker-compose.yaml file

Open thedocker-compose.yaml file under/hanadev and update the contents as follows:

                      version:            '2'            services:                          hello-world-app:                          build:                          context:            .                          dockerfile:            ./hello-world-app/Dockerfile                          ports:                          -            "3333:9999"                          environment:                          -            HANA_UID=${HANA_APP_UID}                          -            HANA_PWD=${HANA_APP_PWD}                          -            HANA_SERVERNODE=${HANA_SERVER}                          sqlpad:                          image:            sqlpad/sqlpad                          volumes:                          - sqlpad:            /var/lib/sqlpad                          ports:                          -            "8899:3000"                          hxehost:                          image:            store/saplabs/hanaexpress:2.00.036.00.20190223.1                          hostname:            hxe                          volumes:                          - hana-express:            /hana/mounts                          command:            --agree-to-sap-license            --master-password            ${HXE_MASTER_PASSWORD}            volumes:                          hana-express:                          sqlpad:                  

Basically, we've only changed thehello-world-app environment variable mapping ofHANA_UID andHANA_PWD to point to our newHANA_APP_UID andHANA_APP_PWDvariables in our.env files.

Create the Application User

  1. Let's briefly start up our HANA Express DB and SQLPad by typing the following from thehanadev directory in a terminal window.
                  docker-compose up                          
  2. Open up SQLPad fromhttp://[cloud 9 external IP]:8899 and log in with the user you created. Refer to Part 1 if you need a reminder on how to log in.
  3. Create a new SQL statement as follows and clickRun
                                  CREATE                USER                APPUSER                PASSWORD                SomeSecretPassword                NO                FORCE_FIRST_PASSWORD_CHANGE;                          
  4. That's it. We can now stop our Stack by pressingControl + C in the terminal window that you typeddocker-compose up.
  5. Let's start back up our stack one last time and make sure our backend app is now running as our new application user. Rundocker-compose-up -d and wait about 60 seconds for HANA Express to start up.
  6. Next, typecurl -X POST http://localhost:3333/api/overview | grep user. You should get a one line back of the JSON output similar to below:
                                  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current                                  Dload  Upload   Total   Spent    Left  Speed 100  1202  100  1202    0     0  52260      0 --:--:-- --:--:-- --:--:-- 52260                "user":                "APPUSER"                          

    Congratulations! You've successfully modified the backend app to use an application user.

Creating a Vue Project

As I mentioned in Part 1, it's been a long time since playing in web frameworks. While this can be a bit of a divisive Holy War topic, for me, I've gotten particularly fond of Vue. If you are more of an Angular or React person, feel free to replace these steps with your favorite frontend tool and read no further. If you'd like to create a super simple Vue app, read on.

  1. From a terminal window in Cloud 9, typenpm i -g @vue/cli. This will install Vue and the Vue CLI.
  2. Next, since I'm not a big CLI guy, let's start up the GUI for the CLI by typingvue ui -p 8080 from thehanadev/hello-world-app directory (important.) Once you see the status in your terminal below, proceed to the next step.
                  ec2-user:~/environment/hanadev (Part3) $ vue ui -p 8080   Starting GUI...   Ready on http://localhost:8080                          
  3. In the Cloud 9 toolbar, clickPreview ->Preview Running Application. A browser window inside your Cloud 9 IDE should open:
  4. Click theCreate button and then clickCreate a new project here.
  5. ForProject Folder, name itfrontend. ClickNext.
  6. Forpreset, leaveDefault preset select and clickCreate Project. Vue CLI will begin to generate the boilerplate project files under thehanadev/hello-world-app/frontend folder. After a few moments, you should arrive at a screen saying "Welcome to your new project!".
  7. On the left edge of the page, find the puzzle piecePlugins icon and click it. Then, click the+ Add plugin button at the top-left.
  8. We are going to install 2 plugins. A routing plugin and a UI plugin. For the router plugin, there should be aAdd vue-router button placed prominently at the top of the plugins page. Click it, and then clickContinue. Then don't forget to clickFinish installation
  9. After vue-router finishes installing, search forvue-cli-plugin-vuetify. Click on the matching search result and click onInstall vie-cli-plugin-vuetify.
  10. After the installation is complete, click on theTasks icon on the left edge of the page. (Clipboard icon.)
  11. This page serves as a launching point to run vue-cli tasks that you can either opt to use this page to run, or if you are more of a CLI person, you can run from a terminal if you so wish. For now though, let's click onserve and thenRun task.
  12. Once the green checkbox appears, we know that our Vue app is running. Click on theOutput button to monitor the status of our serve task. You should see something similar to the following:
                                  App running                at:     Local:                http://localhost:8081/      Network:                http://172.16                .0                .99:8081/           Note that                the                development build is                not                optimized. To                create                a                production build, run npm run build.            
  13. Since we are running in Cloud 9 IDE, the IP address reported back and hostname are not accessible from your browser. You will want to substitute your Cloud 9 External IDE here. You also will need to expose port80xx (whichever one is mentioned in the output) in our Cloud 9 EC2 instance in order to access this application easier. Refer to steps in Part 1 if you do not know how to do this. I'd recommend opening up ports8080 through8085 as sometimes we may be running more than one app at once and it will save you a trip to the EC2 Dashboard later on.
  14. After noting the80xx port, navigate tohttp://[your cloud 9 external ip]:80xx.
  15. If you get back aWelcome to Your Vue.js App congratulations! We are ready to start coding.

Modifying your Vue Project

Now that we have created the boilerplate Vue Project, we are ready to make some changes to the application. While I am not a Vue expert, and for sake of brevity, I won't be explaining everything that's going on. There are many, many great Vue tutorials online that I'd highly suggest you look for if you are interested in Vue.

  1. In your Cloud 9 IDE, locate the/hanadev/hello-world-app/frontend folder. This is where all your frontend code has now been generated. Modify/Create the following files.
  2. Create Environment Variable files
    1. /hello-world-app/frontend/.env.production:This file will be used for our final productin build. TheVUE_APP_HANA_APP_BACKEND variable tells the frontend app where to issue backend requests to. For production, we'll handle this with Nginx a bit later on.
                                            VUE_APP_HANA_APP_BACKEND=/backend                                  
    2. /hello-world-app/frontend/.env.development.local NOTE: Be sure to add your Cloud 9 External IP address in the placeholder below. For development, we'll want to hit our running Docker stack running in Cloud 9.
                        VUE_APP_HANA_APP_BACKEND=http://[your cloud 9 external ip]:3333                                  
  3. Modify/hello-world-app/frontend/src/main.js
                                  import                Vue                from                'vue'                import                './plugins/vuetify'                import                App                from                './App.vue'                import                router                from                './router'                if(!process.env.VUE_APP_HANA_APP_BACKEND){   alert("VUE_APP_HANA_APP_BACKEND environment variable not set.  Please set your environment and restart this frontend server.") }else{   Vue.config.productionTip =                false                new                Vue({     router,                render:                                  h                  =>                h(App)   }).$mount('#app') }                          
  4. Modify/Create/hello-world-app/frontend/src/router.js
                                  import                Vue                from                'vue'                import                Router                from                'vue-router'                import                Overview                from                './views/Overview.vue'                Vue.use(Router)                export                default                new                Router({                routes: [     {                path:                '/',                name:                'Overview',                component: Overview     }   ] })                          
  5. Modify/hello-world-app/frontend/src/App.vue
                                  <template>                <v-app                  dark>                <AppNav                  :systemInformation="results.backend_information"/>                <v-content                  transition="slide-x-transition">                <router-view                  />                </v-content>                </v-app>                </template>                <script>                                  import                  AppNav                  from                  '@/AppNav';                  import                  axios                  from                  'axios';                  export                  default                  {                  name:                  'App',                  components: {         AppNav     },     data () {                  return                  {                  results: {                  backend_information                  : {                  user                  :                  'dummy'                  }         }       };     },                  methods                  : {       getData (){         axios.post(process.env.VUE_APP_HANA_APP_BACKEND +                  '/api/overview/',{ }).then(                    res=>{                  if(res.data){                  this.results = res.data;                  this.systemInformation = res.data.backend_information;                  // console.log(this.results);                  }else{             alert(JSON.stringify(res));                  this.results = {};           }         }, err=> {           alert(JSON.stringify(err.response.data));         }).catch(                    err=>{           alert(`An error occured communicating with the backend.                    ${err}`);         })       },     },     mounted(){                  this.getData();     } };                                </script>                          
  6. Create/hello-world-app/frontend/src/AppNav.vue
                                  <template>                <v-toolbar                  app                  color="blue darken-4"                  dark>                <v-toolbar-title>{{appTitle}}</v-toolbar-title>                <template                  v-for="(item,index) in items">                <v-btn                  v-if="typeof item.link === 'undefined'"                  :key=index                  flat                  :to="'/' + item.title">{{item.title}}</v-btn>                <v-btn                  v-else                  :key=index                  flat                  :to="'/' + item.link">{{item.title}}</v-btn>                </template>                <v-spacer                  />                <v-chip                  color="primary"                  label                  outline                  text-color="white">{{systemInformation.user}}@{{systemInformation.server}}:{{systemInformation.port}}</v-chip>                </v-toolbar>                </template>                <script>                                  export                  default                  {                  name:                  'AppNav',                  props                  : {                  systemInformation                  :                  Object                  },     data(){                  return{                  appTitle:                  'HANA Sandbox',                  drawer:                  false,                  items: [                 {                  title:                  'Overview',link:                  ''                  }             ]         };     } };                                </script>                <style                  scoped>                </style>                          
  7. Delete any files (About.vue,Home.vue etc.) under/hello-world-app/frontend/src/views
  8. Create/hello-world-app/frontend/src/views/Overview.vue
                                  <template>                <div>                <v-list                  two-line>                <template                  v-for="(item,index) in results.M_SYSTEM_OVERVIEW">                <v-list-tile                  :key="index">                <v-list-tile-content>                <v-list-tile-title                  v-html="item.KEY">                </v-list-tile-title>                <v-list-tile-sub-title                  v-html="item.VAL">                </v-list-tile-sub-title>                </v-list-tile-content>                </v-list-tile>                </template>                </v-list>                </div>                </template>                <script>                                  import                  axios                  from                  'axios';                  export                  default                  {                  name:                  'Overview',                  data:                                      ()                    =>                  ({                  results: []   }),                  components: {},                  methods: {     getData(){       axios.post(process.env.VUE_APP_HANA_APP_BACKEND +                  '/api/overview/',{ }).then(                    res=>{                  if(res.data){                  this.results = res.data;         }else{                  this.results = {};         }       }, err=> {         alert(JSON.stringify(err.response.data));       }).catch(                    err=>{         alert(`An error occured communicating with the backend.                    ${err}`);       })     }   },   mounted(){                  this.getData();   } }                                </script>                          
  9. The theOverview.vue file, we are making use of theaxios npm module, so we will want to install this. To do so, open a terminal window in Cloud 9 and cd to yourfrontend folder. Typenpm i axios to install it.

Running our Frontend App in Developer Mode

If you are still running thevue-cli UI, you can now terminate it by pressingControl + C. We will now demonstrate how to run the same serve task via command line from the terminal.

  1. Make one more trip over to your EC2 Console and expose port3333. This is our backend port that we'll need our browser to hit in order to get back data from our HANA Container running in our Stack while running in Developer mode. For "production" use cases, we will not need this port.
  2. In a terminal window:If your Docker Compose stack is not already running, start it now:
                                  cd                /hanadev docker-compose up                -d                          

    Next, let's start up our frontend app in developer mode.

                                  cd                /hanadev/hello-world-app/frontend` npm run serve                          
  3. After a few moments, you should receive the following feedback in your terminal:"`bash DONE Compiled successfully in 20991ms 18:59:50App running at:
    • Local: http://localhost:8080/
    • Network: http://172.16.0.99:8080/

    Note that the development build is not optimized. To create a production build, run npm run build. "`

  4. Like earlier, disregard the internal IP, and replace it with your Cloud 9 External IP address and navigate tohttp://[your cloud 9 external ip]:80xx where80xx is the port mentioned above.
  5. If all has gone well, you should receive a page titled "HANA Sandbox" with your App User shown at the top right, and your HANA Express system information shown below. If so, congratulations! You've created a frontend app that is consuming your Docker Compose stack's backend service!

Running in this manner allows us to make code changes to our frontend application live in Cloud 9 without deploying over and over again, yet at the same time attaching to our Docker Compose stack's backend app and HANA Express DB. Pretty cool!

After celebrating, terminate the development mode task by pressingControl + C.

Wrapping it up in our Container

For Part 3, we'll consider this a "Milestone" and use this as an opportunity to bundle our frontend application changes into ourdocker-compose.yaml file before we call it a day. We'll need to update a few files to incorporate the frontend app.

  1. Open yourDockerfile located under/hanadev Update it with the following:
                                  # Docker Image containing SAP HANA npm package                FROM                node:8-slim                LABEL                                  Maintainer="Your Name <your.name@example.com>"                                # Install nginx to handle backend and frontend apps                RUN                                  apt-get update && apt-get install -y nginx                                # Add SAP HANA Client NPM package from SAP's npm repository                RUN                                  npm config                  set                  @sap:registry https://npm.sap.com && npm i -g @sap/hana-client                                # Set the global NPM path Environment variable                ENV                NODE_PATH /usr/local/lib/node_modules                # Configure nginx and startup                COPY                                  ./hello-world-app/server.conf /etc/nginx/conf.d/default.conf                                # Copy backend Node JS modu                COPY                                  /hello-world-app/backend /app/backend                                # Copy production build of Vue frontend app                COPY                                  /hello-world-app/frontend/dist /app/frontend                                # Copy startup.sh script                COPY                                  ./hello-world-app/startup.sh /app/startup.sh                                WORKDIR                                  /app                                CMD                                  ./startup.sh                                          

    We are adding 3 new main items here:

    1. Our frontend app's productiondist folder will be copied over to our Docker images's/app/frontend folder. The productiondist folder is an optimized and minified version of our frontend Vue app.
    2. Install Nginx and copy some configuration files to do some reverse proxy magic so that we can just have one single port exposed from our container and to abstract the underlying architecture away.
    3. Copy over astartup.sh script since we'll be launching more than one process for theCMD line.
  2. Createstartup.sh in/hanadev/hello-world-app
                                  #!/bin/sh                echo                "Starting Servers..."                mkdir -p /run/nginx rm /etc/nginx/sites-enabled/default                echo                "Starting nginx..."                nginx                cd                /app/backend                echo                "Starting backend..."                npm run prod                          
  3. Change permissions to executable forstartup.sh from a terminal window
                      cd            /hanadev/hello-world-app    chmod +x startup.sh                  
  1. Createserver.conf in/hanadev/hello-world-app

"`conf

          server {     listen            80            default_server;     # document root #     root        /app/frontend/;      # Route requsts to /backend/ to Backend npm            module            location /backend/ {         proxy_pass http://localhost:9999/;            } } ```                  
  1. Build our Vue frontend app to generate thedist folder.
                                  cd                /hanadev/hello-world-app/frontend npm run build                          

    You should get some feedback similar to this:

                                  > frontend@0.1.0 build /home/ec2-user/environment/hanadev/hello-world-app/frontend  > vue-cli-service build              ⠏  Building                for                production...         WARNING  Compiled with 2 warnings                                                                               19:16:17         warning          entrypoint size                limit: The following entrypoint(s) combined asset size exceeds the recommended                limit                (244      KiB). This can impact web performance.  Entrypoints:    app (303 KiB)        css/chunk-vendors.bc527eeb.css        js/chunk-vendors.2793d0c4.js        js/app.02b450ce.js               warning          webpack performance recommendations:   You can                limit                the size of your bundles by using import() or require.ensure to lazy load some parts of your      application.  For more info visit https://webpack.js.org/guides/code-splitting/          File                                   Size              Gzipped          dist/js/chunk-vendors.2793d0c4.js      180.43 KiB        60.10 KiB    dist/js/app.02b450ce.js                4.87 KiB          2.03 KiB    dist/css/chunk-vendors.bc527eeb.css    118.13 KiB        15.45 KiB          Images and other types of assets omitted.         DONE  Build complete. The dist directory is ready to be deployed.   INFO  Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html                          
  2. Update ourdocker-compose.yaml file under/hanadev:
                                  version:                '2'                services:                                  hello-world-app:                                  build:                                  context:                .                                  dockerfile:                ./hello-world-app/Dockerfile                                  ports:                # - "3333:9999" No longer needed we are using Nginx                # Reroute Nginx listening on Port 80 over to 8080 which we've already exposed in EC2                                  -                "8080:80"                                  environment:                                  -                HANA_UID=${HANA_APP_UID}                                  -                HANA_PWD=${HANA_APP_PWD}                                  -                HANA_SERVERNODE=${HANA_SERVER}                                  sqlpad:                                  image:                sqlpad/sqlpad                                  volumes:                                  - sqlpad:                /var/lib/sqlpad                                  ports:                                  -                "8899:3000"                                  hxehost:                                  image:                store/saplabs/hanaexpress:2.00.036.00.20190223.1                                  hostname:                hxe                                  volumes:                                  - hana-express:                /hana/mounts                                  command:                --agree-to-sap-license                --master-password                ${HXE_MASTER_PASSWORD}                volumes:                                  hana-express:                                  sqlpad:                          
    • Basically all that we've done is removed the backend port (3333) from being accessible, since our Nginx app inside of our Docker container will be reverse-proxying calls to the npm task running there. For development use cases, you may wish to leave this in place for when developing live and not hosting inside a container, or better yet, simply have a separate docker compose stack for when you are developing, and maybe this one that represents "production".
    • Secondly, we're exposing Nginx that is listening on Port80 over to Port8080 since we've already exposed8080 in our EC2 Dashboard, and that will save us a trip and another exposed port.
  3. Rebuild our docker-compose stack:
                                  cd                /hanadev docker-compose build                          

    Note The initial time you run the build it will take longer, as we've added in a few new Docker image layers to account for the new Nginx addition, etc. After 2 minutes or so, you should get a confirmation that the build has finished successfully:

                                  ...      Step 7/11 : COPY /hello-world-app/backend /app/backend  ---> c5c3508dc2a2 Step 8/11 : COPY /hello-world-app/frontend/dist /app/frontend  ---> 6ee34d81d8d5 Step 9/11 : COPY ./hello-world-app/startup.sh /app/startup.sh  ---> 60f38e70da77 Step 10/11 : WORKDIR /app  ---> Running                in                e54ee8b3c9c6 Removing intermediate container e54ee8b3c9c6  ---> df3d269e1dff Step 11/11 : CMD ./startup.sh  ---> Running                in                594e5016ca51 Removing intermediate container 594e5016ca51  ---> 4abedcaed348 Successfully built 4abedcaed348 Successfully tagged hanadev_hello-world-app:latest                          

Moment of Truth

We are now ready to test our new Docker Compose stack.

  1. From/hanadev, type:
                  docker-compose up                          
  2. After about 60 seconds, open a browser tab and visithttp://[your cloud 9 ide external ip]:8080 If you see the HANA Sandbox page with your HANA Express system overview, congratulations! You've successfully containerized your frontend and backend app!

What's Next?

As much as I enjoy creating punishing and grueling tutorial blogs, I'm open for any suggestions or ways to improve subsequent posts. Otherwise, for the next Part, we'll add to this frontend application some additional Vue routes for the frontend app, as well as Express backend routes to feed it.

edwardshasexce.blogspot.com

Source: https://blogs.sap.com/2019/05/20/develop-simple-on-hana-express-in-aws-cloud-9-part-3-the-frontend-app/

0 Response to "Cloud 9 Make Command Line Appear Again"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel