diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..7cf77fe --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,20 @@ +version: "3.0" + +services: + eureka-server: + container_name: eureka + image: springcloud/eureka + ports: + - "8761:8761" + redis: + container_name: redis + image: redis + ports: + - "6379:6379" + mongo: + container_name: mongo + image: mongo + ports: + - "27017:27017" + volumes: + - "${MONGO_VOLUME}:/var/lib/mongodb" \ No newline at end of file diff --git a/docker/kubernetes/ui-interface.yml b/docker/kubernetes/ui-interface.yml index 23dbd88..379d349 100644 --- a/docker/kubernetes/ui-interface.yml +++ b/docker/kubernetes/ui-interface.yml @@ -4,6 +4,13 @@ metadata: name: ui-interface data: application.yaml: |- + ribbon: + eureka: + enabled: false + client: + enabled: true + ServerListRefreshInterval: 50 + spring: cloud: gateway: diff --git a/docker/mongo.yml b/docker/mongo.yml deleted file mode 100644 index 9ea08ff..0000000 --- a/docker/mongo.yml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: mongo -spec: - replicas: 1 - selector: - matchLabels: - app: mongo - template: - metadata: - labels: - app: mongo - spec: - containers: - - name: mongo - image: mongo - imagePullPolicy: "IfNotPresent" - ports: - - containerPort: 27017 - ---- - -kind: Service -apiVersion: v1 -metadata: - name: mongo-svc -spec: - selector: - app: mongo - ports: - - port: 27017 \ No newline at end of file diff --git a/docker/starter.sh b/docker/starter.sh new file mode 100644 index 0000000..73d5207 --- /dev/null +++ b/docker/starter.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +docker-compose up 2>docker.log & + +cd .. + +PROJECT_HOME=`pwd` + +HELLO_SERVICE_JAR_DIR=$PROJECT_HOME/hello-service/build/libs +MESSAGE_SERVICE_JAR_DIR=$PROJECT_HOME/message-service/build/libs +UI_JAR_DIR=$PROJECT_HOME/ui/target + +echo "The content of PROJECT_HOME is: $PROJECT_HOME" +echo "The content of HELLO_SERVICE_JAR_DIR is: $HELLO_SERVICE_JAR_DIR" +echo "The content of MESSAGE_SERVICE_JAR_DIR is: $MESSAGE_SERVICE_JAR_DIR" +echo "The content of UI_JAR_DIR is: $UI_JAR_DIR" + + +echo "start of hello-service" +cd $HELLO_SERVICE_JAR_DIR +java -jar -Dspring.profiles.active=netflix hello-service.jar >$PROJECT_HOME/hello-service.log & + + +echo "start of message-service" +cd $MESSAGE_SERVICE_JAR_DIR +java -jar -Dspring.profiles.active=netflix message-service.jar >$PROJECT_HOME/message-service.log & + + +#echo "start of ui" +#cd $UI_JAR_DIR +#java -jar -Dspring.profiles.active=netflix ui-interface.jar >$PROJECT_HOME/ui-interface.log & diff --git a/hello-service/build.gradle b/hello-service/build.gradle index e8cec9e..495921f 100644 --- a/hello-service/build.gradle +++ b/hello-service/build.gradle @@ -27,11 +27,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-webflux' implementation 'org.springframework.boot:spring-boot-starter-actuator' - - implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes' - implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-config' - implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-ribbon' - + compile 'org.projectlombok:lombok:1.18.6' testImplementation 'org.springframework.boot:spring-boot-starter-test' @@ -52,3 +48,5 @@ docker { pull true noCache true } + +apply from: rootProject.file('profile.gradle'); \ No newline at end of file diff --git a/hello-service/profile.gradle b/hello-service/profile.gradle new file mode 100644 index 0000000..3854b4c --- /dev/null +++ b/hello-service/profile.gradle @@ -0,0 +1,12 @@ +if (project.hasProperty('kubernetes')) { + println("kubernetes") + dependencies { + implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes' + implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-config' + } +} else if (project.hasProperty('netflix')) { + println("netflix") + dependencies { + implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' + } +} \ No newline at end of file diff --git a/hello-service/profiles/kubernetes_build.gradle b/hello-service/profiles/kubernetes_build.gradle new file mode 100644 index 0000000..8986dc6 --- /dev/null +++ b/hello-service/profiles/kubernetes_build.gradle @@ -0,0 +1,4 @@ +dependencies { + implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes' + implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-config' +} \ No newline at end of file diff --git a/hello-service/profiles/netflix_build.gradle b/hello-service/profiles/netflix_build.gradle new file mode 100644 index 0000000..f6b40be --- /dev/null +++ b/hello-service/profiles/netflix_build.gradle @@ -0,0 +1,3 @@ +dependencies { + implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' +} \ No newline at end of file diff --git a/hello-service/src/main/kubernetes/hello-service-k8s.yml b/hello-service/src/main/kubernetes/hello-service-k8s.yml deleted file mode 100644 index 6ac9b75..0000000 --- a/hello-service/src/main/kubernetes/hello-service-k8s.yml +++ /dev/null @@ -1,85 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: hello-service-config - labels: - app: hello-service -data: - hello-service-uri: "http://message-service/message/random" - ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: hello-service-deployment - labels: - app: hello-service -spec: - replicas: 3 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 25% - selector: - matchLabels: - app: hello-service - template: - metadata: - labels: - app: hello-service - spec: - containers: - - name: hello-service - image: mrflick72/hello-service:latest - ports: - - containerPort: 8080 - - livenessProbe: - httpGet: - path: /actuator/health - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 5 - successThreshold: 1 - - readinessProbe: - httpGet: - path: /actuator/health - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 5 - successThreshold: 1 - envFrom: - - configMapRef: - name: hello-service-config - ---- - -kind: Service -apiVersion: v1 -metadata: - name: hello-service-svc -spec: - selector: - app: hello-service - ports: - - protocol: TCP - port: 8080 ---- - -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: hello-service-ingress - annotations: - nginx.ingress.kubernetes.io/rewrite-target: /$1 -spec: - rules: - - http: - paths: - - path: /hello-service/?(.*) - backend: - serviceName: hello-service-svc - servicePort: 8080 \ No newline at end of file diff --git a/hello-service/src/main/resources/application-netflix.yml b/hello-service/src/main/resources/application-netflix.yml new file mode 100644 index 0000000..05ddf29 --- /dev/null +++ b/hello-service/src/main/resources/application-netflix.yml @@ -0,0 +1,9 @@ +server: + use-forward-headers: true + port: 7070 + +hello-service-uri: http://message-service/message/random + +management: + server: + port: 7071 \ No newline at end of file diff --git a/message-service/build.gradle b/message-service/build.gradle index ddc1f08..cf2071e 100644 --- a/message-service/build.gradle +++ b/message-service/build.gradle @@ -25,9 +25,6 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-webflux' implementation 'org.springframework.boot:spring-boot-starter-actuator' - implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes' - implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-config' - implementation 'com.fasterxml.jackson.module:jackson-module-kotlin' implementation 'org.jetbrains.kotlin:kotlin-reflect' implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' @@ -36,6 +33,7 @@ dependencies { testImplementation 'io.projectreactor:reactor-test' } + dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" @@ -64,3 +62,5 @@ docker { pull true noCache true } + +apply from: rootProject.file('profile.gradle'); \ No newline at end of file diff --git a/message-service/profile.gradle b/message-service/profile.gradle new file mode 100644 index 0000000..3854b4c --- /dev/null +++ b/message-service/profile.gradle @@ -0,0 +1,12 @@ +if (project.hasProperty('kubernetes')) { + println("kubernetes") + dependencies { + implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes' + implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-config' + } +} else if (project.hasProperty('netflix')) { + println("netflix") + dependencies { + implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' + } +} \ No newline at end of file diff --git a/message-service/profiles/kubernetes_build.gradle b/message-service/profiles/kubernetes_build.gradle new file mode 100644 index 0000000..8986dc6 --- /dev/null +++ b/message-service/profiles/kubernetes_build.gradle @@ -0,0 +1,4 @@ +dependencies { + implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes' + implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-config' +} \ No newline at end of file diff --git a/message-service/profiles/netflix_build.gradle b/message-service/profiles/netflix_build.gradle new file mode 100644 index 0000000..f6b40be --- /dev/null +++ b/message-service/profiles/netflix_build.gradle @@ -0,0 +1,3 @@ +dependencies { + implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' +} \ No newline at end of file diff --git a/message-service/src/main/kotlin/it/valeriovaudi/messageservice/MessageServiceApplication.kt b/message-service/src/main/kotlin/it/valeriovaudi/messageservice/MessageServiceApplication.kt index f332a8d..8bed833 100644 --- a/message-service/src/main/kotlin/it/valeriovaudi/messageservice/MessageServiceApplication.kt +++ b/message-service/src/main/kotlin/it/valeriovaudi/messageservice/MessageServiceApplication.kt @@ -68,5 +68,11 @@ class MessageRoute(private val messageRepository: MessageRepository) { } .flatMap { noContent().build() } } + + DELETE("/message/{messageId}") { + val messageId = it.pathVariable("messageId") + messageRepository.deleteById(messageId) + .flatMap { noContent().build() } + } } } \ No newline at end of file diff --git a/message-service/src/main/kubernetes/message-service-k8s.yml b/message-service/src/main/kubernetes/message-service-k8s.yml deleted file mode 100644 index 548b43e..0000000 --- a/message-service/src/main/kubernetes/message-service-k8s.yml +++ /dev/null @@ -1,87 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: message-service-config - labels: - app: message-service -data: - SPRING_DATA_MONGODB_HOST: "mongo-svc" - SERVER_USEFORWARDHEADERS: "true" - ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: message-service-deployment - labels: - app: message-service -spec: - replicas: 3 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 25% - selector: - matchLabels: - app: message-service - template: - metadata: - labels: - app: message-service - spec: - containers: - - name: message-service - image: mrflick72/message-service:latest - ports: - - containerPort: 8080 - - livenessProbe: - httpGet: - path: /actuator/health - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 5 - successThreshold: 1 - - readinessProbe: - httpGet: - path: /actuator/health - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 5 - successThreshold: 1 - envFrom: - - configMapRef: - name: message-service-config ---- - -kind: Service -apiVersion: v1 -metadata: - name: message-service -spec: - selector: - app: message-service - ports: - - protocol: TCP - port: 8080 - targetPort: 8080 ---- - -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: message-service-ingress - annotations: - nginx.ingress.kubernetes.io/rewrite-target: /$1 -spec: - rules: - - host: message-service.com - http: - paths: - - path: /message-service/?(.*) - backend: - serviceName: message-service - servicePort: 8080 diff --git a/message-service/src/main/resources/application-netflix.yml b/message-service/src/main/resources/application-netflix.yml new file mode 100644 index 0000000..8660fad --- /dev/null +++ b/message-service/src/main/resources/application-netflix.yml @@ -0,0 +1,7 @@ +server: + use-forward-headers: true + port: 9090 + +management: + server: + port: 9091 \ No newline at end of file diff --git a/ui/pom.xml b/ui/pom.xml index d7f513c..8d2a625 100644 --- a/ui/pom.xml +++ b/ui/pom.xml @@ -20,19 +20,20 @@ + - org.springframework.cloud - spring-cloud-starter-kubernetes + org.springframework.session + spring-session-core - org.springframework.cloud - spring-cloud-starter-kubernetes-config + org.springframework.boot + spring-boot-starter-data-redis - org.springframework.cloud - spring-cloud-starter-kubernetes-ribbon + org.springframework.session + spring-session-data-redis @@ -45,6 +46,11 @@ spring-boot-starter-actuator + + org.springframework.boot + spring-boot-starter-security + + org.springframework.boot spring-boot-starter-test @@ -64,6 +70,38 @@ + + + netflix + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + + + kubernetes + + + org.springframework.cloud + spring-cloud-starter-kubernetes + + + + org.springframework.cloud + spring-cloud-starter-kubernetes-config + + + + org.springframework.cloud + spring-cloud-starter-kubernetes-ribbon + + + + + ui-interface @@ -73,6 +111,50 @@ spring-boot-maven-plugin + + com.github.eirslett + frontend-maven-plugin + 1.6 + + + src/main/frontend + + + + + install node and npm + + install-node-and-npm + + + v9.8.0 + 5.8.0 + + + + + npm install + + npm + + + install + + + + + npm build + + npm + + + run-script build + + + + + + com.spotify docker-maven-plugin diff --git a/ui/src/main/frontend/app/component/Jumbotron.js b/ui/src/main/frontend/app/component/Jumbotron.js new file mode 100644 index 0000000..23e8ad5 --- /dev/null +++ b/ui/src/main/frontend/app/component/Jumbotron.js @@ -0,0 +1,15 @@ +import React from "react" + +export default ({title, leadSection, bottomSection}) => { + return
+

