Commit f4a4c944 authored by Carolina Gilabert's avatar Carolina Gilabert

Adding frontend.

parent 61828c52
......@@ -5,4 +5,12 @@
.terraform/
#Temp zip of the lambda code
lambda_code.zip
\ No newline at end of file
lambda_code.zip
#Node modules
node_modules/
#Frontend cache & node modules
frontend/.cache/
frontend/node_modules/
frontend/public/
\ No newline at end of file
The MIT License (MIT)
Copyright (c) 2019 Carolina Gilabert
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# Object finder
Proving out a static-site -> ALB -> lambda -> s3 flow to retrieve objects and display on a UI.
module.exports = {
siteMetadata: {
title: `Object Finder`,
description: `Proving out a static-site -> ALB -> lambda -> s3 flow to retrieve objects and display on a UI.`,
author: `Carolina Gilabert`,
},
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`
],
}
This diff is collapsed.
{
"dependencies": {
"gatsby": "^2.0.118",
"gatsby-image": "^2.0.29",
"gatsby-plugin-manifest": "^2.0.17",
"gatsby-plugin-offline": "^2.0.23",
"gatsby-plugin-react-helmet": "^3.0.6",
"gatsby-plugin-sharp": "^2.0.20",
"gatsby-source-filesystem": "^2.0.20",
"gatsby-transformer-sharp": "^2.1.13",
"prop-types": "^15.6.2",
"react": "^16.8.0",
"react-dom": "^16.8.0",
"react-helmet": "^5.2.0"
}
}
import { Link } from "gatsby"
import PropTypes from "prop-types"
import React from "react"
const Header = ({ siteTitle }) => (
<header
style={{
background: `rebeccapurple`,
marginBottom: `1.45rem`,
}}
>
<div
style={{
margin: `0 auto`,
maxWidth: 960,
padding: `1.45rem 1.0875rem`,
}}
>
<h1 style={{ margin: 0 }}>
<Link
to="/"
style={{
color: `white`,
textDecoration: `none`,
}}
>
{siteTitle}
</Link>
</h1>
</div>
</header>
)
Header.propTypes = {
siteTitle: PropTypes.string,
}
Header.defaultProps = {
siteTitle: ``,
}
export default Header
This diff is collapsed.
import React from "react"
import PropTypes from "prop-types"
import { StaticQuery, graphql } from "gatsby"
import Header from "./header"
import "./layout.css"
const Layout = ({ children }) => (
<StaticQuery
query={graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`}
render={data => (
<>
<Header siteTitle={data.site.siteMetadata.title} />
<div
style={{
margin: `0 auto`,
maxWidth: 960,
padding: `0px 1.0875rem 1.45rem`,
paddingTop: 0,
}}
>
<main>{children}</main>
<footer>
© {new Date().getFullYear()}, Built with 💛 by
{` `}
<a href="https://twitter.com/CarolSaysThings" target="_blank">Carolina Gilabert</a>
</footer>
</div>
</>
)}
/>
)
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default Layout
import React from "react"
import PropTypes from "prop-types"
import Helmet from "react-helmet"
import { StaticQuery, graphql } from "gatsby"
function SEO({ description, lang, meta, keywords, title }) {
return (
<StaticQuery
query={detailsQuery}
render={data => {
const metaDescription =
description || data.site.siteMetadata.description
return (
<Helmet
htmlAttributes={{
lang,
}}
title={title}
titleTemplate={`%s | ${data.site.siteMetadata.title}`}
meta={[
{
name: `description`,
content: metaDescription,
},
{
property: `og:title`,
content: title,
},
{
property: `og:description`,
content: metaDescription,
},
{
property: `og:type`,
content: `website`,
},
{
name: `twitter:card`,
content: `summary`,
},
{
name: `twitter:creator`,
content: data.site.siteMetadata.author,
},
{
name: `twitter:title`,
content: title,
},
{
name: `twitter:description`,
content: metaDescription,
},
]
.concat(
keywords.length > 0
? {
name: `keywords`,
content: keywords.join(`, `),
}
: []
)
.concat(meta)}
/>
)
}}
/>
)
}
SEO.defaultProps = {
lang: `en`,
meta: [],
keywords: [],
}
SEO.propTypes = {
description: PropTypes.string,
lang: PropTypes.string,
meta: PropTypes.array,
keywords: PropTypes.arrayOf(PropTypes.string),
title: PropTypes.string.isRequired,
}
export default SEO
const detailsQuery = graphql`
query DefaultSEOQuery {
site {
siteMetadata {
title
description
author
}
}
}
`
import React from "react"
import Layout from "../components/layout"
import SEO from "../components/seo"
const NotFoundPage = () => (
<Layout>
<SEO title="404: Not found" />
<h1>NOT FOUND</h1>
<p>You just hit a route that doesn&#39;t exist... the sadness.</p>
</Layout>
)
export default NotFoundPage
import React from "react"
import Layout from "../components/layout"
import SEO from "../components/seo"
const IndexPage = () => (
<Layout>
<SEO title="Home" keywords={[`gatsby`, `application`, `react`]} />
<h1>Hi people</h1>
<p>I'm trying to get a static site in an S3 talking to an ALB that targets a lambda, to access the contents of another S3 bucket.</p>
<p>Let's see what happens.</p>
</Layout>
)
export default IndexPage
{
"name": "object-finder",
"version": "0.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"aws-sdk": {
"version": "2.400.0",
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.400.0.tgz",
"integrity": "sha512-FJjRXajLnI52F0C1E4nFARk/907x4ZuffwFd6jiBQfaepT03wsY1PcJNEQ5CNHYA2qxAx4HezL2pKySEX+g87g==",
"requires": {
"buffer": "4.9.1",
"events": "1.1.1",
"ieee754": "1.1.8",
"jmespath": "0.15.0",
"querystring": "0.2.0",
"sax": "1.2.1",
"url": "0.10.3",
"uuid": "3.3.2",
"xml2js": "0.4.19"
}
},
"base64-js": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
"integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw=="
},
"buffer": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
"requires": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4",
"isarray": "^1.0.0"
}
},
"events": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
},
"ieee754": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
"integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"jmespath": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
"integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
},
"punycode": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
"integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
},
"querystring": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
},
"sax": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
"integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o="
},
"url": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz",
"integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=",
"requires": {
"punycode": "1.3.2",
"querystring": "0.2.0"
}
},
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
},
"xml2js": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
"integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~9.0.1"
}
},
"xmlbuilder": {
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
}
}
}
{
"name": "object-finder",
"private": true,
"description": "Proving out a static-site -> ALB -> lambda -> s3 flow to retrieve objects and display on a UI.",
"version": "0.1.0",
"author": "Carolina Gilabert <carolgilabert@gmail.com>",
"license": "MIT",
"scripts": {
"build": "rm lambda_code.zip && zip -X lambda_code.zip index.js",
"deploy": "npm run build && terraform apply"
"build:site": "gatsby build --build-dir frontend && node upload_site.js",
"build:lambda": "rm lambda_code.zip && zip -X lambda_code.zip index.js",
"deploy": "npm run build:site && npm run build:lambda && terraform apply"
},
"repository": {
"type": "git",
"url": "https://gitlab.com/carolgilabert/object-finder"
},
"bugs": {
"url": "https://gitlab.com/carolgilabert/object-finder/issues"
},
"dependencies": {
"aws-sdk": "^2.400.0"
}
}
\ No newline at end of file
}
......@@ -150,3 +150,44 @@ resource "aws_lb_listener" "object_finder_alb_listener" {
target_group_arn = "${aws_lb_target_group.object_finder_target_group.arn}"
}
}
resource "aws_s3_bucket" "frontend" {
bucket = "carolgilabert-object-finder-frontend"
acl = "public-read"
tags {
Name = "Object Finder"
Environment = "production"
}
cors_rule {
allowed_headers = ["*"]
allowed_methods = ["GET","POST"]
allowed_origins = ["*"]
expose_headers = ["ETag"]
max_age_seconds = 3000
}
policy = <<EOF
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "PublicReadForGetBucketObjects",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::carolgilabert-object-finder-frontend/*"
}
]
}
EOF
website {
index_document = "index.html"
error_document = "404.html"
}
}
const AWS = require("aws-sdk");
const fs = require("fs");
const path = require("path");
const config = {
s3BucketName: 'carolgilabert-object-finder-frontend',
folderPath: 'frontend/public'
};
const s3 = new AWS.S3({ signatureVersion: 'v4' });
const distFolderPath = path.join(__dirname, config.folderPath);
const deleteObject = (deleteParams) => {
s3.deleteObject(deleteParams, function (err, data) {
if (err) {
console.log("delete err " + deleteParams.Key);
} else {
console.log("deleted " + deleteParams.Key);
}
});
};
const emptyBucket = () => {
s3.listObjects({ Bucket: config.s3BucketName }, function (err, data) {
if (err) {
console.log("error listing bucket objects " + err);
return;
}
var items = data.Contents;
for (var i = 0; i < items.length; i += 1) {
var deleteParams = { Bucket: config.s3BucketName, Key: items[i].Key };
deleteObject(deleteParams);
}
});
};
const getFileContentType = (extension) => ({
'.js': 'text/javascript',
'.json': 'application/json',
'.css': 'text/css',
'.webmanifest': 'text/plain',
'.map': 'text/plain',
'.html': 'text/html',
'.png': 'image/png'
}[extension] || 'text/plain');
const uploadFiles = (folderPath, prefix) => {
fs.readdir(folderPath, (err, files) => {
if (err) { throw err; }
if (!files || files.length === 0) {
console.log(`provided folder '${distFolderPath}' is empty or does not exist.`);
console.log('Make sure your project was compiled!');
return;
}
for (const fileName of files) {
const filePath = path.join(folderPath, fileName);
if (fs.lstatSync(filePath).isDirectory()) {
uploadFiles(filePath, prefix + '/' + fileName);
continue;
}
fs.readFile(filePath, (error, fileContent) => {
if (error) { throw error; }
const s3Key = prefix ? `${prefix.substr(1)}/${fileName}` : fileName;
s3.putObject({
Bucket: config.s3BucketName,
Key: s3Key,
Body: fileContent,
ContentType: getFileContentType(path.extname(fileName))
}, (err, data) => {
console.log(`Uploading '${fileName}'!`);
console.log(err, data);
});
});
}
});
};
emptyBucket();
uploadFiles(distFolderPath, '');
console.log('Uploaded! :)');
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment