diff --git a/.myeclipse/profiler/WebDemoApplication.xml b/.myeclipse/profiler/WebDemoApplication.xml new file mode 100644 index 0000000..9145cd1 --- /dev/null +++ b/.myeclipse/profiler/WebDemoApplication.xml @@ -0,0 +1,23 @@ + + + +WebDemoApplication Launch Configuration + +com.cube.webDemo.* +10 + +1000 +false +com.cube.webDemo.** + +false +0 +false +100 +true + +1000 +true +true +false + diff --git a/Dockerfile b/Dockerfile index 1f6add9..5742b25 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM openjdk:8-jdk-alpine -RUN addgroup -S webadmin && adduser -S webadmin -G webadmin -USER webadmin:webadmin +#RUN addgroup -S webadmin && adduser -S webadmin -G webadmin +#USER webadmin:webadmin ARG JAR_FILE=target/*.jar COPY ${JAR_FILE} app.jar EXPOSE 18080 diff --git a/Jenkinsfile b/Jenkinsfile index 37d9cf9..59a1b06 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,11 +1,40 @@ +def getEnvFromBranch(branch) { + if (branch == 'master') { + return 'prod' + } else { + return branch + } +} + pipeline { - agent any + agent any environment { - registry = "registry.lab.local:5000/webdemo" - registryCredential = 'docker-registry-100.64.21.108' - dockerImage = '' - env= "uat" + //registry = "registry.lab.local:5000/webdemo-dev" + //registryUrl = 'https://100.64.21.108:5000' + registryUrl = 'https://registry.lab.local:5000' + //registryCredential = 'docker-registry-100.64.21.108' + registryCredential = 'docker-registry-login' + //dockerDOCKER_IMAGE_NAME = '' + + ENV_NAME = getEnvFromBranch("${env.BRANCH_NAME}") + + APP_NAME = "webdemo-${ENV_NAME}" + APP_VERSION = "MAK001"; + + //DOCKER_IMAGE_NAME = readMavenPom().getArtifactId() + //DOCKER_IMAGE_VERSION = readMavenPom().getVersion() + //DOCKER_IMAGE_NAME = "registry.lab.local:5000/${APP_NAME}" + //DOCKER_IMAGE_VERSION = "${BUILD_NUMBER}" + + //BUILD_ENV = "${BRANCH_NAME}" + + DOCKER_IMAGE_NAME = "registry.lab.local:5000/${APP_NAME}" + //DOCKER_IMAGE_VERSION = "${env.BRANCH_NAME}-${APP_VERSION}-${env.BUILD_ID}-${env.GIT_COMMIT}" + DOCKER_IMAGE_VERSION = "${env.BRANCH_NAME}-${APP_VERSION}-${env.GIT_COMMIT}" + + HOST = "100.64.21.141" + HOST_PORT = "31235" } tools { @@ -13,67 +42,194 @@ pipeline { } stages { + + stage('User Input') { + steps { + echo 'wait user input...' +// timeout(1) { +// script { +// approvalMap = input id: 'test', message: 'Hello', ok: 'Proceed?', parameters: [choice(choices: 'dev\nuat\nprod', description: 'Select env to build', name: 'Environment'), string(defaultValue: '', description: '', name: 'Remarks')], submitter: 'user1,user2,group1', submitterParameter: 'APPROVER' +// } +// } +// +// echo "This build was approved by: ${approvalMap['APPROVER']}" +// echo "build env: ${approvalMap['Environment']}" +// echo "Remarks : ${approvalMap['Remarks']}" + } + } stage ('Initialize') { steps { - sh ''' - echo "PATH = ${PATH}" - echo "M2_HOME = ${M2_HOME}" - ''' - } - } - - stage("Cloning Git") { - steps{ - git credentialsId: 'cube-github', url: 'git@github.com:cubecc/devop_java.git' - } - } - - stage ('Build Src') { - steps { - echo 'Start Build...' - //sh 'mvn -Dmaven.test.failure.ignore=true package' - sh 'mvn package -P${env}' + //sh ''' + // echo "PATH = ${PATH}" + // echo "M2_HOME = ${M2_HOME}" + // echo "" + //''' + echo 'init' } + } + + stage('Build & Test') { + steps { + //sh 'mvn clean package -P${env} -DskipTests' + sh 'mvn clean package' + //sh 'mvn clean package -DskipTests' + } post { success { + echo 'generate test report' junit 'target/surefire-reports/**/*.xml' } - } + } + } + + + stage('Dependency Check') { + steps { + dependencycheck additionalArguments: '--project [project_name] --scan ./ --out ./target/dependency-check-report.html --format HTML --noupdate', odcInstallation: 'Dependency Checker' + //dependencyCheckPublisher pattern: './target/dependency-check-report.xml' + } + } + + + stage('SonarQube Analysis') { + steps { + + echo 'call sonar' + //sh 'mvn sonar:sonar -Dsonar.login=$SONAR_PSW' + + withSonarQubeEnv('SonarQube'){ + sh 'mvn sonar:sonar -Dsonar.dependencyCheck.reportPath=target/dependency-check-report.html -Dsonar.dependencyCheck.htmlReportPath=target/dependency-check-report.html' + //sh 'mvn sonar:sonar' + } + } } - + stage('Quality Gate') { + steps { + timeout(time: 15, unit: 'MINUTES') { + waitForQualityGate abortPipeline: true + } + } + } + + stage('Build Docker DOCKER_IMAGE_NAMEs') { - stage('Building image') { - steps{ - script { - dockerImage = docker.build registry + ":$BUILD_NUMBER -f Dockerfile" - } - } - + steps { + script { + docker.withRegistry( registryUrl, registryCredential ) { + sh ''' + docker build -t ${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} . + ''' + } + } + } } + + /* + stage('Docker security analysis'){ + steps { + echo 'Performing Docker DOCKER_IMAGE_NAME analysis' + //sh "CLAIR_ADDR=localhost:6060 CLAIR_OUTPUT=High CLAIR_THRESHOLD=100 /home/yyy/ ${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}" + } + } + */ + + stage('Push Docker Image') { - stage('Push Image') { - steps{ - script { - docker.withRegistry( 'https://registry.lab.local:5000', registryCredential ) { - sh "docker tag $registry:$BUILD_NUMBER $registry:latest" - sh "docker push $registry:latest" - } - } - } - } - stage('Deploy K8') { + steps { + script { + docker.withRegistry( registryUrl, registryCredential ) { + //docker tag ${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} ${DOCKER_IMAGE_NAME}:latest + //docker push ${DOCKER_IMAGE_NAME}:latest + sh ''' + docker push ${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} + docker rmi ${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} + ''' + } + } + } + } + + stage('Deploy to K8') { steps{ - sh("kubectl replace -f webdemo.yaml --force") - } - - } + //envsubst < webdemo.yaml > webdemo_out.yaml + sh ''' + + sed -i -e "s~\\${APP_NAME}~${APP_NAME}~g;s~\\${DOCKER_IMAGE_NAME}~${DOCKER_IMAGE_NAME}~g;s~\\${DOCKER_IMAGE_VERSION}~${DOCKER_IMAGE_VERSION}~g" webdemo.yaml + sed -i -e "s~\\${HOST_PORT}~${HOST_PORT}~g" webdemo.yaml + + kubectl replace -f webdemo.yaml --force + kubectl rollout status deployment ${APP_NAME} --watch --timeout=5m + ''' + } + } + + /* + stage('OWASP Scan') { + agent { label 'zap' } + options { skipDefaultCheckout() } + steps { + //sh 'mvn verify -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8088 -Dhttps.proxyHost=localhost -Dhttps.proxyPort=8088' + script { + startZap(host: "100.64.21.108", port: 8088, timeout:500, zapHome: "/usr/share/owasp-zap") + //startZap(host: "127.0.0.1", port: 8088, timeout:500, zapHome: "/usr/share/owasp-zap") + //startZap(host: "localhost", port: 8088, timeout:1000, zapHome: "/usr/share/owasp-zap", sessionPath:"/tmp/session.session", allowedHosts:['100.64.21.136']) + //sh "mvn verify -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dhttp.proxyHost=100.64.21.108 -Dhttp.proxyPort=8088 -Dhttps.proxyHost=100.64.21.108 -Dhttps.proxyPort=8088 -DskipTests" + runZapCrawler(host:"http://100.64.21.141:31235") + //runZapCrawler(host:"http://100.64.21.141:31235/getWebUserList") + //runZapAttack() + } + } + post { + always { + script { + archiveZap(failAllAlerts: 100, failHighAlerts: 5, failMediumAlerts: 0, failLowAlerts: 0, falsePositivesFilePath: "zapFalsePositives.json") + } + } + } + } +*/ - stage('Remove Unused docker image') { - steps{ - sh "docker rmi $registry:$BUILD_NUMBER" - } - } + stage('OWASP Scan') { + steps { + script { + runLog = sh (script: "docker run --user \$(id -u):\$(id -g) -v ${workspace}:/zap/wrk/:rw -t owasp/zap2docker-stable zap-baseline.py -t http://${HOST}:${HOST_IP} -r zap_report.html -m 5", returnStatus: true) + publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: true, reportDir: './', reportFiles: 'zap_report.html', reportName: 'OWASP ZAP Scan', reportTitles: 'OWASP ZAP Scan']) + + //0 if there are no issues, 1 if there are any failures or 2 if there are just warning + echo "ZAP Run Log: ${runLog}" + } + } + } + + stage('Smoke Test') { + steps{ + echo 'ping curl...' + } + } + } + post { + always { + echo 'post status : clearup workspace' + deleteDir() /* clean up our workspace */ + } + success { + echo 'post status : success' + } + unstable { + echo 'post status : unstable' + } + failure { + echo 'post status : failure' + //mail to: 'alex.cc.chan@jos.com', + //subject: "Failed Pipeline: ${currentBuild.fullDisplayName}", + //body: "Something is wrong with ${env.BUILD_URL}" + } + changed { + echo 'post status : changed' + } + + } } \ No newline at end of file diff --git a/config/dev/config.properties b/config/dev/config.properties index 5fe6460..d04ddba 100644 --- a/config/dev/config.properties +++ b/config/dev/config.properties @@ -1,2 +1,2 @@ -env.name=cube-dev-${env} +env.name=cube-dev secret.password=ENC(jkYAjTJWtD6vNMDL1gsQantyRxLyy7dJKYw/IGu5mdzsxF2Zdcrbe7hevZmNm8+4VAVazz/Hp4DtgG2tmGVQUv1FwCsvNoqzESWHjRxqEAxAvmF3nA7YfaNs7UX8l1wsFD3luhfdp6OIFXjr0eSOvafLbhVeR/u6fs9vbcfF48dDcOtRS9Tr8fMsfN+F2Yds3QxtM73Pg39C417cLY86FNKkSroX6Pwoifl1ihor0804OphvzkBM6mftjwZ/wI2efYdPOae8aNd/OUy1vNTj/Hwp+ZhTxpWEFk1Zk2Q6UxekmL7A0XDhkoONYGC1p+pEbG4n6UD2VkTNduHM4AcOHw+V/zRSRww8yw0Onw0gYYQc4UyszRZOr6jGL+ABqtfkYyhL8zi0kXPAcrEBlLCWlA1pFT4NblLfzoDiNIRUtynR5ONH8I51ElYTdMjhO8Fh6PE9/+S9eCIxbhaIbAkL5jkw/53bk1fFYZkXO4ZloX8dJWS3yh6/XMEF4cjIrBwMtm6lbClFCBoNa+uZ99DwY2S+/sXVDsrtxQRoNcxf8F6qklknUfLs772J3rdrKl5NNWvu6EGzepaRoTTckev1XLHtw89NsI+To6z+dm6iSFDu1nuAecJlUNaQEAN1ex7ouffG4lT2ek9UdRRYkeO4opVMC+sKtgYkCUylZKYXajI\=) \ No newline at end of file diff --git a/config/uat/config.properties b/config/uat/config.properties index 31c8bc6..ca62273 100644 --- a/config/uat/config.properties +++ b/config/uat/config.properties @@ -1,2 +1,2 @@ -env.name=cube-dev-${env} +env.name=cube-dev secret.password=ENC(JiNmuGqZUIgmjnLq9I5ojk4BnSid5bKDh0pTzeLQJrnSjS8p9uhTcN8Y8vr5XcDR+XJzN7KYBezylEN2vssfGE8EF5EhnWvg25H8aEx3Nm0ABESgzEN5cGUFW2kLzYKA8oMMLYFGDai5GHf1YJg64M/HgTWX1fb533Y6XndhDvhZVtsSWOyqKppR/xTMh8pYia6tazjAZaK5KvPkoZGBNV6wNc608tg6D0IV3OrJh+hNiSETtL32Acilzgm0dwf+2xElfJqEc6DxYJeNJpTzFwxtxwA1FntdWd4KK58Uiosm0h1d7RLD7y3953leQPExZg8K5g+/NP3+lGVTqghKKVOyzU2HrMqPq5QLEsXog4MySj5qm7WMqcbhekKA7XV9iUTXtfOB34g0yz0Fb7BgobAWFnMI4nPeZjcjsRQam0nb4L/x00vRwcg6ltwM/YJ22HSrdgM8wxuJnUSK8QEmLSx9KUqr7JSA/VPRiSntqSjVIQAwxW7H/sFH5rJoJpI+CDDiHBQ7PlhEWXCPtb7FnN3oU+KSupFQUiQmsMQwgH0mI73JKk6KmBmyzwQmwjQ8PJ32g/W97vOpKMcEp9djXRXvOS9dzJd3vcsdec42ZfjNGDI6GOBancNKXACKlsanWS05dbaPl9BpUF0vKfY4kEJ+FHgmsKbRfkeYRZT2WjI\=) \ No newline at end of file diff --git a/create_table.sql b/create_table.sql new file mode 100644 index 0000000..23bae28 --- /dev/null +++ b/create_table.sql @@ -0,0 +1,19 @@ +drop table web_user; + +CREATE TABLE web_user ( + id int NOT NULL AUTO_INCREMENT, + login varchar(255) NOT NULL, + password varchar(255), + username varchar(255), + PRIMARY KEY (id) +); + + +create unique index login on `devop`.`web_user`(`login`); +-- create unique index `PRIMARY` on `devop`.`web_users`(`id`); + +insert into web_user (login,password,username) values ('user1','password','Chan Tai Man'); +insert into web_user (login,password,username) values ('user2','password','Wong Siu Ming'); + + +select * from web_user \ No newline at end of file diff --git a/pom.xml b/pom.xml index cb00a4f..1ee93ff 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,5 @@ - 4.0.0 @@ -16,8 +15,7 @@ Demo - 1.8 - + 1.8 @@ -42,16 +40,42 @@ org.springframework.boot spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + com.github.ulisesbocchio jasypt-spring-boot 3.0.2 + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + mysql + mysql-connector-java + org.springframework.boot spring-boot-devtools + + org.springframework.boot + spring-boot-starter-log4j2 + + + org.projectlombok + lombok + org.springframework.boot spring-boot-starter-test @@ -79,7 +103,7 @@ org.springframework.boot spring-boot-maven-plugin - + diff --git a/src/main/java/com/cube/webDemo/WebDemoApplication.java b/src/main/java/com/cube/webDemo/WebDemoApplication.java index e86aade..0c995ee 100644 --- a/src/main/java/com/cube/webDemo/WebDemoApplication.java +++ b/src/main/java/com/cube/webDemo/WebDemoApplication.java @@ -9,7 +9,7 @@ @EnableEncryptableProperties public class WebDemoApplication { - public static void main(String[] args) { + public static void main(String[] args) { SpringApplication.run(WebDemoApplication.class, args); } diff --git a/src/main/java/com/cube/webDemo/controller/HelloController.java b/src/main/java/com/cube/webDemo/controller/HelloController.java index fc26c28..29d7cfa 100644 --- a/src/main/java/com/cube/webDemo/controller/HelloController.java +++ b/src/main/java/com/cube/webDemo/controller/HelloController.java @@ -1,15 +1,28 @@ package com.cube.webDemo.controller; import org.springframework.web.bind.annotation.RestController; + +import com.cube.webDemo.dao.WebUserDao; +import com.cube.webDemo.entity.WebUser; + +import java.util.Optional; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; +import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; @RestController public class HelloController { @Autowired Environment env; + + @Autowired + private WebUserDao webUserDao; + + @RequestMapping("/") public String index() { System.out.println("Request incoming"); @@ -19,4 +32,12 @@ public String index() { return "Hello Hello, current profile : " + env + ", config name : " + env.getProperty("env.name") + ", secret : " + env.getProperty("secret.password"); } + + @RequestMapping("/getWebUser") + public WebUser getWebUser(int id) { + WebUser u = webUserDao.findById(id).orElse(new WebUser()); + return u; + } + + } \ No newline at end of file diff --git a/src/main/java/com/cube/webDemo/controller/WebUserController.java b/src/main/java/com/cube/webDemo/controller/WebUserController.java new file mode 100644 index 0000000..f284260 --- /dev/null +++ b/src/main/java/com/cube/webDemo/controller/WebUserController.java @@ -0,0 +1,67 @@ +package com.cube.webDemo.controller; + +import java.util.ArrayList; +import java.util.Date; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.context.request.WebRequest; + +import com.cube.webDemo.dao.WebUserDao; +import com.cube.webDemo.entity.WebUser; + +import antlr.collections.List; +import lombok.extern.log4j.Log4j2; + +@Controller +public class WebUserController { + private static final Logger logger = LogManager.getLogger(WebUserController.class); + + @Autowired + Environment env; + + @Autowired + private WebUserDao webUserDao; + + @GetMapping("/login") + public String showLoginPage(Model model) { + Date currentDate = new Date(); + logger.info("Test Log from k8 : Curent Date and Time - " + currentDate.toString()); + + model.addAttribute("page_info", env.getProperty("env.name")); + //model.addAttribute("users", webUserDao.findAll()); + //model.addAttribute("error", "invalid losssgin"); + return "login"; + } + + @PostMapping("/login") + public String login(Model model, @RequestParam(value = "login") String login, @RequestParam(value = "password") String password) { + + ArrayList users = (ArrayList)webUserDao.findByLoginAndPassword(login, password); + + if(users.size()>0){ + return "redirect:getWebUserList"; + }else{ + model.addAttribute("error", "Invalid login"); + return showLoginPage(model); + } + + } + + @RequestMapping("/getWebUserList") + public String greeting(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) { + //model.addAttribute("name", name); + model.addAttribute("users", webUserDao.findAll()); + + return "users"; + } +} diff --git a/src/main/java/com/cube/webDemo/dao/WebUserDao.java b/src/main/java/com/cube/webDemo/dao/WebUserDao.java new file mode 100644 index 0000000..9837093 --- /dev/null +++ b/src/main/java/com/cube/webDemo/dao/WebUserDao.java @@ -0,0 +1,15 @@ +package com.cube.webDemo.dao; + + +import java.util.List; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +import com.cube.webDemo.entity.WebUser; + + +@Repository +public interface WebUserDao extends CrudRepository{ + List findByLoginAndPassword(String login, String password); +} diff --git a/src/main/java/com/cube/webDemo/entity/WebUser.java b/src/main/java/com/cube/webDemo/entity/WebUser.java new file mode 100644 index 0000000..3a6df90 --- /dev/null +++ b/src/main/java/com/cube/webDemo/entity/WebUser.java @@ -0,0 +1,57 @@ +package com.cube.webDemo.entity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "web_user") +public class WebUser { + @Id + @GeneratedValue + @Column(name = "id") + private int id; + + @Column(name = "login") + private String login; + + @Column(name = "password") + private String password; + + @Column(name = "username") + private String username; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } +} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 49b956a..98cad50 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -1,6 +1,16 @@ spring: - profiles: - active: '@spring.profiles.active@' + profiles: + active: '@spring.profiles.active@' + datasource: + url: jdbc:mysql://100.64.21.141:31907/devop + username: root + password: password + driver-class-name: com.mysql.cj.jdbc.Driver + jpa: + database-platform: org.hibernate.dialect.MySQL8Dialect + hibernate: + ddl-auto: update + server: port: 18080 env: @@ -65,4 +75,7 @@ jasypt: tTN4oPzywYB1AfxtlZ18C42UU1Cj1hAX4iYCM/sQL2klcitZ3almnEEFiM2gUXMo MSvTcHdAsQTZCM6TqTAOhuG24AwC -----END PRIVATE KEY----- - #privateKeyLocation: file:/var/app_certs/private.key \ No newline at end of file + #privateKeyLocation: file:/var/app_certs/private.key + + + \ No newline at end of file diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..6950f98 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,35 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex + + /var/log/webDemo + + + + + + + + + ${LOG_PATTERN} + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 0000000..61491c2 --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,22 @@ + + + + + + + xxxxENV NAME : +
+
+
+ +
+
+
+
+
+
+
+ web user list + + \ No newline at end of file diff --git a/src/main/resources/templates/users.html b/src/main/resources/templates/users.html new file mode 100644 index 0000000..45c87e5 --- /dev/null +++ b/src/main/resources/templates/users.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + +
id login password username
No Data
+ \ No newline at end of file diff --git a/src/test/java/com/cube/webDemo/controller/WebUserControllerTest.java b/src/test/java/com/cube/webDemo/controller/WebUserControllerTest.java new file mode 100644 index 0000000..7986b47 --- /dev/null +++ b/src/test/java/com/cube/webDemo/controller/WebUserControllerTest.java @@ -0,0 +1,27 @@ +package com.cube.webDemo.controller; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +import static org.hamcrest.Matchers.equalTo; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@AutoConfigureMockMvc +public class WebUserControllerTest { + + @Autowired + private MockMvc mvc; + + @Test + public void getWebUserList() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/getWebUserList").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } +} \ No newline at end of file diff --git a/webdemo.yaml b/webdemo.yaml index e5f16c1..74333e3 100644 --- a/webdemo.yaml +++ b/webdemo.yaml @@ -3,28 +3,41 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: webdemo + name: ${APP_NAME} spec: - replicas: 3 + replicas: 1 selector: matchLabels: - app: webdemo + app: ${APP_NAME} template: metadata: labels: - app: webdemo + app: ${APP_NAME} spec: containers: - - name: webdemo - image: registry.lab.local:5000/webdemo:latest + - name: ${APP_NAME} + DOCKER_IMAGE_NAME: ${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} imagePullPolicy: Always env: - name: env value: "testing" ports: - containerPort: 18080 - name: webdemo + name: ${APP_NAME} protocol: TCP + resources: + limits: + cpu: 1.5 + requests: + cpu: 500m + volumeMounts: + - name: app-log-volume + mountPath: /var/log/webDemo/ + volumes: + - name: app-log-volume + hostPath: + # directory location on host + path: /var/log/k8s-mount/webDemo imagePullSecrets: - name: regcred @@ -32,13 +45,27 @@ spec: apiVersion: v1 kind: Service metadata: - name: webdemo + name: ${APP_NAME} spec: selector: - app: webdemo + app: ${APP_NAME} type: NodePort ports: - - name: webdemo + - name: ${APP_NAME} port: 18080 - nodePort: 31234 + nodePort: ${HOST_PORT} + +--- +apiVersion: autoscaling/v1 +kind: HorizontalPodAutoscaler +metadata: + name: ${APP_NAME} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: ${APP_NAME} + minReplicas: 1 + maxReplicas: 10 + targetCPUUtilizationPercentage: 50