{title}

+ +
+ {leadSection} +
+ +
+ + {bottomSection} +
+} diff --git a/ui/src/main/frontend/app/component/TextInputForm.js b/ui/src/main/frontend/app/component/TextInputForm.js new file mode 100644 index 0000000..9edb9bd --- /dev/null +++ b/ui/src/main/frontend/app/component/TextInputForm.js @@ -0,0 +1,11 @@ +import React from "react" + +export default ({value, onChangeHandler, componentId, componentLabel, componentPlaceholder, inputRef}) => { + return
+ + +
+} \ No newline at end of file diff --git a/ui/src/main/frontend/app/messages-site/MessageSiteApp.js b/ui/src/main/frontend/app/messages-site/MessageSiteApp.js new file mode 100644 index 0000000..e32b076 --- /dev/null +++ b/ui/src/main/frontend/app/messages-site/MessageSiteApp.js @@ -0,0 +1,73 @@ +import React from "react" +import Jumbotron from "../component/Jumbotron"; +import MessageRepository from "../repository/MessageRepository"; +import TextInputForm from "../component/TextInputForm"; + +export default class MessageSiteApp extends React.Component { + + constructor(props) { + super(props) + + this.state = { + messages: [] + }; + + this.inputRef = React.createRef(); + this.messageRepository = new MessageRepository(); + this.saveMessage = this.saveMessage.bind(this); + this.displayMessages = this.displayMessages.bind(this); + } + + saveMessage() { + this.messageRepository + .saveMessage({message: this.inputRef.current.value}) + .then(response => this.displayMessages()) + } + + componentDidMount() { + this.displayMessages(); + } + + displayMessages() { + this.messageRepository.findMessages() + .then(data => { + console.log(data) + this.setState({messages: data}) + }) + } + + deleteMessage(messageId) { + this.messageRepository.deleteMessage(messageId) + .then(response => { + this.displayMessages() + }) + } + + render() { + let leadSection =
+ + + + + let bottomSection = +
    + {this.state.messages.map(message => { + return
  • + {message.message} + + Delete + +
  • + })} +
+ return + } +} \ No newline at end of file diff --git a/ui/src/main/frontend/app/messages-site/index.js b/ui/src/main/frontend/app/messages-site/index.js new file mode 100644 index 0000000..b7a7b7e --- /dev/null +++ b/ui/src/main/frontend/app/messages-site/index.js @@ -0,0 +1,7 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import MessageSiteApp from "./MessageSiteApp"; + +if(document.getElementById('app')){ + ReactDOM.render(, document.getElementById('app')); +} \ No newline at end of file diff --git a/ui/src/main/frontend/app/repository/MessageRepository.js b/ui/src/main/frontend/app/repository/MessageRepository.js new file mode 100644 index 0000000..f7750c4 --- /dev/null +++ b/ui/src/main/frontend/app/repository/MessageRepository.js @@ -0,0 +1,40 @@ +const SAY_HELLO_TO = (name) => `/ui/hello-service/hello/${name}`; +const SAVE_A_NEW_MESSAGE = "/ui/message-service/message"; +const DELETE_A_MESSAGE = (messageId) => `/ui/message-service/message/${messageId}`; + +export default class MessageRepository { + + sayHelloTo(name) { + return fetch(SAY_HELLO_TO(name)) + .then(data => data.text()); + } + + saveMessage(message) { + return fetch(SAVE_A_NEW_MESSAGE, { + method: "POST", + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(message), + credentials: 'same-origin' + }) + } + + findMessages() { + return fetch(SAVE_A_NEW_MESSAGE, { + method: "GET", + headers: { + 'Accept': 'application/json' + }, + credentials: 'same-origin' + }).then(response => response.json()) + } + + + deleteMessage(messageId) { + return fetch(DELETE_A_MESSAGE(messageId), { + method: "DELETE", + credentials: 'same-origin' + }) + } +} \ No newline at end of file diff --git a/ui/src/main/frontend/app/site/MainSiteApp.js b/ui/src/main/frontend/app/site/MainSiteApp.js new file mode 100644 index 0000000..ed56cc7 --- /dev/null +++ b/ui/src/main/frontend/app/site/MainSiteApp.js @@ -0,0 +1,42 @@ +import React from "react" +import Jumbotron from "../component/Jumbotron"; +import MessageRepository from "../repository/MessageRepository"; +import TextInputForm from "../component/TextInputForm"; + +export default class MainSiteApp extends React.Component { + + constructor(props) { + super(props) + + this.state = { + message: "No message right now" + }; + + this.inputRef = React.createRef(); + this.messageRepository = new MessageRepository(); + this.sayHello = this.sayHello.bind(this); + } + + sayHello() { + this.messageRepository + .sayHelloTo(this.inputRef.current.value) + .then(message => this.setState({message: message})) + } + + render() { + let leadSection =
+ + + + let bottomSection =

{this.state.message}

+ + return + } +} \ No newline at end of file diff --git a/ui/src/main/frontend/app/site/index.js b/ui/src/main/frontend/app/site/index.js new file mode 100644 index 0000000..c0b8505 --- /dev/null +++ b/ui/src/main/frontend/app/site/index.js @@ -0,0 +1,7 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import MainSiteApp from "./MainSiteApp"; + +if(document.getElementById('app')){ + ReactDOM.render(, document.getElementById('app')); +} \ No newline at end of file diff --git a/ui/src/main/frontend/package.json b/ui/src/main/frontend/package.json new file mode 100644 index 0000000..b927fcd --- /dev/null +++ b/ui/src/main/frontend/package.json @@ -0,0 +1,37 @@ +{ + "name": "ui", + "version": "1.0.0", + "description": "UI of My say hello on kubernetes", + "babel": { + "presets": [ + "react", + "env" + ] + }, + "scripts": { + "build": "webpack --config webpack.config.js", + "watch": "webpack --watch" + }, + "author": "mrFlick72", + "license": "ISC", + "devDependencies": { + "babel-core": "^6.26.2", + "babel-preset-env": "^1.6.1", + "babel-preset-react": "^6.24.1", + "clean-webpack-plugin": "^0.1.19", + "css-loader": "^0.28.11", + "html-webpack-plugin": "^3.2.0", + "uglifyjs-webpack-plugin": "^2.1.1", + "webpack": "^4.29.0", + "webpack-cli": "^3.3.1" + }, + "dependencies": { + "acorn": "^6.1.1", + "babel-loader": "^7.1.4", + "build": "^0.1.4", + "prop-types": "^15.6.1", + "react": "^16.3.2", + "react-dom": "^16.3.2", + "style-loader": "^0.21.0" + } +} diff --git a/ui/src/main/frontend/webpack.config.js b/ui/src/main/frontend/webpack.config.js new file mode 100644 index 0000000..fb82e7b --- /dev/null +++ b/ui/src/main/frontend/webpack.config.js @@ -0,0 +1,50 @@ +var path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +const BUID_DIR = path.resolve(__dirname + "../../../../target/classes/static"); + +module.exports = { + // mode: 'production', + entry: { + site: path.resolve(__dirname, './app/site/index.js'), + messagesSite: path.resolve(__dirname, './app/messages-site/index.js') + }, + resolve: { + extensions: [".js", ".jsx"] + }, + plugins: [ + new HtmlWebpackPlugin({ + chunks: ['site'], + filename: "index.html", + template: path.resolve(__dirname, "../resources/static/index.html") + }), + new HtmlWebpackPlugin({ + chunks: ['messagesSite'], + filename: "messages.html", + template: path.resolve(__dirname, "../resources/static/messages.html") + }) + ], + module: { + rules: [ + { + test: /\.css$/, + use: ['style-loader', 'css-loader'] + }, + { + test: path.join(__dirname, "."), + exclude: path.resolve(__dirname, "node_modules"), + use: { + loader: "babel-loader", + options: { + presets: ["env", "react"] + } + } + + } + ] + }, + output: { + filename: '[name]_[hash]_bundle.js', + path: BUID_DIR + } +}; \ No newline at end of file diff --git a/ui/src/main/java/it/valeriovaudi/ui/UiApplication.java b/ui/src/main/java/it/valeriovaudi/ui/UiApplication.java index 6a986b0..a634eed 100644 --- a/ui/src/main/java/it/valeriovaudi/ui/UiApplication.java +++ b/ui/src/main/java/it/valeriovaudi/ui/UiApplication.java @@ -3,6 +3,18 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.context.annotation.Bean; +import org.springframework.security.authorization.AuthorizationDecision; +import org.springframework.security.authorization.ReactiveAuthorizationManager; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.server.SecurityWebFilterChain; +import reactor.core.publisher.Mono; + +import static java.util.Arrays.asList; @EnableDiscoveryClient @SpringBootApplication @@ -12,4 +24,36 @@ public static void main(String[] args) { SpringApplication.run(UiApplication.class, args); } +} + +@EnableWebFluxSecurity +class SecurityConfig { + + @Bean + public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { + return http.csrf().disable().authorizeExchange() + .pathMatchers("/index.html").hasRole("USER") + .pathMatchers("/messages.html").hasRole("ADMIN") + .anyExchange().permitAll() + .and().formLogin() + .and().logout() + .and().build(); + } + + @Bean + public MapReactiveUserDetailsService userDetailsService() { + UserDetails user = User.withDefaultPasswordEncoder() + .username("user") + .password("secret") + .roles("USER") + .build(); + + UserDetails admin = User.withDefaultPasswordEncoder() + .username("admin") + .password("secret") + .roles("ADMIN") + .build(); + + return new MapReactiveUserDetailsService(asList(admin, user)); + } } \ No newline at end of file diff --git a/ui/src/main/kubernetes/ui-interface-k8s.yml b/ui/src/main/kubernetes/ui-interface-k8s.yml deleted file mode 100644 index 9f4899d..0000000 --- a/ui/src/main/kubernetes/ui-interface-k8s.yml +++ /dev/null @@ -1,95 +0,0 @@ -kind: ConfigMap -apiVersion: v1 -metadata: - name: ui-interface -data: - application.yaml: |- - ribbon: - eureka: - enabled: false - client: - enabled: true - ServerListRefreshInterval: 50 - - spring: - cloud: - gateway: - routes: - - id: hello-service - uri: lb://hello-service-svc/ - predicates: - - Path=/hello-service/** - filters: - - StripPrefix=1 - ---- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: ui-interface-deployment - labels: - app: ui-interface -spec: - replicas: 3 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 25% - selector: - matchLabels: - app: ui-interface - template: - metadata: - labels: - app: ui-interface - spec: - containers: - - name: ui-interface - image: mrflick72/ui-interface:latest - ports: - - containerPort: 8080 - livenessProbe: - httpGet: - path: /actuator/health - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 5 - successThreshold: 1 - - readinessProbe: - httpGet: - path: /actuator/health - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 5 - successThreshold: 1 ---- - -kind: Service -apiVersion: v1 -metadata: - name: ui-interface -spec: - selector: - app: ui-interface - ports: - - protocol: TCP - port: 808 ---- - -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: ui-interface-ingress - annotations: - nginx.ingress.kubernetes.io/rewrite-target: /$1 -spec: - rules: - - http: - paths: - - path: /ui/?(.*) - backend: - serviceName: ui-interface - servicePort: 8080 diff --git a/ui/src/main/resources/application-netflix.yml b/ui/src/main/resources/application-netflix.yml new file mode 100644 index 0000000..f1ce346 --- /dev/null +++ b/ui/src/main/resources/application-netflix.yml @@ -0,0 +1,16 @@ +spring: + cloud: + gateway: + routes: + - id: hello-service + uri: lb://hello-service/ + predicates: + - Path=/ui/hello-service/** + filters: + - StripPrefix=2 + - id: message-service + uri: lb://message-service/ + predicates: + - Path=/ui/message-service/** + filters: + - StripPrefix=2 \ No newline at end of file diff --git a/ui/src/main/resources/static/index.html b/ui/src/main/resources/static/index.html index 43d9b89..e96b4b2 100644 --- a/ui/src/main/resources/static/index.html +++ b/ui/src/main/resources/static/index.html @@ -10,20 +10,7 @@ - -
-

Hello, world!

-
-
- - -
- -
-
- -

-
+
- \ No newline at end of file diff --git a/ui/src/main/resources/static/messages.html b/ui/src/main/resources/static/messages.html index 189a12f..c3342d3 100644 --- a/ui/src/main/resources/static/messages.html +++ b/ui/src/main/resources/static/messages.html @@ -10,19 +10,7 @@ - -
-

Special Message

-
-
- - -
- -
-
-
    -
    +
    + - \ No newline at end of file