├── LICENSE ├── README.md ├── api-gateway ├── .gitignore ├── .project ├── .settings │ ├── gradle │ │ ├── org.springsource.ide.eclipse.gradle.core.import.prefs │ │ ├── org.springsource.ide.eclipse.gradle.core.prefs │ │ └── org.springsource.ide.eclipse.gradle.refresh.prefs │ ├── org.eclipse.buildship.core.prefs │ └── org.eclipse.jdt.core.prefs ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── docker │ └── Dockerfile │ ├── java │ └── com │ │ └── anilallewar │ │ └── microservices │ │ └── gateway │ │ ├── GatewayApplication.java │ │ ├── config │ │ ├── bean │ │ │ └── BeanFactory.java │ │ └── swagger │ │ │ └── SwaggerDocumentationConfiguration.java │ │ └── security │ │ └── WebSecurityConfiguration.java │ └── resources │ ├── application.yml │ ├── bootstrap.yml │ └── run.sh ├── auth-server ├── .gitignore ├── .project ├── .settings │ ├── gradle │ │ ├── org.springsource.ide.eclipse.gradle.core.import.prefs │ │ ├── org.springsource.ide.eclipse.gradle.core.prefs │ │ └── org.springsource.ide.eclipse.gradle.refresh.prefs │ ├── org.eclipse.buildship.core.prefs │ └── org.eclipse.jdt.core.prefs ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── docker │ └── Dockerfile │ ├── java │ └── com │ │ └── anilallewar │ │ └── microservices │ │ └── auth │ │ ├── AuthServerApplication.java │ │ ├── api │ │ └── AuthUserController.java │ │ ├── config │ │ ├── OAuthServerConfiguration.java │ │ └── OAuthWebFormConfiguration.java │ │ └── service │ │ └── JdbcUserDetailsService.java │ └── resources │ ├── anilkeystore.jks │ ├── application.yml │ ├── bootstrap.yml │ ├── run.sh │ ├── schema.sql │ └── templates │ ├── authorize.ftl │ └── login.ftl ├── build-all-projects.sh ├── comments-webservice ├── .gitignore ├── .project ├── .settings │ ├── org.eclipse.buildship.core.prefs │ ├── org.eclipse.jdt.core.prefs │ └── org.eclipse.jdt.groovy.core.prefs ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ ├── main │ ├── docker │ │ └── Dockerfile │ ├── java │ │ └── com │ │ │ └── anilallewar │ │ │ └── microservices │ │ │ └── comments │ │ │ ├── CommentsApplication.java │ │ │ ├── apis │ │ │ └── CommentsController.java │ │ │ └── dtos │ │ │ └── CommentDTO.java │ └── resources │ │ ├── application.yml │ │ ├── bootstrap.yml │ │ └── run.sh │ └── test │ ├── java │ └── com │ │ └── anilallewar │ │ └── microservices │ │ └── comments │ │ └── contracts │ │ └── TaskCommentsBase.java │ └── resources │ └── contracts │ └── task │ └── comments │ └── returnCommentsForTasks.groovy ├── config-server ├── .gitignore ├── .project ├── .settings │ └── org.eclipse.jdt.core.prefs ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── docker │ └── Dockerfile │ ├── java │ └── com │ │ └── anilallewar │ │ └── microservices │ │ └── config │ │ └── ConfigApplication.java │ └── resources │ ├── application.yml │ ├── bootstrap.yml │ └── run.sh ├── docker-image-all-projects.sh ├── docker-orchestration ├── docker-compose │ └── docker-compose.yml ├── k8s │ └── manifests │ │ ├── helm-charts │ │ ├── README.md │ │ └── application │ │ │ ├── app-services │ │ │ ├── .helmignore │ │ │ ├── Chart.yaml │ │ │ ├── templates │ │ │ │ ├── _helpers.tpl │ │ │ │ ├── app-service-autoscaler.yml │ │ │ │ ├── app-service-deployment.yml │ │ │ │ └── app-service-service.yml │ │ │ └── values.yaml │ │ │ └── support-services │ │ │ ├── .helmignore │ │ │ ├── Chart.yaml │ │ │ ├── templates │ │ │ ├── _helpers.tpl │ │ │ ├── helper-service-deployment.yml │ │ │ └── helper-service-service.yml │ │ │ └── values.yaml │ │ ├── istio │ │ ├── README.md │ │ ├── application │ │ │ └── system-services │ │ │ │ ├── .helmignore │ │ │ │ ├── Chart.yaml │ │ │ │ ├── templates │ │ │ │ ├── _helpers.tpl │ │ │ │ ├── helper-service-deployment.yml │ │ │ │ └── helper-service-service.yml │ │ │ │ └── values.yaml │ │ ├── istio-auth-policy.yml │ │ ├── istio-destination-rule.yml │ │ ├── istio-gateway.yml │ │ └── istio-virtual-service.yml │ │ └── standalone │ │ ├── README.md │ │ ├── config-server-deployment.yml │ │ ├── config-server-service.yml │ │ └── config-server-single.yml └── rancher │ ├── docker-compose.yml │ └── rancher-compose.yml ├── images ├── Application_Components.jpg ├── Decentralized_Goverance.png ├── OAuth2_abstract_protocol_flow.png └── Target_Architecture.jpg ├── task-webservice ├── .gitignore ├── .project ├── .settings │ ├── gradle │ │ ├── org.springsource.ide.eclipse.gradle.core.import.prefs │ │ ├── org.springsource.ide.eclipse.gradle.core.prefs │ │ └── org.springsource.ide.eclipse.gradle.refresh.prefs │ ├── org.eclipse.buildship.core.prefs │ └── org.eclipse.jdt.core.prefs ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ ├── main │ ├── docker │ │ └── Dockerfile │ ├── java │ │ └── com │ │ │ └── anilallewar │ │ │ └── microservices │ │ │ └── task │ │ │ ├── TaskApplication.java │ │ │ ├── apis │ │ │ ├── CommentsService.java │ │ │ └── TaskController.java │ │ │ ├── config │ │ │ ├── OAuthClientConfiguration.java │ │ │ ├── TaskBeanFactory.java │ │ │ └── security │ │ │ │ ├── ResourceServerConfiguration.java │ │ │ │ └── WebSecurityConfiguration.java │ │ │ ├── dtos │ │ │ └── TaskDTO.java │ │ │ └── model │ │ │ ├── CommentCollectionResource.java │ │ │ └── CommentResource.java │ └── resources │ │ ├── application.yml │ │ ├── bootstrap.yml │ │ └── run.sh │ └── test │ └── java │ └── com │ └── anilallewar │ └── microservices │ └── task │ ├── CommentsServiceTests.java │ └── oauth2 │ ├── config │ └── OAuth2ClientTestConfiguration.java │ └── security │ ├── WithMockOAuth2Token.java │ └── WithOAuth2MockAccessTokenSecurityContextFactory.java ├── understanding_notes.pages ├── user-webservice ├── .gitignore ├── .project ├── .settings │ ├── org.eclipse.buildship.core.prefs │ └── org.eclipse.jdt.core.prefs ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── docker │ └── Dockerfile │ ├── java │ └── com │ │ └── anilallewar │ │ └── microservices │ │ └── user │ │ ├── UserApplication.java │ │ ├── api │ │ └── UserController.java │ │ ├── config │ │ ├── UserBeanFactory.java │ │ └── security │ │ │ ├── ResourceServerConfiguration.java │ │ │ └── WebSecurityConfiguration.java │ │ └── dto │ │ └── UserDTO.java │ └── resources │ ├── application.yml │ ├── bootstrap.yml │ └── run.sh ├── web-portal ├── .gitignore ├── .project ├── .settings │ ├── org.eclipse.buildship.core.prefs │ └── org.eclipse.jdt.core.prefs ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── docker │ └── Dockerfile │ ├── java │ └── com │ │ └── anilallewar │ │ └── microservices │ │ └── portal │ │ └── PortalApplication.java │ └── resources │ ├── application.yml │ ├── bootstrap.yml │ ├── run.sh │ └── static │ ├── css │ └── bootstrap.min.css │ ├── index.html │ ├── js │ ├── app │ │ ├── controller │ │ │ ├── homeController.js │ │ │ ├── navController.js │ │ │ ├── taskController.js │ │ │ └── userController.js │ │ ├── oauthapp.js │ │ └── services │ │ │ └── dataservice.js │ └── libs │ │ ├── angular-route.min.js │ │ └── angular.min.js │ └── views │ ├── home.html │ ├── task-comments.html │ ├── task-details.html │ ├── task.html │ └── user.html ├── webservice-registry ├── .gitignore ├── .project ├── .settings │ └── org.eclipse.jdt.core.prefs ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── docker │ └── Dockerfile │ ├── java │ └── com │ │ └── anilallewar │ │ └── microservices │ │ └── registry │ │ └── RegistryApplication.java │ └── resources │ ├── application.yml │ ├── bootstrap.yml │ └── run.sh └── zipkin-server ├── .gitignore ├── .project ├── .settings └── org.eclipse.jdt.core.prefs ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src └── main ├── docker └── Dockerfile ├── java └── com │ └── anilallewar │ └── microservices │ └── tracing │ └── ZipkinTracingApplication.java └── resources ├── application.yml ├── bootstrap.yml └── run.sh /api-gateway/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | .classpath 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /api-gateway/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | api-gateway 4 | 5 | 6 | 7 | org.springsource.ide.eclipse.gradle.core.nature 8 | org.eclipse.jdt.core.javanature 9 | 10 | 11 | 12 | org.eclipse.jdt.core.javabuilder 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /api-gateway/.settings/gradle/org.springsource.ide.eclipse.gradle.core.import.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleImportPreferences 2 | #Mon Apr 06 13:25:59 PDT 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | enableDependendencyManagement=true 10 | projects=; 11 | -------------------------------------------------------------------------------- /api-gateway/.settings/gradle/org.springsource.ide.eclipse.gradle.core.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleProjectPreferences 2 | #Mon Apr 06 13:26:03 PDT 2015 3 | org.springsource.ide.eclipse.gradle.linkedresources= 4 | org.springsource.ide.eclipse.gradle.rootprojectloc= 5 | -------------------------------------------------------------------------------- /api-gateway/.settings/gradle/org.springsource.ide.eclipse.gradle.refresh.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.actions.GradleRefreshPreferences 2 | #Mon Apr 06 13:26:02 PDT 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | useHierarchicalNames=false 10 | -------------------------------------------------------------------------------- /api-gateway/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.arguments= 2 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) 3 | connection.java.home=null 4 | connection.jvm.arguments= 5 | connection.project.dir= 6 | derived.resources=.gradle,build 7 | eclipse.preferences.version=1 8 | project.path=\: 9 | -------------------------------------------------------------------------------- /api-gateway/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | # 2 | #Fri Nov 23 17:01:00 IST 2018 3 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 7 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 8 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 9 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 10 | eclipse.preferences.version=1 11 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 12 | org.eclipse.jdt.core.compiler.source=1.8 13 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 14 | -------------------------------------------------------------------------------- /api-gateway/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | The api-gateway application acts the router and authentication and authorization endpoint. 4 | 5 | The Zuul api gateway solves a very common use case where a UI application wants to proxy calls to one or more back end services. This feature is useful for a user interface to proxy to the backend services it requires, avoiding the need to manage CORS and authentication concerns independently for all the backends.For example in our application `/user-service/**` endpoint is mapped to the `user-webservice`. 6 | 7 | It also knows how to invoke the authorization server in case the user is not authenticated. Once the authentication is complete, it relays the OAuth2 token to the respective services so that they can find the authenticated user and provide services. 8 | 9 | ##Pre-requisites 10 | 11 | ### Projects that need to be started before 12 | * [config server](/../../blob/master/config-server/README.md) - For pulling the configuration information 13 | * [webserver-registry](/../../blob/master/webservice-registry/README.md) - For starting the Eureka server since the authorization server also is a micro-service that needs to be registered with Eureka server. 14 | 15 | ### Running the application 16 | * Build the application by running the `./gradlew clean build` gradle command at the "task-webservice" project root folder on the terminal. 17 | * If you want to run the application as jar file, then run `java -jar build/libs/basic-api-gateway-0.0.1.jar` command at the terminal. 18 | 19 | ## External Configuration 20 | Please refer to [user webservice](/../../blob/master/user-webservice/README.md) for details on how the external configuration works. Note that there is separate configuration file for each Spring application; the application should refer to it's own .yml file for configuration. -------------------------------------------------------------------------------- /api-gateway/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/api-gateway/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /api-gateway/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 26 15:37:00 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip 7 | -------------------------------------------------------------------------------- /api-gateway/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /api-gateway/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------------------------------- 2 | # API Gateway 3 | #----------------------------------------------------------------------------------------------------- 4 | FROM openjdk:8u121-jdk-alpine 5 | 6 | MAINTAINER Anil Allewar 7 | 8 | # Keep consistent with build.gradle 9 | ENV APP_JAR_NAME basic-api-gateway 10 | ENV APP_JAR_VERSION 0.0.1 11 | 12 | # Install curl and bash for the entry script 13 | RUN apk --update add curl bash && \ 14 | rm -rf /var/cache/apk/* 15 | 16 | RUN mkdir /app 17 | 18 | ADD ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar /app/ 19 | ADD run.sh /app/ 20 | RUN chmod +x /app/run.sh 21 | 22 | WORKDIR /app 23 | 24 | EXPOSE 8765 25 | 26 | ENTRYPOINT ["/bin/bash","-c"] 27 | CMD ["/app/run.sh"] -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/anilallewar/microservices/gateway/GatewayApplication.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.gateway; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; 6 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 7 | import org.springframework.cloud.netflix.zuul.EnableZuulProxy; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 10 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 11 | import org.springframework.security.web.csrf.CookieCsrfTokenRepository; 12 | 13 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 14 | 15 | /** 16 | * The Main Spring Boot Application class which does the following 17 | *
    18 | *
  1. Act as a Eureka client; this behavior is provided by the 19 | * {@link EnableEurekaClient} annotation. The Eureka server URL is provided by 20 | * the external configuration provided by the config server.
  2. 21 | *
  3. Act as Zuul reverse proxy; this behavior is provided by the 22 | * {@link EnableZuulProxy} annotation. Annotating the application with 23 | * {@link EnableZuulProxy} forwards local calls to the appropriate service. By 24 | * convention, a service with the Eureka ID "users", will receive requests from 25 | * the proxy located at /users (with the prefix stripped).
  4. 26 | *
  5. Enable OAuth2 single sign on (SSO) using the {@link EnableOAuth2Sso} 27 | * annotation. 28 | *
      29 | *
    1. If your app has a Spring Cloud Zuul embedded reverse proxy (using 30 | * {@link EnableZuulProxy}) then you can ask it to forward OAuth2 access tokens 31 | * downstream to the services it is proxying.
    2. 32 | *
    3. If you also add the {@link EnableOAuth2Sso} annotation; then it will (in 33 | * addition to loggin the user in and grabbing a token) pass the authentication 34 | * token downstream to the /proxy/* services.
    4. 35 | *
    5. If those services are implemented with {@link EnableResourceServer} then 36 | * they will get a valid token in the correct header.
    6. 37 | *
    38 | *
  6. 39 | *
  7. Note that all these annotations work in conjunction with properties 40 | * defined in the external configuration files specified by the config server. 41 | *
  8. 42 | *
43 | * 44 | * @author anilallewar 45 | */ 46 | @SpringBootApplication 47 | @EnableEurekaClient 48 | @EnableZuulProxy 49 | @EnableSwagger2 50 | public class GatewayApplication/* extends WebSecurityConfigurerAdapter */{ 51 | 52 | public static void main(String[] args) { 53 | SpringApplication.run(GatewayApplication.class, args); 54 | } 55 | 56 | 57 | /** 58 | * Uncomment and make changes to external API gateway configuration if you want to use the web-portal 59 | */ 60 | // @Override 61 | // public void configure(HttpSecurity http) throws Exception { 62 | // // @formatter:off 63 | // http.logout().and().authorizeRequests().antMatchers("/**/*.html", "/login").permitAll().anyRequest() 64 | // .authenticated().and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); 65 | // // @formatter:on 66 | // } 67 | } 68 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/anilallewar/microservices/gateway/config/bean/BeanFactory.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.gateway.config.bean; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 8 | 9 | @Configuration 10 | public class BeanFactory { 11 | 12 | @Bean 13 | public WebMvcConfigurer corsConfigurer() { 14 | return new WebMvcConfigurerAdapter() { 15 | @Override 16 | public void addCorsMappings(CorsRegistry registry) { 17 | registry.addMapping("/**").allowedMethods("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH") 18 | .allowedHeaders("*"); 19 | } 20 | }; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/anilallewar/microservices/gateway/config/swagger/SwaggerDocumentationConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.gateway.config.swagger; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.annotation.Primary; 8 | 9 | import springfox.documentation.swagger.web.SwaggerResource; 10 | import springfox.documentation.swagger.web.SwaggerResourcesProvider; 11 | 12 | @Configuration 13 | @Primary 14 | public class SwaggerDocumentationConfiguration implements SwaggerResourcesProvider { 15 | 16 | @Override 17 | public List get() { 18 | List resources = new ArrayList<>(); 19 | resources.add(this.createSwaggerResource("auth-server", "/userauth/v2/api-docs", "2.0")); 20 | resources.add(this.createSwaggerResource("task-service", "/task-service/v2/api-docs", "2.0")); 21 | resources.add(this.createSwaggerResource("user-service", "/user-service/v2/api-docs", "2.0")); 22 | return resources; 23 | } 24 | 25 | /** 26 | * Create swagger resource for all microservices 27 | * 28 | * @param name 29 | * @param location 30 | * @param version 31 | * @return 32 | */ 33 | private SwaggerResource createSwaggerResource(String name, String location, String version) { 34 | SwaggerResource swaggerResource = new SwaggerResource(); 35 | swaggerResource.setName(name); 36 | swaggerResource.setLocation(location); 37 | swaggerResource.setSwaggerVersion(version); 38 | return swaggerResource; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/anilallewar/microservices/gateway/security/WebSecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.gateway.security; 2 | 3 | import org.springframework.boot.actuate.autoconfigure.ManagementServerProperties; 4 | import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.core.annotation.Order; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 11 | import org.springframework.security.config.http.SessionCreationPolicy; 12 | import org.springframework.web.cors.CorsConfiguration; 13 | import org.springframework.web.cors.CorsConfigurationSource; 14 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource; 15 | 16 | import com.google.common.collect.ImmutableList; 17 | 18 | @Configuration 19 | @EnableWebSecurity 20 | @Order(ManagementServerProperties.ACCESS_OVERRIDE_ORDER) 21 | @EnableOAuth2Sso 22 | public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 23 | 24 | @Override 25 | public void configure(HttpSecurity http) throws Exception { 26 | 27 | // @formatter:off 28 | http 29 | // configure CORS -- uses a Bean by the name of corsConfigurationSource (see method below) 30 | // CORS must be configured prior to Spring Security 31 | .cors() 32 | .and() 33 | .sessionManagement() 34 | .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 35 | .and() 36 | .authorizeRequests() 37 | .antMatchers("/**") 38 | .permitAll() 39 | .and() 40 | .csrf() 41 | .disable(); 42 | // @formatter:on 43 | } 44 | 45 | @Bean 46 | public CorsConfigurationSource corsConfigurationSource() { 47 | final CorsConfiguration configuration = new CorsConfiguration(); 48 | configuration.setAllowedOrigins(ImmutableList.of("*")); 49 | configuration.setAllowedMethods(ImmutableList.of("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH")); 50 | 51 | // setAllowCredentials(true) is important, otherwise: 52 | // The value of the 'Access-Control-Allow-Origin' header in the response must 53 | // not be the wildcard '*' when the request's credentials mode is 'include'. 54 | configuration.setAllowCredentials(true); 55 | 56 | // setAllowedHeaders is important! Without it, OPTIONS preflight request 57 | // will fail with 403 Invalid CORS request 58 | configuration.setAllowedHeaders(ImmutableList.of("*")); 59 | 60 | final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 61 | source.registerCorsConfiguration("/**", configuration); 62 | return source; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /api-gateway/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: 3 | org: 4 | springframework: 5 | security: DEBUG -------------------------------------------------------------------------------- /api-gateway/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: api-gateway 4 | cloud: 5 | config: 6 | uri: http://localhost:8888 7 | 8 | --- 9 | 10 | spring: 11 | profiles: docker 12 | cloud: 13 | config: 14 | uri: http://configserver:8888 -------------------------------------------------------------------------------- /api-gateway/src/main/resources/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SPRING_ACTIVE_PROFILE=${SPRING_ACTIVE_PROFILE:-"local-docker"} 4 | GIT_BRANCH_LABEL=${GIT_BRANCH_LABEL:-"develop"} 5 | 6 | # The environment variables are already set up by the Dockerfile 7 | exec java -Djava.security.egd=file:/dev/urandom -Dspring.profiles.active=${SPRING_ACTIVE_PROFILE} -Dgit.config.active.branch=${GIT_BRANCH_LABEL} -Duser.timezone=Asia/Kolkata -XX:+PrintFlagsFinal $JAVA_OPTIONS -jar ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar -------------------------------------------------------------------------------- /auth-server/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | .classpath -------------------------------------------------------------------------------- /auth-server/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | auth-server 4 | 5 | 6 | 7 | org.springsource.ide.eclipse.gradle.core.nature 8 | org.eclipse.jdt.core.javanature 9 | 10 | 11 | 12 | org.eclipse.jdt.core.javabuilder 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /auth-server/.settings/gradle/org.springsource.ide.eclipse.gradle.core.import.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleImportPreferences 2 | #Mon Apr 06 13:25:59 PDT 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | enableDependendencyManagement=true 10 | projects=; 11 | -------------------------------------------------------------------------------- /auth-server/.settings/gradle/org.springsource.ide.eclipse.gradle.core.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleProjectPreferences 2 | #Mon Apr 06 13:26:03 PDT 2015 3 | org.springsource.ide.eclipse.gradle.linkedresources= 4 | org.springsource.ide.eclipse.gradle.rootprojectloc= 5 | -------------------------------------------------------------------------------- /auth-server/.settings/gradle/org.springsource.ide.eclipse.gradle.refresh.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.actions.GradleRefreshPreferences 2 | #Mon Apr 06 13:26:02 PDT 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | useHierarchicalNames=false 10 | -------------------------------------------------------------------------------- /auth-server/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.arguments= 2 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) 3 | connection.java.home=null 4 | connection.jvm.arguments= 5 | connection.project.dir= 6 | derived.resources=.gradle,build 7 | eclipse.preferences.version=1 8 | project.path=\: 9 | -------------------------------------------------------------------------------- /auth-server/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | # 2 | #Thu Apr 27 19:30:44 IST 2017 3 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 7 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 8 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 9 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 10 | eclipse.preferences.version=1 11 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 12 | org.eclipse.jdt.core.compiler.source=1.8 13 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 14 | -------------------------------------------------------------------------------- /auth-server/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Build file for authorization server 3 | */ 4 | apply plugin: 'java' 5 | apply plugin: 'org.springframework.boot' 6 | apply plugin: 'application' 7 | apply plugin: 'docker' 8 | apply plugin: 'eclipse' 9 | 10 | buildscript { 11 | project.ext { 12 | springBootVersion = '1.5.6.RELEASE' 13 | jarName = 'basic-auth-server' 14 | versionName = '0.0.1' 15 | gradleDockerVersion = '1.2' 16 | swagger2version = '2.7.0' 17 | } 18 | repositories { 19 | jcenter() 20 | mavenCentral() 21 | } 22 | 23 | dependencies { 24 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.springBootVersion}" 25 | classpath "se.transmode.gradle:gradle-docker:${project.gradleDockerVersion}" 26 | } 27 | } 28 | 29 | task createWrapper(type: Wrapper) { 30 | gradleVersion = '3.5' 31 | } 32 | 33 | // Used by the Docker gradle plugin, group refers to the account under which the docker image is created 34 | group = 'anilallewar' 35 | mainClassName = 'com.anilallewar.microservices.auth.AuthServerApplication' 36 | sourceCompatibility = 1.8 37 | targetCompatibility = 1.8 38 | 39 | repositories { 40 | mavenCentral() 41 | jcenter() 42 | } 43 | 44 | ext { 45 | springCloudVersion = 'Dalston.SR3' 46 | } 47 | 48 | dependencyManagement { 49 | imports { 50 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 51 | } 52 | } 53 | 54 | dependencies { 55 | // Basic Spring boot with config client 56 | compile('org.springframework.cloud:spring-cloud-starter-config') 57 | compile("org.springframework.boot:spring-boot-starter-web") 58 | compile("org.springframework.boot:spring-boot-starter-actuator") 59 | compile("org.springframework.boot:spring-boot-starter-freemarker") 60 | 61 | // Spring OAuth2 security 62 | compile("org.springframework.boot:spring-boot-starter-security") 63 | compile("org.springframework.security.oauth:spring-security-oauth2") 64 | compile("org.springframework.security:spring-security-jwt") 65 | 66 | // Eureka client 67 | compile('org.springframework.cloud:spring-cloud-starter-eureka') 68 | 69 | // JPA for persisting user data 70 | compile("org.springframework.boot:spring-boot-starter-data-jpa") 71 | compile("mysql:mysql-connector-java:8.0.13") 72 | 73 | // Swagger for API testing 74 | compile("io.springfox:springfox-swagger2:${swagger2version}") 75 | compile("io.springfox:springfox-swagger-ui:${swagger2version}") 76 | } 77 | 78 | jar { 79 | baseName = "${project.jarName}" 80 | version = "${project.versionName}" 81 | } 82 | 83 | /* 84 | * This task builds the docker image by copying the output of the "jar" gradle command 85 | * and moving it to the "build/docker" directory which is used as the staging directory 86 | * by the docker gradle plugin. We then build the docker image by invoking the appropriate 87 | * Dockerfile. 88 | */ 89 | task buildDocker(type: Docker, dependsOn: build) { 90 | push = false 91 | applicationName = jar.baseName 92 | tagVersion = jar.version 93 | dockerfile = file('src/main/docker/Dockerfile') 94 | doFirst { 95 | // Copy the built fat jar to the Docker plugin staging directory 96 | copy { 97 | from jar 98 | into stageDir 99 | } 100 | // Copy the run.sh file to the Docker plugin staging directory 101 | copy { 102 | from "${project.buildDir}/resources/main/run.sh" 103 | into stageDir 104 | } 105 | } 106 | } 107 | 108 | run { 109 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4100,suspend=n','-Dspring.profiles.active=default'] 110 | } 111 | -------------------------------------------------------------------------------- /auth-server/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/auth-server/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /auth-server/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Apr 25 12:56:47 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip 7 | -------------------------------------------------------------------------------- /auth-server/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /auth-server/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------------------------------- 2 | # Authorization Server 3 | #----------------------------------------------------------------------------------------------------- 4 | FROM openjdk:8u121-jdk-alpine 5 | 6 | MAINTAINER Anil Allewar 7 | 8 | # Keep consistent with build.gradle 9 | ENV APP_JAR_NAME basic-auth-server 10 | ENV APP_JAR_VERSION 0.0.1 11 | 12 | # Install curl 13 | RUN apk --update add curl bash && \ 14 | rm -rf /var/cache/apk/* 15 | 16 | RUN mkdir /app 17 | 18 | ADD ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar /app/ 19 | ADD run.sh /app/ 20 | RUN chmod +x /app/run.sh 21 | 22 | WORKDIR /app 23 | 24 | EXPOSE 8899 25 | 26 | ENTRYPOINT ["/bin/bash","-c"] 27 | CMD ["/app/run.sh"] 28 | -------------------------------------------------------------------------------- /auth-server/src/main/java/com/anilallewar/microservices/auth/AuthServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.auth; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 7 | 8 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 9 | 10 | /** 11 | * The Main Spring Boot Application class that starts the authorization 12 | * server.
13 | *
14 | * 15 | * Note that the server is also a Eureka client so as to register with the 16 | * Eureka server and be auto-discovered by other Eureka clients. 17 | * 18 | * @author anilallewar 19 | */ 20 | @SpringBootApplication 21 | @EnableEurekaClient 22 | @EnableResourceServer 23 | //@SessionAttributes("authorizationRequest") 24 | @EnableSwagger2 25 | public class AuthServerApplication { 26 | 27 | public static void main(String[] args) { 28 | SpringApplication.run(AuthServerApplication.class, args); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /auth-server/src/main/java/com/anilallewar/microservices/auth/api/AuthUserController.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.auth.api; 2 | 3 | import java.security.Principal; 4 | 5 | import org.springframework.http.MediaType; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestMethod; 8 | import org.springframework.web.bind.annotation.ResponseBody; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | /** 12 | * REST endpoint to be used by other micro-services using SSO to validate the 13 | * authentication of the logged in user. 14 | * 15 | * Since the "me" endpoint needs to be protected to be accessed only after the 16 | * OAuth2 authentication is successful; the OAuth2 server also becomes a 17 | * resource server. 18 | * 19 | * @author anilallewar 20 | * 21 | */ 22 | @RestController 23 | public class AuthUserController { 24 | 25 | /** 26 | * Return the principal identifying the logged in user 27 | * 28 | * @param user 29 | * @return 30 | */ 31 | @RequestMapping(path = "/me", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) 32 | @ResponseBody 33 | public Principal getCurrentLoggedInUser(Principal user) { 34 | return user; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /auth-server/src/main/java/com/anilallewar/microservices/auth/config/OAuthWebFormConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.auth.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.core.annotation.Order; 6 | import org.springframework.security.authentication.AuthenticationManager; 7 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.builders.WebSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 11 | import org.springframework.security.config.http.SessionCreationPolicy; 12 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 13 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 14 | 15 | @Configuration 16 | public class OAuthWebFormConfiguration extends WebMvcConfigurerAdapter { 17 | 18 | @Override 19 | public void addViewControllers(ViewControllerRegistry registry) { 20 | registry.addViewController("/login").setViewName("login"); 21 | registry.addViewController("/oauth/confirm_access").setViewName("authorize"); 22 | } 23 | 24 | @Configuration 25 | @Order(-20) 26 | protected static class LoginConfig extends WebSecurityConfigurerAdapter { 27 | 28 | @Autowired 29 | private AuthenticationManager authenticationManager; 30 | 31 | @Override 32 | protected void configure(HttpSecurity http) throws Exception { 33 | // @formatter:off 34 | http 35 | .sessionManagement() 36 | .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 37 | .and() 38 | .formLogin() 39 | .loginPage("/login") 40 | .permitAll() 41 | .and() 42 | .requestMatchers() 43 | .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access") 44 | .and() 45 | .authorizeRequests() 46 | .anyRequest() 47 | .authenticated(); 48 | // @formatter:on 49 | } 50 | 51 | @Override 52 | protected void configure(AuthenticationManagerBuilder auth) throws Exception { 53 | auth.parentAuthenticationManager(authenticationManager); 54 | } 55 | 56 | // Swagger specific, allow access 57 | @Override 58 | public void configure(WebSecurity web) throws Exception { 59 | // @formatter:off 60 | web 61 | .ignoring() 62 | .antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources/**", "/configuration/**", 63 | "/swagger-ui.html", "/webjars/**"); 64 | // @formatter:on 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /auth-server/src/main/java/com/anilallewar/microservices/auth/service/JdbcUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.auth.service; 2 | 3 | import java.util.LinkedList; 4 | import java.util.List; 5 | 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.security.core.userdetails.UserDetails; 8 | import org.springframework.security.core.userdetails.UserDetailsService; 9 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 10 | 11 | @Configuration 12 | public class JdbcUserDetailsService implements UserDetailsService { 13 | 14 | private List uds = new LinkedList<>(); 15 | 16 | public JdbcUserDetailsService() { 17 | // Default constructor 18 | } 19 | 20 | /** 21 | * Add the default user detail service or any other user detail service so 22 | * that we can validate the user. 23 | * 24 | * @param srv 25 | */ 26 | public void addService(UserDetailsService srv) { 27 | uds.add(srv); 28 | } 29 | 30 | @Override 31 | public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { 32 | if (uds != null) { 33 | for (UserDetailsService srv : uds) { 34 | try { 35 | final UserDetails details = srv.loadUserByUsername(userName); 36 | if (details != null) { 37 | return details; 38 | } 39 | } catch (UsernameNotFoundException ex) { 40 | assert ex != null; 41 | } catch (Exception ex) { 42 | throw ex; 43 | } 44 | } 45 | } 46 | 47 | throw new UsernameNotFoundException("Unknown user"); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /auth-server/src/main/resources/anilkeystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/auth-server/src/main/resources/anilkeystore.jks -------------------------------------------------------------------------------- /auth-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: 3 | org: 4 | springframework: 5 | security: DEBUG -------------------------------------------------------------------------------- /auth-server/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: auth-server 4 | cloud: 5 | config: 6 | uri: http://localhost:8888 7 | 8 | --- 9 | 10 | spring: 11 | profiles: docker 12 | cloud: 13 | config: 14 | uri: http://configserver:8888 15 | -------------------------------------------------------------------------------- /auth-server/src/main/resources/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SPRING_ACTIVE_PROFILE=${SPRING_ACTIVE_PROFILE:-"local-docker"} 4 | GIT_BRANCH_LABEL=${GIT_BRANCH_LABEL:-"develop"} 5 | 6 | # The environment variables are already set up by the Dockerfile 7 | exec java -Djava.security.egd=file:/dev/urandom -Dspring.profiles.active=${SPRING_ACTIVE_PROFILE} -Dgit.config.active.branch=${GIT_BRANCH_LABEL} -Duser.timezone=Asia/Kolkata -XX:+PrintFlagsFinal $JAVA_OPTIONS -jar ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar -------------------------------------------------------------------------------- /auth-server/src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `users`; 2 | CREATE TABLE `users` ( 3 | `username` varchar(50) NOT NULL, 4 | `password` varchar(50) NOT NULL, 5 | `enabled` tinyint(1) NOT NULL, 6 | PRIMARY KEY (`username`) 7 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 8 | 9 | DROP TABLE IF EXISTS `authorities`; 10 | CREATE TABLE `authorities` ( 11 | `username` varchar(50) NOT NULL, 12 | `authority` varchar(50) NOT NULL, 13 | UNIQUE KEY `ix_auth_username` (`username`,`authority`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 15 | 16 | DROP TABLE IF EXISTS `oauth_client_details`; 17 | CREATE TABLE `oauth_client_details` ( 18 | `client_id` varchar(256) NOT NULL, 19 | `resource_ids` varchar(256) DEFAULT NULL, 20 | `client_secret` varchar(256) DEFAULT NULL, 21 | `scope` varchar(256) DEFAULT NULL, 22 | `authorized_grant_types` varchar(256) DEFAULT NULL, 23 | `web_server_redirect_uri` varchar(256) DEFAULT NULL, 24 | `authorities` varchar(256) DEFAULT NULL, 25 | `access_token_validity` int(11) DEFAULT NULL, 26 | `refresh_token_validity` int(11) DEFAULT NULL, 27 | `additional_information` varchar(4096) DEFAULT NULL, 28 | `autoapprove` varchar(256) DEFAULT NULL, 29 | PRIMARY KEY (`client_id`) 30 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -------------------------------------------------------------------------------- /auth-server/src/main/resources/templates/authorize.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 |
8 |

Please Confirm

9 | 10 |

11 | Do you authorize "${authorizationRequest.clientId}" at "${authorizationRequest.redirectUri}" to access your protected resources 12 | with scope ${authorizationRequest.scope?join(", ")}. 13 |

14 |
16 | 17 | 18 | 19 |
20 |
22 | 23 | 24 | 25 |
26 |
27 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /auth-server/src/main/resources/templates/login.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | <#if RequestParameters['error']??> 8 |
9 | There was a problem logging in. Please try again. 10 |
11 | 12 |
13 |
14 |
15 | 16 | 17 |
18 |
19 | 20 | 21 |
22 | 23 | 24 |
25 |
26 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /build-all-projects.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd api-gateway; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build; cd .. 4 | cd auth-server; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build; cd .. 5 | cd config-server; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build; cd .. 6 | cd comments-webservice; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build publishToMavenLocal; cd .. 7 | cd task-webservice; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build; cd .. 8 | cd user-webservice; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build; cd .. 9 | cd web-portal; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build; cd .. 10 | cd webservice-registry; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build; cd .. 11 | cd zipkin-server; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build ; cd .. 12 | -------------------------------------------------------------------------------- /comments-webservice/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | .DS_Store 4 | /.gradle/ 5 | .classpath 6 | -------------------------------------------------------------------------------- /comments-webservice/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | comments-webservice 4 | 5 | 6 | 7 | org.springsource.ide.eclipse.gradle.core.nature 8 | org.eclipse.jdt.core.javanature 9 | org.eclipse.jdt.groovy.core.groovyNature 10 | 11 | 12 | 13 | org.eclipse.jdt.core.javabuilder 14 | 15 | 16 | 17 | 18 | 19 | 20 | 1 21 | 22 22 | 23 | 24 | org.eclipse.ui.ide.multiFilter 25 | 1.0-name-matches-false-false-.DS_Store 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /comments-webservice/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.arguments= 2 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) 3 | connection.java.home=null 4 | connection.jvm.arguments= 5 | connection.project.dir= 6 | derived.resources=.gradle,build 7 | eclipse.preferences.version=1 8 | project.path=\: 9 | -------------------------------------------------------------------------------- /comments-webservice/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | # 2 | #Mon Jul 03 12:13:20 IST 2017 3 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 7 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 8 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 9 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 10 | eclipse.preferences.version=1 11 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 12 | org.eclipse.jdt.core.compiler.source=1.8 13 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 14 | -------------------------------------------------------------------------------- /comments-webservice/.settings/org.eclipse.jdt.groovy.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | groovy.compiler.level=24 3 | -------------------------------------------------------------------------------- /comments-webservice/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | This application provides the **comments** related functionality and serves as one component. It defines the REST endpoints that are used to provide comment functionality. 4 | 5 | Note that this component is only used internally by the "task" microservice and is NOT actually exposed at the API gateway level. 6 | 7 | ##Pre-requisites 8 | 9 | ### Projects that need to be started before 10 | * [config server](/../../blob/master/config-server/README.md) - For pulling the configuration information 11 | * [webserver-registry](/../../blob/master/webservice-registry/README.md) - For starting the Eureka server since the authorization server also is a micro-service that needs to be registered with Eureka server. 12 | 13 | ### Running the application 14 | * Build the application by running the `./gradlew clean build` gradle command at the "comments-webservice" project root folder on the terminal. 15 | * If you want to run the application as jar file, then run `java -jar build/libs/basic-comments-webservice-0.0.1.jar` command at the terminal. 16 | 17 | ## External Configuration 18 | Please refer to [user webservice](/../../blob/master/user-webservice/README.md) for details on how the external configuration works. Note that there is separate configuration file for each Spring application; the application should refer to it's own .yml file for configuration. 19 | 20 | ## Consumer Driven Contracts 21 | * The comments webservice is consumed by the task-webservice and hence needs to adhere to the contract which is provided to the consumer. 22 | * We use consumer driven contracts to create the producer contracts and auto-generate tests. The implementation of CDC is `Spring Cloud Contract Verifier` that provides the following 23 | * Contract Definition Language (DSL) 24 | * Definition either in groovy or pact format 25 | * Used to produce following resources 26 | * JSON stub definitions 27 | * Used by client side 28 | * Test written by hand, test data provided by Spring 29 | * Server tests 30 | * Test generated by Spring 31 | * The contract and associated class is defined under the `src/test` folder. 32 | * To publish the contract stubs to the local maven repository, run the following gradle task 33 | ``` 34 | ./gradlew clean build publishToMavenLocal 35 | ``` 36 | -------------------------------------------------------------------------------- /comments-webservice/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/comments-webservice/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /comments-webservice/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 26 15:26:43 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip 7 | -------------------------------------------------------------------------------- /comments-webservice/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /comments-webservice/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------------------------------- 2 | # User Service 3 | #----------------------------------------------------------------------------------------------------- 4 | FROM openjdk:8u121-jdk-alpine 5 | 6 | MAINTAINER Anil Allewar 7 | 8 | # Keep consistent with build.gradle 9 | ENV APP_JAR_NAME basic-comments-webservice 10 | ENV APP_JAR_VERSION 0.0.1 11 | 12 | # Install curl 13 | RUN apk --update add curl bash && \ 14 | rm -rf /var/cache/apk/* 15 | 16 | RUN mkdir /app 17 | 18 | ADD ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar /app/ 19 | ADD run.sh /app/ 20 | RUN chmod +x /app/run.sh 21 | 22 | WORKDIR /app 23 | 24 | EXPOSE 8080 25 | 26 | ENTRYPOINT ["/bin/bash","-c"] 27 | CMD ["/app/run.sh"] 28 | -------------------------------------------------------------------------------- /comments-webservice/src/main/java/com/anilallewar/microservices/comments/CommentsApplication.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.comments; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 7 | 8 | /** 9 | * The boot application class that defines the spring boot application to have 10 | * the following properties
11 | *
12 | * 13 | *
    14 | *
  1. Act as a Eureka client; this behavior is provided by the 15 | * {@link EnableEurekaClient} annotation. The Eureka server URL is provided by 16 | * the external configuration provided by the config server.
  2. 17 | *
  3. {@link EnableEurekaClient} makes the app into both a Eureka "instance" (i.e. it 18 | * registers itself) and a "client" (i.e. it can query the registry to locate 19 | * other services).
  4. 20 | *
  5. Note that all these annotations work in conjunction with properties 21 | * defined in the external configuration files specified by the config server. 22 | *
  6. 23 | *
24 | * 25 | * @author anilallewar 26 | * 27 | */ 28 | @SpringBootApplication 29 | @EnableEurekaClient 30 | @EnableResourceServer 31 | public class CommentsApplication { 32 | public static void main(String[] args) { 33 | 34 | SpringApplication.run(CommentsApplication.class,args); 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /comments-webservice/src/main/java/com/anilallewar/microservices/comments/apis/CommentsController.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.comments.apis; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | import java.util.logging.Level; 9 | import java.util.logging.Logger; 10 | 11 | import org.springframework.web.bind.annotation.PathVariable; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RequestMethod; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | import com.anilallewar.microservices.comments.dtos.CommentDTO; 17 | 18 | /** 19 | * REST endpoint for the comments functionality
20 | *
21 | * 22 | * Note that this endpoint is supposed to be consumed by the Task webservice and 23 | * is not accessible to the general public; i.e. the api-gateway doesn't handle 24 | * requests for comments-webservice. 25 | * 26 | * @author anilallewar 27 | * 28 | */ 29 | @RestController 30 | @RequestMapping("/comments") 31 | public class CommentsController { 32 | 33 | private static final Logger LOGGER = Logger.getLogger(CommentsController.class.getName()); 34 | 35 | private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); 36 | 37 | private List comments = null; 38 | 39 | /** 40 | * Public constructor to initialize the comments and handle the 41 | * ParseException 42 | * 43 | * @throws ParseException 44 | */ 45 | public CommentsController() throws ParseException { 46 | this.comments = Arrays.asList(new CommentDTO("task11", "comment on task11", formatter.parse("2015-04-23")), 47 | new CommentDTO("task12", "comment on task12", formatter.parse("2015-05-12")), 48 | new CommentDTO("task11", "new comment on task11", formatter.parse("2015-04-27")), 49 | new CommentDTO("task21", "comment on task21", formatter.parse("2015-01-15")), 50 | new CommentDTO("task22", "comment on task22", formatter.parse("2015-03-05"))); 51 | } 52 | 53 | /** 54 | * Get comments for specific taskid that is passed in the path. 55 | * 56 | * @param taskId 57 | * @return 58 | */ 59 | @RequestMapping(value = "/{taskId}", method = RequestMethod.GET, headers = "Accept=application/json") 60 | public List getCommentsByTaskId(@PathVariable("taskId") String taskId) { 61 | List commentListToReturn = new ArrayList<>(); 62 | for (CommentDTO currentComment : comments) { 63 | if (currentComment.getTaskId().equalsIgnoreCase(taskId)) { 64 | if (LOGGER.isLoggable(Level.INFO)) { 65 | LOGGER.info(String.format("Found matching comments for task [%s] with comment [%s]", taskId, 66 | currentComment.getComment())); 67 | } 68 | commentListToReturn.add(currentComment); 69 | } 70 | } 71 | 72 | return commentListToReturn; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /comments-webservice/src/main/resources/application.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/comments-webservice/src/main/resources/application.yml -------------------------------------------------------------------------------- /comments-webservice/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | 4 | # Name of the service that is using with Zuul routes to forward specific requests to this service 5 | name: comments-webservice 6 | cloud: 7 | config: 8 | 9 | # Define the URL from where this service would pick up it's external configuration. Note that it is 10 | # pointing to the config-server aplication 11 | uri: http://localhost:8888 12 | 13 | --- 14 | 15 | spring: 16 | profiles: docker 17 | cloud: 18 | config: 19 | uri: http://configserver:8888 -------------------------------------------------------------------------------- /comments-webservice/src/main/resources/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SPRING_ACTIVE_PROFILE=${SPRING_ACTIVE_PROFILE:-"local-docker"} 4 | GIT_BRANCH_LABEL=${GIT_BRANCH_LABEL:-"develop"} 5 | 6 | # The environment variables are already set up by the Dockerfile 7 | exec java -Djava.security.egd=file:/dev/urandom -Dspring.profiles.active=${SPRING_ACTIVE_PROFILE} -Dgit.config.active.branch=${GIT_BRANCH_LABEL} -Duser.timezone=Asia/Kolkata -XX:+PrintFlagsFinal $JAVA_OPTIONS -jar ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar -------------------------------------------------------------------------------- /comments-webservice/src/test/java/com/anilallewar/microservices/comments/contracts/TaskCommentsBase.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.comments.contracts; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | import org.junit.Before; 7 | import org.junit.Ignore; 8 | import org.junit.runner.RunWith; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 12 | import org.springframework.test.context.junit4.SpringRunner; 13 | import org.springframework.web.context.WebApplicationContext; 14 | 15 | import com.anilallewar.microservices.comments.CommentsApplication; 16 | import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc; 17 | 18 | /** 19 | * Base class for the generated contract provider tests
20 | *
21 | * 22 | * The name of the class if defined by 2 things 23 | *
    24 | *
  1. Sub-folder under the contractsDir while defaults to 25 | * /src/test/resources/contracts
  2. 26 | *
  3. packageWithBaseClasses defined in build.gradle
  4. 27 | *
  5. Since the package for base classes is defined as 28 | * com.anilallewar.microservices.comments.contracts and the 29 | * contract is defined under the task/comments folder under 30 | * test/resources/contracts, the base class name is TaskCommentsBase
  6. 31 | *
32 | * 33 | * @author anilallewar 34 | * 35 | */ 36 | @Ignore 37 | @RunWith(SpringRunner.class) 38 | @SpringBootTest(classes = { CommentsApplication.class }, webEnvironment = WebEnvironment.MOCK, properties = { 39 | "spring.cloud.discovery.enabled=false", "spring.cloud.config.enabled=false" }) 40 | public abstract class TaskCommentsBase { 41 | 42 | @Autowired 43 | private WebApplicationContext context; 44 | 45 | @Before 46 | public void setUp() throws Exception { 47 | RestAssuredMockMvc.webAppContextSetup(context); 48 | } 49 | 50 | private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); 51 | 52 | /** 53 | * Return the formatted date for validation 54 | * 55 | * @param timeValue 56 | * @return 57 | */ 58 | public String convertTimeValueToDate(Long timeValue) { 59 | return dateFormat.format(new Date(timeValue)); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /comments-webservice/src/test/resources/contracts/task/comments/returnCommentsForTasks.groovy: -------------------------------------------------------------------------------- 1 | package contracts.task.comments; 2 | 3 | import org.springframework.cloud.contract.spec.Contract; 4 | 5 | Contract.make { 6 | name("comments-for-task") 7 | description(''' 8 | Represents a successful scenario of getting a comments for task 9 | ``` 10 | given: 11 | comments exists for task 12 | when: 13 | when comments requested for task 14 | then: 15 | send the comments for the task 16 | ``` 17 | ''') 18 | request { 19 | method 'GET' 20 | url $(consumer(regex('/comments/([0-9a-zA-z]+)')), producer('/comments/task11')) 21 | headers { 22 | accept(applicationJson()) 23 | } 24 | } 25 | response { 26 | status 200 27 | body( [ 28 | [ 29 | "taskId": "task11", 30 | "comment": "comment on task11", 31 | "posted": $(consumer('2015-04-23'),producer(execute('convertTimeValueToDate($it)'))) 32 | ], 33 | [ 34 | "taskId": "task11", 35 | "comment":"new comment on task11", 36 | "posted": $(consumer("2015-04-27"),producer(execute('convertTimeValueToDate($it)'))) 37 | ] 38 | ] 39 | ) 40 | headers { 41 | contentType('application/json') 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /config-server/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | .classpath 5 | -------------------------------------------------------------------------------- /config-server/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | config-server 4 | 5 | 6 | 7 | org.springsource.ide.eclipse.gradle.core.nature 8 | org.eclipse.jdt.core.javanature 9 | 10 | 11 | 12 | org.eclipse.jdt.core.javabuilder 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /config-server/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | # 2 | #Wed Nov 14 13:55:58 IST 2018 3 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 7 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 8 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 9 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 10 | eclipse.preferences.version=1 11 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 12 | org.eclipse.jdt.core.compiler.source=1.8 13 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 14 | -------------------------------------------------------------------------------- /config-server/README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | This application loads and makes the **external configuration** available to rest of the applications. Note that the external configuration can be hosted either on GitHub or on local file system. 4 | 5 | The respective applications pick up the configuration based on a `.yml` file defined in the configuration by matching the service's `spring.application.name` property defined in the `bootstrap.yml` file. 6 | 7 | ## Pre-requisites 8 | 9 | ### Projects that need to be started before 10 | * This is the first application that needs to run since it pulls the configuration information(like what port to run etc) that is needed by rest of the applications to start. 11 | 12 | ### Running the application 13 | * Build the application by running the `./gradlew clean build` gradle command at the "config-server" project root folder on the terminal. 14 | * If you want to run the application as jar file, then run `java -jar build/libs/basic-config-server-0.0.1.jar` command at the terminal. 15 | -------------------------------------------------------------------------------- /config-server/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Build file for config server 3 | */ 4 | apply plugin: 'java' 5 | apply plugin: 'org.springframework.boot' 6 | apply plugin: 'application' 7 | apply plugin: 'docker' 8 | apply plugin: 'eclipse' 9 | 10 | buildscript { 11 | project.ext { 12 | springBootVersion = '1.5.6.RELEASE' 13 | jarName = 'basic-config-server' 14 | versionName = '0.0.1' 15 | gradleDockerVersion = '1.2' 16 | } 17 | repositories { 18 | jcenter() 19 | mavenCentral() 20 | } 21 | 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.springBootVersion}" 24 | classpath "se.transmode.gradle:gradle-docker:${project.gradleDockerVersion}" 25 | } 26 | } 27 | 28 | task createWrapper(type: Wrapper) { 29 | gradleVersion = '3.5' 30 | } 31 | 32 | // Used by the Docker gradle plugin, group refers to the account under which the docker image is created 33 | group = 'anilallewar' 34 | mainClassName = 'com.anilallewar.microservices.config.ConfigApplication' 35 | sourceCompatibility = 1.8 36 | targetCompatibility = 1.8 37 | 38 | repositories { 39 | mavenCentral() 40 | jcenter() 41 | } 42 | 43 | ext { 44 | springCloudVersion = 'Dalston.SR3' 45 | } 46 | 47 | dependencyManagement { 48 | imports { 49 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 50 | } 51 | } 52 | 53 | 54 | dependencies { 55 | compile("org.springframework.cloud:spring-cloud-config-server") 56 | } 57 | 58 | jar { 59 | baseName = "${project.jarName}" 60 | version = "${project.versionName}" 61 | } 62 | 63 | /* 64 | * This task builds the docker image by copying the output of the "jar" gradle command 65 | * and moving it to the "build/docker" directory which is used as the staging directory 66 | * by the docker gradle plugin. We then build the docker image by invoking the appropriate 67 | * Dockerfile. 68 | */ 69 | task buildDocker(type: Docker, dependsOn: build) { 70 | push = false 71 | applicationName = jar.baseName 72 | tagVersion = jar.version 73 | dockerfile = file('src/main/docker/Dockerfile') 74 | doFirst { 75 | // Copy the built fat jar to the Docker plugin staging directory 76 | copy { 77 | from jar 78 | into stageDir 79 | } 80 | // Copy the run.sh file to the Docker plugin staging directory 81 | copy { 82 | from "${project.buildDir}/resources/main/run.sh" 83 | into stageDir 84 | } 85 | } 86 | } 87 | 88 | run { 89 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4100,suspend=n','-Dspring.profiles.active=default'] 90 | } -------------------------------------------------------------------------------- /config-server/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/config-server/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /config-server/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Apr 21 16:25:12 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip 7 | -------------------------------------------------------------------------------- /config-server/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /config-server/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------------------------------- 2 | # Config Server 3 | #----------------------------------------------------------------------------------------------------- 4 | FROM openjdk:8u121-jdk-alpine 5 | 6 | MAINTAINER Anil Allewar 7 | 8 | # Keep consistent with build.gradle 9 | ENV APP_JAR_NAME basic-config-server 10 | ENV APP_JAR_VERSION 0.0.1 11 | 12 | # Install curl, bash and mysql-client to check if DB is up 13 | RUN apk --update add curl bash mysql-client && \ 14 | rm -rf /var/cache/apk/* 15 | 16 | RUN mkdir /app 17 | 18 | ADD ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar /app/ 19 | ADD run.sh /app/ 20 | RUN chmod +x /app/run.sh 21 | 22 | WORKDIR /app 23 | 24 | EXPOSE 8888 25 | 26 | ENTRYPOINT ["/bin/bash","-c"] 27 | CMD ["/app/run.sh"] 28 | -------------------------------------------------------------------------------- /config-server/src/main/java/com/anilallewar/microservices/config/ConfigApplication.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.config; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.config.server.EnableConfigServer; 6 | 7 | 8 | /** 9 | * The Main Spring Boot Application class.
10 | *
11 | * 12 | * The {@link EnableConfigServer} annotation defines that this application will 13 | * serve as the REST based API for providing external configuration.
14 | *
15 | * 16 | * The external repository from where the configuration will be picked up is 17 | * defined in the {@linkplain application.yml} file. 18 | * 19 | * @author anilallewar 20 | */ 21 | @EnableConfigServer 22 | @SpringBootApplication 23 | public class ConfigApplication { 24 | 25 | /** 26 | * The main method. 27 | * 28 | * @param args the arguments 29 | */ 30 | public static void main(String[] args) { 31 | SpringApplication.run(ConfigApplication.class, args); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /config-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | server: 5 | git: 6 | uri: https://github.com/anilallewar/microservices-basics-cloud-config 7 | # username: <> 8 | # password: <> 9 | 10 | # While in development mode, you can configure the config server to pick up configuration files from 11 | # the file system 12 | 13 | # uri: file://Users/anilallewar/Documents/Anil Allewar/Trainings/Code Samples/Enterprise Java/Micro Services/sample-config 14 | 15 | # Defines the port where the config server is running so that rest of the services can pick up 16 | # their external configurations 17 | server: 18 | port: 8888 -------------------------------------------------------------------------------- /config-server/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: configserver -------------------------------------------------------------------------------- /config-server/src/main/resources/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SPRING_ACTIVE_PROFILE=${SPRING_ACTIVE_PROFILE:-"local-docker"} 4 | GIT_BRANCH_LABEL=${GIT_BRANCH_LABEL:-"develop"} 5 | 6 | # The environment variables are already set up by the Dockerfile 7 | exec java -Djava.security.egd=file:/dev/urandom -Dspring.profiles.active=${SPRING_ACTIVE_PROFILE} -Dgit.config.active.branch=${GIT_BRANCH_LABEL} -Duser.timezone=Asia/Kolkata $JAVA_OPTIONS -jar ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar -------------------------------------------------------------------------------- /docker-image-all-projects.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd api-gateway; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build buildDocker; cd .. 4 | cd auth-server; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build buildDocker; cd .. 5 | cd config-server; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build buildDocker; cd .. 6 | cd comments-webservice; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build publishToMavenLocal buildDocker; cd .. 7 | cd task-webservice; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build buildDocker; cd .. 8 | cd user-webservice; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build buildDocker; cd .. 9 | cd web-portal; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build buildDocker; cd .. 10 | cd webservice-registry; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build buildDocker; cd .. 11 | cd zipkin-server; echo "\033[1;96m Execution directory: `pwd | xargs basename` \033[0m"; ./gradlew clean build buildDocker; cd .. 12 | -------------------------------------------------------------------------------- /docker-orchestration/docker-compose/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.1' 2 | services: 3 | mysqldb: 4 | image: mysql:latest 5 | mem_limit: 1073741824 6 | restart: unless-stopped 7 | healthcheck: 8 | test: ["CMD", "mysqladmin", "ping", "-hmysqldb", "-uroot", "-ppassword", "--silent"] 9 | interval: 5s 10 | timeout: 3s 11 | retries: 5 12 | ports: 13 | - "3306/tcp" 14 | environment: 15 | MYSQL_ROOT_PASSWORD: password 16 | MYSQL_DATABASE: auth 17 | 18 | configserver: 19 | image: anilallewar/basic-config-server:0.0.1 20 | mem_limit: 1073741824 21 | restart: unless-stopped 22 | healthcheck: 23 | test: ["CMD", "curl", "-I", "http://configserver:8888"] 24 | interval: 5s 25 | timeout: 3s 26 | retries: 5 27 | ports: 28 | - "8888/tcp" 29 | depends_on: 30 | mysqldb: 31 | condition: service_healthy 32 | 33 | eurekaregistry: 34 | image: anilallewar/basic-webservice-registry:0.0.1 35 | mem_limit: 1073741824 36 | restart: unless-stopped 37 | healthcheck: 38 | test: ["CMD", "curl", "-f", "http://eurekaregistry:8761"] 39 | interval: 5s 40 | timeout: 3s 41 | retries: 10 42 | ports: 43 | - "8761:8761/tcp" 44 | depends_on: 45 | configserver: 46 | condition: service_healthy 47 | 48 | authserver: 49 | image: anilallewar/basic-auth-server:0.0.1 50 | mem_limit: 1073741824 51 | restart: unless-stopped 52 | ports: 53 | - "8899/tcp" 54 | depends_on: 55 | eurekaregistry: 56 | condition: service_healthy 57 | 58 | apigateway: 59 | image: anilallewar/basic-api-gateway:0.0.1 60 | mem_limit: 1073741824 61 | restart: unless-stopped 62 | ports: 63 | - "8765:8765/tcp" 64 | depends_on: 65 | eurekaregistry: 66 | condition: service_healthy 67 | 68 | webportal: 69 | image: anilallewar/basic-web-portal:0.0.1 70 | mem_limit: 1073741824 71 | restart: unless-stopped 72 | ports: 73 | - "8080/tcp" 74 | depends_on: 75 | eurekaregistry: 76 | condition: service_healthy 77 | 78 | userwebservice: 79 | image: anilallewar/basic-user-webservice:0.0.1 80 | mem_limit: 1073741824 81 | restart: unless-stopped 82 | ports: 83 | - "8080/tcp" 84 | depends_on: 85 | eurekaregistry: 86 | condition: service_healthy 87 | 88 | taskwebservice: 89 | image: anilallewar/basic-task-webservice:0.0.1 90 | mem_limit: 1073741824 91 | restart: unless-stopped 92 | ports: 93 | - "8080/tcp" 94 | depends_on: 95 | eurekaregistry: 96 | condition: service_healthy 97 | 98 | commentswebservice: 99 | image: anilallewar/basic-comments-webservice:0.0.1 100 | mem_limit: 1073741824 101 | restart: unless-stopped 102 | ports: 103 | - "8080/tcp" 104 | depends_on: 105 | eurekaregistry: 106 | condition: service_healthy 107 | 108 | zipkinserver: 109 | image: anilallewar/basic-zipkin-server:0.0.1 110 | mem_limit: 1073741824 111 | restart: unless-stopped 112 | ports: 113 | - "9411:9411/tcp" 114 | depends_on: 115 | configserver: 116 | condition: service_healthy 117 | -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/helm-charts/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | How to run the config-service using help charts 4 | 5 | ## Pre-requisites 6 | 7 | * The docker image should have been build previously using the ../../../../docker-image-all-projects.sh 8 | 9 | ## Running the application 10 | * Once you have the helm CLI installed 11 | ** helm install config config-server/ 12 | *** [[config]] - Name of helm release 13 | *** [[ config-server]] - Name of the folder holding the helm charts 14 | ** kubectl get svc,pods,deployment (to check if deployment was successful) 15 | 16 | 17 | ## Checking if app is running or not 18 | ** curl http://localhost:8888/api-gateway/default 19 | *** This should give you the contents from api-gateway.yml 20 | 21 | ## Delete the deployment 22 | ** helm delete config -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/helm-charts/application/app-services/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *~ 18 | # Various IDEs 19 | .project 20 | .idea/ 21 | *.tmproj -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/helm-charts/application/app-services/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | appVersion: "1.0" 3 | description: | 4 | A Helm chart for deploying application services for the Microsercices project in Kubernetes 5 | name: app-microservices-project 6 | version: 0.0.1 -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/helm-charts/application/app-services/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{- define "labels" }} 2 | labels: 3 | generator: helm 4 | date: {{ now | htmlDate }} 5 | release: {{ .Release.Name }} 6 | revision: {{ .Release.Revision | quote }} 7 | chart: {{ .Chart.Name }} 8 | version: {{ .Chart.Version }} 9 | {{- end }} -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/helm-charts/application/app-services/templates/app-service-autoscaler.yml: -------------------------------------------------------------------------------- 1 | apiVersion: autoscaling/v2beta2 2 | kind: HorizontalPodAutoscaler 3 | metadata: 4 | name: user-service-autoscaler 5 | spec: 6 | maxReplicas: {{ .Values.userservice.maxReplicaCount }} 7 | minReplicas: {{ .Values.userservice.replicaCount }} 8 | scaleTargetRef: 9 | apiVersion: app/v1 10 | kind: Deployment 11 | name: {{ .Release.Name }}-user-service 12 | metrics: 13 | - type: Resource 14 | resource: 15 | name: cpu 16 | target: 17 | type: Utilization 18 | averageUtilization: 70 -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/helm-charts/application/app-services/templates/app-service-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: userservice 5 | spec: 6 | selector: 7 | app: {{ .Release.Name }}-user-service 8 | ports: 9 | - name: http 10 | protocol: TCP 11 | port: {{ .Values.service.userservice.internalPort }} 12 | 13 | --- 14 | 15 | apiVersion: v1 16 | kind: Service 17 | metadata: 18 | name: taskservice 19 | spec: 20 | selector: 21 | app: {{ .Release.Name }}-task-service 22 | ports: 23 | - name: http 24 | protocol: TCP 25 | # Not exposing the service to external endpoints 26 | port: {{ .Values.service.taskservice.internalPort }} 27 | 28 | --- 29 | 30 | apiVersion: v1 31 | kind: Service 32 | metadata: 33 | name: commentservice 34 | spec: 35 | selector: 36 | app: {{ .Release.Name }}-comment-service 37 | ports: 38 | - name: http 39 | protocol: TCP 40 | port: {{ .Values.service.commentservice.internalPort }} 41 | targetPort: {{ .Values.service.commentservice.externalPort }} 42 | type: {{ .Values.service.commentservice.type }} -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/helm-charts/application/app-services/values.yaml: -------------------------------------------------------------------------------- 1 | userservice: 2 | image: anilallewar/basic-user-webservice 3 | tag: 0.0.1 4 | replicaCount: 1 5 | maxReplicaCount: 2 6 | javaOptions: -Xms256M -Xmx512M 7 | containerMemoryRequest: 256Mi 8 | containerMemoryLimit: 512Mi 9 | 10 | taskservice: 11 | image: anilallewar/basic-task-webservice 12 | tag: 0.0.1 13 | replicaCount: 1 14 | javaOptions: -Xms256M -Xmx512M 15 | containerMemoryRequest: 256Mi 16 | containerMemoryLimit: 512Mi 17 | 18 | commentservice: 19 | image: anilallewar/basic-comments-webservice 20 | tag: 0.0.1 21 | replicaCount: 1 22 | javaOptions: -Xms256M -Xmx512M 23 | containerMemoryRequest: 256Mi 24 | containerMemoryLimit: 512Mi 25 | 26 | service: 27 | userservice: 28 | type: ClusterIP 29 | internalPort: 8080 30 | taskservice: 31 | # default type is ClusterIP 32 | internalPort: 8080 33 | commentservice: 34 | type: ClusterIP 35 | internalPort: 8080 36 | 37 | image: 38 | pullPolicy: IfNotPresent 39 | 40 | spring: 41 | activeProfile: docker 42 | -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/helm-charts/application/support-services/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *~ 18 | # Various IDEs 19 | .project 20 | .idea/ 21 | *.tmproj -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/helm-charts/application/support-services/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | appVersion: "1.0" 3 | description: | 4 | A Helm chart for deploying supporting services for the Microservices framework application in Kubernetes 5 | name: microservices-support-project 6 | version: 0.0.1 -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/helm-charts/application/support-services/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{- define "labels" }} 2 | labels: 3 | generator: helm 4 | date: {{ now | htmlDate }} 5 | release: {{ .Release.Name }} 6 | revision: {{ .Release.Revision | quote }} 7 | chart: {{ .Chart.Name }} 8 | version: {{ .Chart.Version }} 9 | {{- end }} -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/helm-charts/application/support-services/templates/helper-service-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: mysqldb 5 | spec: 6 | selector: 7 | app: {{ .Release.Name }}-mysql 8 | ports: 9 | - name: http 10 | protocol: TCP 11 | port: {{ .Values.service.mysql.internalPort }} 12 | 13 | --- 14 | 15 | apiVersion: v1 16 | kind: Service 17 | metadata: 18 | name: configserver 19 | spec: 20 | selector: 21 | app: {{ .Release.Name }}-config-server 22 | ports: 23 | - name: http 24 | protocol: TCP 25 | # Not exposing the service to external endpoints 26 | port: {{ .Values.service.configserver.internalPort }} 27 | type: {{ .Values.service.configserver.type }} 28 | 29 | --- 30 | 31 | apiVersion: v1 32 | kind: Service 33 | metadata: 34 | name: eurekaregistry 35 | spec: 36 | selector: 37 | app: {{ .Release.Name }}-eurekaregistry 38 | ports: 39 | - name: http 40 | protocol: TCP 41 | port: {{ .Values.service.eurekaregistry.internalPort }} 42 | targetPort: {{ .Values.service.eurekaregistry.externalPort }} 43 | type: {{ .Values.service.eurekaregistry.type }} 44 | 45 | --- 46 | 47 | apiVersion: v1 48 | kind: Service 49 | metadata: 50 | name: zipkinserver 51 | spec: 52 | selector: 53 | app: {{ .Release.Name }}-zipkin-server 54 | ports: 55 | - name: http 56 | protocol: TCP 57 | port: {{ .Values.service.zipkinserver.internalPort }} 58 | targetPort: {{ .Values.service.zipkinserver.externalPort }} 59 | type: {{ .Values.service.zipkinserver.type }} 60 | 61 | --- 62 | 63 | apiVersion: v1 64 | kind: Service 65 | metadata: 66 | name: authserver 67 | spec: 68 | selector: 69 | app: {{ .Release.Name }}-auth-server 70 | ports: 71 | - name: http 72 | protocol: TCP 73 | port: {{ .Values.service.authserver.internalPort }} 74 | type: {{ .Values.service.authserver.type }} 75 | 76 | --- 77 | 78 | apiVersion: v1 79 | kind: Service 80 | metadata: 81 | name: apigateway 82 | spec: 83 | selector: 84 | app: {{ .Release.Name }}-api-gateway 85 | ports: 86 | - name: http 87 | protocol: TCP 88 | port: {{ .Values.service.apigateway.internalPort }} 89 | type: {{ .Values.service.apigateway.type }} 90 | 91 | 92 | -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/helm-charts/application/support-services/values.yaml: -------------------------------------------------------------------------------- 1 | configserver: 2 | image: anilallewar/basic-config-server 3 | tag: 0.0.1 4 | replicaCount: 1 5 | javaOptions: -Xms256M -Xmx512M 6 | containerMemoryRequest: 256Mi 7 | containerMemoryLimit: 512Mi 8 | 9 | mysql: 10 | image: mysql 11 | tag: latest 12 | replicaCount: 1 13 | containerMemoryRequest: 256Mi 14 | containerMemoryLimit: 1Gi 15 | 16 | eurekaregistry: 17 | image: anilallewar/basic-webservice-registry 18 | tag: 0.0.1 19 | replicaCount: 1 20 | javaOptions: -Xms256M -Xmx512M 21 | containerMemoryRequest: 256Mi 22 | containerMemoryLimit: 512Mi 23 | 24 | zipkinserver: 25 | image: anilallewar/basic-zipkin-server 26 | tag: 0.0.1 27 | replicaCount: 1 28 | javaOptions: -Xms256M -Xmx1G 29 | containerMemoryRequest: 256Mi 30 | containerMemoryLimit: 1Gi 31 | 32 | authserver: 33 | image: anilallewar/basic-auth-server 34 | tag: 0.0.1 35 | replicaCount: 1 36 | javaOptions: -Xms256M -Xmx1G 37 | containerMemoryRequest: 256Mi 38 | containerMemoryLimit: 1Gi 39 | 40 | apigateway: 41 | image: anilallewar/basic-api-gateway 42 | tag: 0.0.1 43 | replicaCount: 1 44 | javaOptions: -Xms256M -Xmx2G 45 | containerMemoryRequest: 256Mi 46 | containerMemoryLimit: 2Gi 47 | 48 | service: 49 | configserver: 50 | type: ClusterIP 51 | internalPort: 8888 52 | mysql: 53 | internalPort: 3306 54 | rootPassword: password 55 | database: auth 56 | eurekaregistry: 57 | type: LoadBalancer 58 | externalPort: 8761 59 | internalPort: 8761 60 | zipkinserver: 61 | type: LoadBalancer 62 | externalPort: 9411 63 | internalPort: 9411 64 | authserver: 65 | type: ClusterIP 66 | internalPort: 8899 67 | apigateway: 68 | type: LoadBalancer 69 | externalPort: 8765 70 | internalPort: 8765 71 | 72 | image: 73 | pullPolicy: IfNotPresent 74 | 75 | spring: 76 | activeProfile: docker -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/istio/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | How to run the system services using Istio and helm charts 4 | 5 | ## Pre-requisites 6 | 7 | * The docker image should have been build previously using the ../../../../docker-image-all-projects.sh 8 | * Helm installed on the system 9 | * Install Istio using the following commands 10 | ** Download Istio => `curl -L https://istio.io/downloadIstio | sh -` 11 | ** Make the Istio commands avaialble on path => `export PATH="$PATH:<>/bin"` 12 | ** Set Istio default profile for development work => `istioctl install --set profile=demo` 13 | ** Delete existing namespace if it exists => `kubectl delete namespace istio-io-health` 14 | ** Create a brand new namespace => `kubectl create namespace istio-io-health` 15 | ** Add a namespace label to instruct Istio to automatically inject Envoy sidecar proxies into the "default" kubernetes namespace when you deploy your application later => `kubectl label namespace istio-io-health istio-injection=enabled` 16 | ** Check whether the current context is set to the `istio-io-health` namespace => `kubectl config get-context` 17 | ** If the current context namespace us not set to `istio-io-health` then exceute command to set the current namespace => `kubectl config set-context --current --namespace=istio-io-health` 18 | 19 | ** Set the kubernetes `istio-io-health` namespace to do the readiness/liveness probe using mutual TLS 20 | *** Specify authentication policy for `istio-io-health` namespace => `kubectl apply -f istio-auth-policy.yml` 21 | *** Specify destination rule for `istio-io-health` namespace => `kubectl apply -f istio-destination-rule.yml` 22 | 23 | ## Running the application 24 | * Note that the load balancer is not defined in the service for the eurekaregistry 25 | ** `helm install system-svc application/system-services/ ` 26 | *** [[ system-svc ]] - Name of helm release 27 | *** [[ application/system-services/ ]] - Name of the folder holding the helm charts 28 | ** kubectl get svc,pods,deployment (to check if deployment was successful) 29 | 30 | ## NOTE - The application is currently failing since it's not able to negotiate the TLS handshake as part of Istio mutual TLS authentication. -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/istio/application/system-services/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *~ 18 | # Various IDEs 19 | .project 20 | .idea/ 21 | *.tmproj -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/istio/application/system-services/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | appVersion: "1.0" 3 | description: | 4 | A Helm chart for deploying system services needed for distributed Microservices in Kubernetes 5 | name: system-services 6 | version: 0.0.1 -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/istio/application/system-services/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{- define "labels" }} 2 | labels: 3 | generator: helm 4 | date: {{ now | htmlDate }} 5 | release: {{ .Release.Name }} 6 | revision: {{ .Release.Revision | quote }} 7 | chart: {{ .Chart.Name }} 8 | version: {{ .Chart.Version }} 9 | {{- end }} -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/istio/application/system-services/templates/helper-service-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ .Release.Name }}-mysql 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: {{ .Release.Name }}-mysql 10 | template: 11 | metadata: 12 | labels: 13 | app: {{ .Release.Name }}-mysql 14 | spec: 15 | containers: 16 | - name: {{ .Release.Name }}-mysql 17 | image: {{ .Values.mysql.image }}:{{ .Values.mysql.tag }} 18 | imagePullPolicy: {{ .Values.image.pullPolicy }} 19 | ports: 20 | - containerPort: {{ .Values.service.mysql.internalPort }} 21 | name: "tcp" 22 | env: 23 | - name: MYSQL_DATABASE 24 | value: {{ .Values.service.mysql.database }} 25 | - name: MYSQL_ROOT_PASSWORD 26 | value: {{ .Values.service.mysql.rootPassword }} 27 | readinessProbe: 28 | exec: 29 | # Check we can ping TCP 30 | command: ["mysqladmin", "ping"] 31 | initialDelaySeconds: 5 32 | periodSeconds: 2 33 | timeoutSeconds: 1 34 | 35 | --- 36 | 37 | apiVersion: apps/v1 38 | kind: Deployment 39 | metadata: 40 | name: {{ .Release.Name }}-config-server 41 | spec: 42 | replicas: 1 43 | selector: 44 | matchLabels: 45 | app: {{ .Release.Name }}-config-server 46 | template: 47 | metadata: 48 | labels: 49 | app: {{ .Release.Name }}-config-server 50 | annotations: 51 | sidecar.istio.io/rewriteAppHTTPProbers: "true" 52 | spec: 53 | containers: 54 | - name: {{ .Release.Name }}-config-server 55 | image: {{ .Values.configserver.image }}:{{ .Values.configserver.tag }} 56 | imagePullPolicy: {{ .Values.image.pullPolicy }} 57 | ports: 58 | - containerPort: {{ .Values.service.configserver.internalPort}} 59 | name: "http" 60 | command: ["/bin/bash"] 61 | args: ["-c", 'until nslookup mysql; do echo Waiting for mySql database to start; sleep 5; done; /app/run.sh'] 62 | livenessProbe: 63 | httpGet: 64 | path: /health 65 | port: {{ .Values.service.configserver.internalPort }} 66 | initialDelaySeconds: 10 67 | periodSeconds: 3 68 | timeoutSeconds: 2 69 | 70 | --- 71 | 72 | apiVersion: apps/v1 73 | kind: Deployment 74 | metadata: 75 | name: {{ .Release.Name }}-eurekaregistry 76 | spec: 77 | replicas: 1 78 | selector: 79 | matchLabels: 80 | app: {{ .Release.Name }}-eurekaregistry 81 | template: 82 | metadata: 83 | labels: 84 | app: {{ .Release.Name }}-eurekaregistry 85 | annotations: 86 | sidecar.istio.io/rewriteAppHTTPProbers: "true" 87 | spec: 88 | containers: 89 | - name: {{ .Release.Name }}-eurekaregistry 90 | image: {{ .Values.eurekaregistry.image }}:{{ .Values.eurekaregistry.tag }} 91 | imagePullPolicy: {{ .Values.image.pullPolicy }} 92 | ports: 93 | - containerPort: {{ .Values.service.eurekaregistry.internalPort}} 94 | name: "http" 95 | env: 96 | - name: SPRING_ACTIVE_PROFILE 97 | value: {{ .Values.spring.activeProfile }} 98 | command: ["/bin/bash"] 99 | args: ["-c", 'while ! curl -s http://configserver:8888/health > /dev/null; do echo Waiting for Config Service to start; sleep 5; done; /app/run.sh'] 100 | livenessProbe: 101 | httpGet: 102 | path: /health 103 | port: {{ .Values.service.eurekaregistry.internalPort }} 104 | initialDelaySeconds: 10 105 | periodSeconds: 3 106 | timeoutSeconds: 2 -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/istio/application/system-services/templates/helper-service-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: mysql 5 | spec: 6 | selector: 7 | app: {{ .Release.Name }}-mysql 8 | ports: 9 | - name: http 10 | protocol: TCP 11 | port: {{ .Values.service.mysql.internalPort }} 12 | 13 | --- 14 | 15 | apiVersion: v1 16 | kind: Service 17 | metadata: 18 | name: configserver 19 | spec: 20 | selector: 21 | app: {{ .Release.Name }}-config-server 22 | ports: 23 | - name: http 24 | protocol: TCP 25 | # Not exposing the service to external endpoints 26 | port: {{ .Values.service.configserver.internalPort }} 27 | type: {{ .Values.service.configserver.type }} 28 | 29 | --- 30 | 31 | apiVersion: v1 32 | kind: Service 33 | metadata: 34 | name: eurekaregistry 35 | spec: 36 | selector: 37 | app: {{ .Release.Name }}-eurekaregistry 38 | ports: 39 | - name: http 40 | protocol: TCP 41 | port: {{ .Values.service.eurekaregistry.internalPort }} 42 | targetPort: {{ .Values.service.eurekaregistry.externalPort }} 43 | type: {{ .Values.service.eurekaregistry.type }} -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/istio/application/system-services/values.yaml: -------------------------------------------------------------------------------- 1 | configserver: 2 | image: anilallewar/basic-config-server 3 | tag: 0.0.1 4 | replicaCount: 1 5 | 6 | mysql: 7 | image: mysql 8 | tag: latest 9 | replicaCount: 1 10 | 11 | eurekaregistry: 12 | image: anilallewar/basic-webservice-registry 13 | tag: 0.0.1 14 | replicaCount: 1 15 | 16 | image: 17 | pullPolicy: IfNotPresent 18 | 19 | spring: 20 | activeProfile: docker 21 | 22 | service: 23 | configserver: 24 | type: ClusterIP 25 | internalPort: 8888 26 | mysql: 27 | internalPort: 3306 28 | rootPassword: root 29 | database: auth 30 | eurekaregistry: 31 | type: ClusterIP 32 | externalPort: 8761 33 | internalPort: 8761 -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/istio/istio-auth-policy.yml: -------------------------------------------------------------------------------- 1 | apiVersion: "security.istio.io/v1beta1" 2 | kind: "PeerAuthentication" 3 | metadata: 4 | name: "default" 5 | namespace: "istio-io-health" 6 | spec: 7 | mtls: 8 | mode: STRICT -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/istio/istio-destination-rule.yml: -------------------------------------------------------------------------------- 1 | apiVersion: "networking.istio.io/v1alpha3" 2 | kind: "DestinationRule" 3 | metadata: 4 | name: "default" 5 | namespace: "istio-io-health" 6 | spec: 7 | host: "*.istio-io-health.svc.cluster.local" 8 | trafficPolicy: 9 | tls: 10 | mode: ISTIO_MUTUAL -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/istio/istio-gateway.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.istio.io/v1alpha3 2 | kind: Gateway 3 | metadata: 4 | name: config-server-gateway 5 | spec: 6 | selector: 7 | istio: ingressgateway # use Istio default gateway implementation 8 | servers: 9 | - port: 10 | number: 80 11 | name: http 12 | protocol: HTTP 13 | hosts: 14 | - "config.example.com" -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/istio/istio-virtual-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.istio.io/v1alpha3 2 | kind: VirtualService 3 | metadata: 4 | name: config-server-virtual-service 5 | spec: 6 | hosts: 7 | - "config.example.com" 8 | gateways: 9 | - config-server-gateway 10 | http: 11 | - match: 12 | - uri: 13 | prefix: /* 14 | route: 15 | - destination: 16 | port: 17 | number: 8888 18 | host: config-server-service -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/standalone/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | How to run the config-service in standalone mode 4 | 5 | ## Pre-requisites 6 | 7 | * The docker image should have been build previously using the ../../../../docker-image-all-projects.sh 8 | 9 | ## Running the application 10 | * Once you have the Kubernetes server installed (either through Docker for Desktop or MiniKube), you can run the following commands in this folder 11 | ** kubectl create -f config-server-deployment.yml 12 | ** kubectl get deployment (to check if deployment was successful) 13 | ** kubectl get pods 14 | ** kubectl logs 15 | ** kubectl create -f config-server-deployment.yml 16 | ** kubectl get svc 17 | 18 | ## Checking if app is running or not 19 | ** curl http://localhost:8888/api-gateway/default 20 | *** This should give you the contents from api-gateway.yml 21 | 22 | ## Delete the deployment 23 | ** kubectl delete -f config-server-service.yml 24 | ** kubectl delete -f config-server-deployment.yml 25 | 26 | ## Creating the deployment and service through single manifest file 27 | ** kubectl create -f config-server-single.yml 28 | ** kubectl get svc,pods,deployment 29 | ** curl http://localhost:8888/api-gateway/default (check if app is running) 30 | ** kubectl delete -f config-server-single.yml 31 | ** You can also delete resources by name 32 | *** kubectl delete deployment/config-server service/config-server-service -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/standalone/config-server-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: config-server 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: config-server 10 | template: 11 | metadata: 12 | labels: 13 | app: config-server 14 | spec: 15 | containers: 16 | - name: config-server 17 | image: anilallewar/basic-config-server:0.0.1 18 | imagePullPolicy: IfNotPresent 19 | ports: 20 | - containerPort: 8888 21 | name: "http" -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/standalone/config-server-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: config-server-service 5 | spec: 6 | selector: 7 | app: config-server 8 | ports: 9 | - name: http 10 | protocol: TCP 11 | port: {{ .Values.service.config-server.internalPort}} 12 | targetPort: {{ .Values.service.config-server.internalPort}} 13 | type: LoadBalancer -------------------------------------------------------------------------------- /docker-orchestration/k8s/manifests/standalone/config-server-single.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: config-server 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: config-server 10 | template: 11 | metadata: 12 | labels: 13 | app: config-server 14 | spec: 15 | containers: 16 | - name: config-server 17 | image: anilallewar/basic-config-server:0.0.1 18 | imagePullPolicy: IfNotPresent 19 | ports: 20 | - containerPort: 8888 21 | name: "config-port" 22 | livenessProbe: 23 | httpGet: 24 | path: /health 25 | port: 8888 26 | initialDelaySeconds: 10 27 | periodSeconds: 3 28 | timeoutSeconds: 2 29 | --- 30 | apiVersion: v1 31 | kind: Service 32 | metadata: 33 | name: config-server-service 34 | spec: 35 | selector: 36 | app: config-server 37 | ports: 38 | - name: http 39 | protocol: TCP 40 | port: 8888 41 | targetPort: 8888 42 | type: LoadBalancer -------------------------------------------------------------------------------- /docker-orchestration/rancher/rancher-compose.yml: -------------------------------------------------------------------------------- 1 | mysqldb: 2 | scale: 1 3 | health_check: 4 | # Which port to perform the check against 5 | port: 3306 6 | # Interval is measured in milliseconds 7 | interval: 5000 8 | initializing_timeout: 20000 9 | unhealthy_threshold: 3 10 | # Strategy for what to do when unhealthy 11 | # In this service, Rancher will recreate any unhealthy containers 12 | strategy: none 13 | healthy_threshold: 2 14 | # Response timeout is measured in milliseconds 15 | response_timeout: 2000 16 | configserver: 17 | scale: 1 18 | eurekaregistry: 19 | scale: 1 20 | authserver: 21 | scale: 1 22 | apigateway: 23 | scale: 1 24 | webportal: 25 | scale: 1 26 | userwebservice: 27 | scale: 1 28 | taskwebservice: 29 | scale: 1 30 | commentswebservice: 31 | scale: 1 32 | zipkinserver: 33 | scale: 1 34 | -------------------------------------------------------------------------------- /images/Application_Components.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/images/Application_Components.jpg -------------------------------------------------------------------------------- /images/Decentralized_Goverance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/images/Decentralized_Goverance.png -------------------------------------------------------------------------------- /images/OAuth2_abstract_protocol_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/images/OAuth2_abstract_protocol_flow.png -------------------------------------------------------------------------------- /images/Target_Architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/images/Target_Architecture.jpg -------------------------------------------------------------------------------- /task-webservice/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | .classpath -------------------------------------------------------------------------------- /task-webservice/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | task-webservice 4 | 5 | 6 | 7 | org.springsource.ide.eclipse.gradle.core.nature 8 | org.eclipse.jdt.core.javanature 9 | 10 | 11 | 12 | org.eclipse.jdt.core.javabuilder 13 | 14 | 15 | 16 | 17 | 18 | 19 | 1 20 | 22 21 | 22 | 23 | org.eclipse.ui.ide.multiFilter 24 | 1.0-name-matches-false-false-.DS_Store 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /task-webservice/.settings/gradle/org.springsource.ide.eclipse.gradle.core.import.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleImportPreferences 2 | #Mon Apr 06 13:25:59 PDT 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | enableDependendencyManagement=true 10 | projects=; 11 | -------------------------------------------------------------------------------- /task-webservice/.settings/gradle/org.springsource.ide.eclipse.gradle.core.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleProjectPreferences 2 | #Mon Apr 06 13:26:03 PDT 2015 3 | org.springsource.ide.eclipse.gradle.linkedresources= 4 | org.springsource.ide.eclipse.gradle.rootprojectloc= 5 | -------------------------------------------------------------------------------- /task-webservice/.settings/gradle/org.springsource.ide.eclipse.gradle.refresh.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.actions.GradleRefreshPreferences 2 | #Mon Apr 06 13:26:02 PDT 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | useHierarchicalNames=false 10 | -------------------------------------------------------------------------------- /task-webservice/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.arguments= 2 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) 3 | connection.java.home=null 4 | connection.jvm.arguments= 5 | connection.project.dir= 6 | derived.resources=.gradle,build 7 | eclipse.preferences.version=1 8 | project.path=\: 9 | -------------------------------------------------------------------------------- /task-webservice/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | # 2 | #Wed Nov 14 16:33:15 IST 2018 3 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 7 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 8 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 9 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 10 | eclipse.preferences.version=1 11 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 12 | org.eclipse.jdt.core.compiler.source=1.8 13 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 14 | -------------------------------------------------------------------------------- /task-webservice/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | This application provides the **task** related functionality and serves as one component. It defines the REST endpoints that are used to provide task functionality. 4 | 5 | This micro-service also provides an example of to call another OAuth2 protected service from within this service using OAuth2 client configuration. The OAuth2 bearer token that has been passed to the task service is propagated to the "comments" service to get the comments for the given task. 6 | 7 | ##Pre-requisites 8 | 9 | ### Projects that need to be started before 10 | * [config server](/../../blob/master/config-server/README.md) - For pulling the configuration information 11 | * [webserver-registry](/../../blob/master/webservice-registry/README.md) - For starting the Eureka server since the authorization server also is a micro-service that needs to be registered with Eureka server. 12 | 13 | ### Running the application 14 | * Build the application by running the `./gradlew clean build` gradle command at the "task-webservice" project root folder on the terminal. 15 | * If you want to run the application as jar file, then run `java -jar build/libs/basic-task-webservice-0.0.1.jar` command at the terminal. 16 | 17 | ## External Configuration 18 | Please refer to [user webservice](/../../blob/master/user-webservice/README.md) for details on how the external configuration works. Note that there is separate configuration file for each Spring application; the application should refer to it's own .yml file for configuration. 19 | 20 | ## Consumer Driven Contracts 21 | * The task service has tests that validate the contract defined by the comments webservice. 22 | * The `comments-webservice` publishes the stubs to the local maven repository which is then used by the `task-webservice` to validate the contract. 23 | * To run the contract test, run the following gradle task 24 | ``` 25 | ./gradlew clean build 26 | ``` -------------------------------------------------------------------------------- /task-webservice/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Build file for Task-webservice 3 | */ 4 | apply plugin: 'java' 5 | apply plugin: 'org.springframework.boot' 6 | apply plugin: 'application' 7 | apply plugin: 'docker' 8 | apply plugin: 'eclipse' 9 | 10 | buildscript { 11 | project.ext { 12 | springBootVersion = '1.5.6.RELEASE' 13 | jarName = 'basic-task-webservice' 14 | versionName = '0.0.1' 15 | gradleDockerVersion = '1.2' 16 | swagger2version = '2.7.0' 17 | } 18 | repositories { 19 | jcenter() 20 | mavenCentral() 21 | } 22 | 23 | dependencies { 24 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.springBootVersion}" 25 | classpath "se.transmode.gradle:gradle-docker:${project.gradleDockerVersion}" 26 | } 27 | } 28 | 29 | task createWrapper(type: Wrapper) { 30 | gradleVersion = '3.5' 31 | } 32 | 33 | // Used by the Docker gradle plugin, group refers to the account under which the docker image is created 34 | group = 'anilallewar' 35 | mainClassName = 'com.anilallewar.microservices.task.TaskApplication' 36 | sourceCompatibility = 1.8 37 | targetCompatibility = 1.8 38 | 39 | repositories { 40 | mavenCentral() 41 | jcenter() 42 | } 43 | 44 | ext { 45 | springCloudVersion = 'Dalston.SR3' 46 | } 47 | 48 | dependencyManagement { 49 | imports { 50 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 51 | } 52 | } 53 | 54 | 55 | dependencies { 56 | // Basic Spring boot with config client 57 | compile('org.springframework.cloud:spring-cloud-starter-config') 58 | compile("org.springframework.boot:spring-boot-starter-web") 59 | compile("org.springframework.boot:spring-boot-starter-actuator") 60 | compile("org.springframework.cloud:spring-cloud-starter-hystrix") 61 | 62 | // Spring OAuth2 security 63 | compile("org.springframework.boot:spring-boot-starter-security") 64 | compile("org.springframework.security.oauth:spring-security-oauth2") 65 | compile("org.springframework.security:spring-security-jwt") 66 | compile('org.springframework.cloud:spring-cloud-security') 67 | 68 | // Eureka client 69 | compile('org.springframework.cloud:spring-cloud-starter-eureka') 70 | 71 | // Spring cloud contract client and OAuth2 security tests 72 | testCompile("org.springframework.security:spring-security-test") 73 | testCompile("org.springframework.boot:spring-boot-starter-test") 74 | testCompile("org.springframework.cloud:spring-cloud-starter-contract-stub-runner") 75 | 76 | // Zipkin tracing 77 | compile('org.springframework.cloud:spring-cloud-starter-zipkin') 78 | 79 | // Swagger for API testing 80 | compile("io.springfox:springfox-swagger2:${swagger2version}") 81 | compile("io.springfox:springfox-swagger-ui:${swagger2version}") 82 | } 83 | 84 | jar { 85 | baseName = "${project.jarName}" 86 | version = "${project.versionName}" 87 | } 88 | 89 | /* 90 | * This task builds the docker image by copying the output of the "jar" gradle command 91 | * and moving it to the "build/docker" directory which is used as the staging directory 92 | * by the docker gradle plugin. We then build the docker image by invoking the appropriate 93 | * Dockerfile. 94 | */ 95 | task buildDocker(type: Docker, dependsOn: build) { 96 | push = false 97 | applicationName = jar.baseName 98 | tagVersion = jar.version 99 | dockerfile = file('src/main/docker/Dockerfile') 100 | doFirst { 101 | // Copy the built fat jar to the Docker plugin staging directory 102 | copy { 103 | from jar 104 | into stageDir 105 | } 106 | // Copy the run.sh file to the Docker plugin staging directory 107 | copy { 108 | from "${project.buildDir}/resources/main/run.sh" 109 | into stageDir 110 | } 111 | } 112 | } 113 | 114 | run { 115 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4300,suspend=n','-Dspring.profiles.active=default'] 116 | } 117 | 118 | -------------------------------------------------------------------------------- /task-webservice/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/task-webservice/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /task-webservice/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 26 15:12:24 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip 7 | -------------------------------------------------------------------------------- /task-webservice/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /task-webservice/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------------------------------- 2 | # User Service 3 | #----------------------------------------------------------------------------------------------------- 4 | FROM openjdk:8u121-jdk-alpine 5 | 6 | MAINTAINER Anil Allewar 7 | 8 | # Keep consistent with build.gradle 9 | ENV APP_JAR_NAME basic-task-webservice 10 | ENV APP_JAR_VERSION 0.0.1 11 | 12 | # Install curl 13 | RUN apk --update add curl bash && \ 14 | rm -rf /var/cache/apk/* 15 | 16 | RUN mkdir /app 17 | 18 | ADD ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar /app/ 19 | ADD run.sh /app/ 20 | RUN chmod +x /app/run.sh 21 | 22 | WORKDIR /app 23 | 24 | EXPOSE 8080 25 | 26 | ENTRYPOINT ["/bin/bash","-c"] 27 | CMD ["/app/run.sh"] 28 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/anilallewar/microservices/task/TaskApplication.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.task; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 6 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 7 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 9 | 10 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 11 | 12 | /** 13 | * The boot application class that defines the spring boot application to have 14 | * the following properties
15 | *
16 | * 17 | *
    18 | *
  1. Act as a Eureka client; this behavior is provided by the 19 | * {@link EnableEurekaClient} annotation. The Eureka server URL is provided by 20 | * the external configuration provided by the config server.
  2. 21 | *
  3. {@link EnableEurekaClient} makes the app into both a Eureka "instance" (i.e. it 22 | * registers itself) and a "client" (i.e. it can query the registry to locate 23 | * other services).
  4. 24 | *
  5. {@link EnableCircuitBreaker} allows the application to respond to 25 | + * failures on services it relies. For example consider that you have an 26 | + * "employee" service that uses the "address" service to get addresses. Now if 27 | + * the address service goes down, then we can provide a fallback method using 28 | + * the circuit breaker. Now the address would be sent back using the static 29 | + * value from the method till the "address" service comes back again.
  6. 30 | *
  7. Note that all these annotations work in conjunction with properties 31 | * defined in the external configuration files specified by the config server. 32 | *
  8. 33 | *
34 | * 35 | * @author anilallewar 36 | * 37 | */ 38 | @SpringBootApplication 39 | @EnableEurekaClient 40 | @EnableCircuitBreaker 41 | @EnableResourceServer 42 | @EnableOAuth2Client 43 | @EnableSwagger2 44 | public class TaskApplication { 45 | public static void main(String[] args) { 46 | 47 | SpringApplication.run(TaskApplication.class,args); 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/anilallewar/microservices/task/apis/TaskController.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.task.apis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestMethod; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import com.anilallewar.microservices.task.dtos.TaskDTO; 14 | 15 | /** 16 | * REST endpoint for the task functionality 17 | * 18 | * @author anilallewar 19 | * 20 | */ 21 | @RestController 22 | @RequestMapping("/") 23 | public class TaskController { 24 | 25 | @Autowired 26 | private CommentsService commentsService; 27 | 28 | private List tasks = Arrays.asList(new TaskDTO("task11", "description11", "1"), 29 | new TaskDTO("task12", "description12", "1"), new TaskDTO("task13", "description13", "1"), 30 | new TaskDTO("task21", "description21", "2"), new TaskDTO("task22", "description22", "2")); 31 | 32 | /** 33 | * Get all tasks 34 | * 35 | * @return 36 | */ 37 | @RequestMapping(method = RequestMethod.GET, headers = "Accept=application/json") 38 | public List getTasks() { 39 | return tasks; 40 | } 41 | 42 | /** 43 | * Get tasks for specific taskid 44 | * 45 | * @param taskId 46 | * @return 47 | */ 48 | @RequestMapping(value = "{taskId}", method = RequestMethod.GET, headers = "Accept=application/json") 49 | public TaskDTO getTaskByTaskId(@PathVariable("taskId") String taskId) { 50 | TaskDTO taskToReturn = null; 51 | for (TaskDTO currentTask : tasks) { 52 | if (currentTask.getTaskId().equalsIgnoreCase(taskId)) { 53 | taskToReturn = currentTask; 54 | break; 55 | } 56 | } 57 | 58 | if (taskToReturn != null) { 59 | taskToReturn.setComments(this.commentsService.getCommentsForTask(taskId)); 60 | } 61 | return taskToReturn; 62 | } 63 | 64 | /** 65 | * Get tasks for specific user that is passed in 66 | * 67 | * @param taskId 68 | * @return 69 | */ 70 | @RequestMapping(value = "/usertask/{userName}", method = RequestMethod.GET, headers = "Accept=application/json") 71 | public List getTasksByUserName(@PathVariable("userName") String userName) { 72 | List taskListToReturn = new ArrayList<>(); 73 | for (TaskDTO currentTask : tasks) { 74 | if (currentTask.getUserName().equalsIgnoreCase(userName)) { 75 | taskListToReturn.add(currentTask); 76 | } 77 | } 78 | 79 | return taskListToReturn; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/anilallewar/microservices/task/config/OAuthClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.task.config; 2 | 3 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Primary; 7 | import org.springframework.security.oauth2.client.OAuth2ClientContext; 8 | import org.springframework.security.oauth2.client.OAuth2RestTemplate; 9 | import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; 10 | import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails; 11 | 12 | /** 13 | * Configuration that sets up the OAuth2 client operation for making calls to 14 | * the comments-webservice.
15 | *
16 | * 17 | * @author anilallewar 18 | * 19 | */ 20 | @Configuration 21 | public class OAuthClientConfiguration { 22 | 23 | /** 24 | * RestTempate that relays the OAuth2 token passed to the task webservice. 25 | * 26 | * @param oauth2ClientContext 27 | * @return 28 | */ 29 | @Bean(name = "oAuth2RestTemplate") 30 | @LoadBalanced 31 | @Primary 32 | public OAuth2RestTemplate restTemplate(OAuth2ClientContext context) { 33 | return new OAuth2RestTemplate(authServer(), context); 34 | } 35 | 36 | private OAuth2ProtectedResourceDetails authServer() { 37 | ResourceOwnerPasswordResourceDetails resourceOwnerPasswordResourceDetails = new ResourceOwnerPasswordResourceDetails(); 38 | // Need to set the access token URI since RestTemplate tries to access it first 39 | // time 40 | resourceOwnerPasswordResourceDetails.setAccessTokenUri("/userauth/oauth/token"); 41 | return resourceOwnerPasswordResourceDetails; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/anilallewar/microservices/task/config/TaskBeanFactory.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.task.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | import springfox.documentation.builders.PathSelectors; 7 | import springfox.documentation.builders.RequestHandlerSelectors; 8 | import springfox.documentation.spi.DocumentationType; 9 | import springfox.documentation.spring.web.plugins.Docket; 10 | 11 | @Configuration 12 | public class TaskBeanFactory { 13 | 14 | /** 15 | * Swagger2 support 16 | * 17 | * @return 18 | */ 19 | @Bean 20 | public Docket api() { 21 | return new Docket(DocumentationType.SWAGGER_2).select() 22 | .apis(RequestHandlerSelectors.basePackage("com.anilallewar.microservices.task")).paths(PathSelectors.any()) 23 | .paths(PathSelectors.any()).build(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/anilallewar/microservices/task/config/security/ResourceServerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.task.config.security; 2 | 3 | import org.springframework.boot.autoconfigure.security.SecurityProperties; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 7 | import org.springframework.security.config.http.SessionCreationPolicy; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 10 | 11 | /** 12 | * Override the security properties for the resources exposed by this 13 | * application. NOTE that the {@link EnableResourceServer} annotation creates a 14 | * filter with Order as {@link SecurityProperties#ACCESS_OVERRIDE_ORDER} - 1, 15 | * hence this security filter would be applied before the filter defined for web 16 | * security at {@link OAuth2SecurityConfiguration}.
17 | *
18 | * 19 | * What this essentially means is that the rules for the endpoint applied here 20 | * would be applied before the rules defined in the 21 | * {@link WebSecurityConfigurerAdapter} class. 22 | * 23 | * @author anilallewar 24 | * 25 | */ 26 | @Configuration 27 | @EnableResourceServer 28 | public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { 29 | 30 | /* 31 | * (non-Javadoc) 32 | * 33 | * @see org.springframework.security.oauth2.config.annotation.web.configuration. 34 | * ResourceServerConfigurerAdapter#configure(org.springframework.security.config 35 | * .annotation.web.builders.HttpSecurity) 36 | */ 37 | @Override 38 | public void configure(HttpSecurity http) throws Exception { 39 | // @formatter:off 40 | http 41 | .sessionManagement() 42 | .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 43 | .and() 44 | .authorizeRequests() 45 | .anyRequest() 46 | .authenticated(); 47 | // @formatter:on 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/anilallewar/microservices/task/config/security/WebSecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.task.config.security; 2 | 3 | import org.springframework.boot.autoconfigure.security.SecurityProperties; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.core.annotation.Order; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.builders.WebSecurity; 8 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 10 | 11 | @Configuration 12 | @EnableWebSecurity 13 | @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) 14 | public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 15 | @Override 16 | protected void configure(HttpSecurity http) throws Exception { 17 | // @formatter:off 18 | http 19 | .authorizeRequests() 20 | .anyRequest() 21 | .authenticated(); 22 | // @formatter:on 23 | } 24 | 25 | // Swagger specific, allow access 26 | @Override 27 | public void configure(WebSecurity web) throws Exception { 28 | // @formatter:off 29 | web 30 | .ignoring() 31 | .antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources/**", "/configuration/**", 32 | "/swagger-ui.html", "/webjars/**"); 33 | // @formatter:on 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/anilallewar/microservices/task/model/CommentCollectionResource.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.anilallewar.microservices.task.model; 5 | 6 | import java.io.IOException; 7 | import java.util.ArrayList; 8 | import java.util.Date; 9 | import java.util.List; 10 | 11 | import com.fasterxml.jackson.core.JsonParser; 12 | import com.fasterxml.jackson.core.JsonProcessingException; 13 | import com.fasterxml.jackson.databind.DeserializationContext; 14 | import com.fasterxml.jackson.databind.JsonDeserializer; 15 | import com.fasterxml.jackson.databind.JsonNode; 16 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 17 | 18 | /** 19 | * @author anilallewar 20 | * 21 | */ 22 | @JsonDeserialize(using = CommentsCollectionDeserializer.class) 23 | public class CommentCollectionResource { 24 | private List taskComments; 25 | 26 | /** 27 | * Adds the comment. 28 | * 29 | * @param comment 30 | * the comment 31 | */ 32 | public void addComment(CommentResource comment) { 33 | if (this.taskComments == null) { 34 | this.taskComments = new ArrayList<>(); 35 | } 36 | this.taskComments.add(comment); 37 | } 38 | 39 | /** 40 | * @return the taskComments 41 | */ 42 | public List getTaskComments() { 43 | return taskComments; 44 | } 45 | 46 | /** 47 | * @param taskComments 48 | * the taskComments to set 49 | */ 50 | public void setTaskComments(List taskComments) { 51 | this.taskComments = taskComments; 52 | } 53 | 54 | /* 55 | * (non-Javadoc) 56 | * 57 | * @see java.lang.Object#hashCode() 58 | */ 59 | @Override 60 | public int hashCode() { 61 | final int prime = 31; 62 | int result = 1; 63 | result = prime * result + ((taskComments == null) ? 0 : taskComments.hashCode()); 64 | return result; 65 | } 66 | 67 | /* 68 | * (non-Javadoc) 69 | * 70 | * @see java.lang.Object#equals(java.lang.Object) 71 | */ 72 | @Override 73 | public boolean equals(Object obj) { 74 | if (this == obj) 75 | return true; 76 | if (obj == null) 77 | return false; 78 | if (getClass() != obj.getClass()) 79 | return false; 80 | CommentCollectionResource other = (CommentCollectionResource) obj; 81 | if (taskComments == null) { 82 | if (other.taskComments != null) 83 | return false; 84 | } else if (!taskComments.equals(other.taskComments)) 85 | return false; 86 | return true; 87 | } 88 | 89 | /* 90 | * (non-Javadoc) 91 | * 92 | * @see java.lang.Object#toString() 93 | */ 94 | @Override 95 | public String toString() { 96 | return "CommentCollectionResource [taskComments=" + taskComments + "]"; 97 | } 98 | } 99 | 100 | /** 101 | * Inner class to perform the de-serialization of the comments array 102 | * 103 | * @author anilallewar 104 | * 105 | */ 106 | class CommentsCollectionDeserializer extends JsonDeserializer { 107 | @Override 108 | public CommentCollectionResource deserialize(JsonParser jp, DeserializationContext ctxt) 109 | throws IOException, JsonProcessingException { 110 | CommentCollectionResource commentArrayResource = new CommentCollectionResource(); 111 | CommentResource commentResource = null; 112 | 113 | JsonNode jsonNode = jp.readValueAsTree(); 114 | 115 | for (JsonNode childNode : jsonNode) { 116 | if (childNode.has(CommentResource.JP_TASKID)) { 117 | commentResource = new CommentResource(); 118 | commentResource.setTaskId(childNode.get(CommentResource.JP_TASKID).asText()); 119 | commentResource.setComment(childNode.get(CommentResource.JP_COMMENT).asText()); 120 | commentResource.setPosted(new Date(childNode.get(CommentResource.JP_POSTED).asLong())); 121 | 122 | commentArrayResource.addComment(commentResource); 123 | } 124 | } 125 | return commentArrayResource; 126 | 127 | } 128 | } -------------------------------------------------------------------------------- /task-webservice/src/main/resources/application.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/task-webservice/src/main/resources/application.yml -------------------------------------------------------------------------------- /task-webservice/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | 4 | # Name of the service that is using with Zuul routes to forward specific requests to this service 5 | name: task-webservice 6 | cloud: 7 | config: 8 | 9 | # Define the URL from where this service would pick up it's external configuration. Note that it is 10 | # pointing to the config-server aplication 11 | uri: http://localhost:8888 12 | 13 | --- 14 | 15 | spring: 16 | profiles: docker 17 | cloud: 18 | config: 19 | uri: http://configserver:8888 -------------------------------------------------------------------------------- /task-webservice/src/main/resources/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SPRING_ACTIVE_PROFILE=${SPRING_ACTIVE_PROFILE:-"local-docker"} 4 | GIT_BRANCH_LABEL=${GIT_BRANCH_LABEL:-"develop"} 5 | 6 | # The environment variables are already set up by the Dockerfile 7 | exec java -Djava.security.egd=file:/dev/urandom -Dspring.profiles.active=${SPRING_ACTIVE_PROFILE} -Dgit.config.active.branch=${GIT_BRANCH_LABEL} -Duser.timezone=Asia/Kolkata -XX:+PrintFlagsFinal $JAVA_OPTIONS -jar ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar -------------------------------------------------------------------------------- /task-webservice/src/test/java/com/anilallewar/microservices/task/CommentsServiceTests.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.task; 2 | 3 | import org.junit.After; 4 | import org.junit.Assert; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 11 | import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; 12 | import org.springframework.context.annotation.Import; 13 | import org.springframework.test.annotation.DirtiesContext; 14 | import org.springframework.test.context.junit4.SpringRunner; 15 | 16 | import com.anilallewar.microservices.task.apis.CommentsService; 17 | import com.anilallewar.microservices.task.model.CommentCollectionResource; 18 | import com.anilallewar.microservices.task.oauth2.config.OAuth2ClientTestConfiguration; 19 | import com.anilallewar.microservices.task.oauth2.security.WithMockOAuth2Token; 20 | 21 | /** 22 | * @author anilallewar 23 | * 24 | */ 25 | @RunWith(SpringRunner.class) 26 | @SpringBootTest(classes = { TaskApplication.class }, webEnvironment = WebEnvironment.MOCK, properties = { 27 | "spring.cloud.discovery.enabled=false", "spring.cloud.config.enabled=false", 28 | "stubrunner.idsToServiceIds.basic-comments-webservice-stubs=comments-webservice", 29 | "spring.zipkin.enabled=false" }) 30 | @Import(OAuth2ClientTestConfiguration.class) 31 | @AutoConfigureStubRunner(ids = { "anilallewar:basic-comments-webservice-stubs:+:stubs:9083" }, workOffline = true) 32 | @DirtiesContext 33 | public class CommentsServiceTests { 34 | 35 | @Autowired 36 | private CommentsService commentsService; 37 | 38 | private static final String TEST_TASK_ID = "task11"; 39 | private static final String REQUEST_TASK_ID = "task12"; 40 | 41 | /** 42 | * @throws java.lang.Exception 43 | */ 44 | @Before 45 | public void setUp() throws Exception { 46 | } 47 | 48 | /** 49 | * @throws java.lang.Exception 50 | */ 51 | @After 52 | public void tearDown() throws Exception { 53 | } 54 | 55 | @Test 56 | @WithMockOAuth2Token(userName = "dave") 57 | public void testGetCommentsForTask() { 58 | CommentCollectionResource comments = this.commentsService.getCommentsForTask(REQUEST_TASK_ID); 59 | 60 | Assert.assertEquals(2, comments.getTaskComments().size()); 61 | Assert.assertTrue(comments.getTaskComments().get(0).getTaskId().equals(TEST_TASK_ID)); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /task-webservice/src/test/java/com/anilallewar/microservices/task/oauth2/config/OAuth2ClientTestConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.task.oauth2.config; 2 | 3 | import org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration; 4 | import org.springframework.boot.test.context.TestConfiguration; 5 | import org.springframework.context.annotation.Import; 6 | 7 | 8 | @TestConfiguration 9 | @Import({OAuth2AutoConfiguration.class}) 10 | public class OAuth2ClientTestConfiguration { 11 | // The OAuth2 Rest template is configured with the bean 12 | } 13 | -------------------------------------------------------------------------------- /task-webservice/src/test/java/com/anilallewar/microservices/task/oauth2/security/WithMockOAuth2Token.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.task.oauth2.security; 2 | 3 | import static java.lang.annotation.ElementType.METHOD; 4 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import org.springframework.security.test.context.support.WithSecurityContext; 10 | 11 | /** 12 | * Annotation to help us setup our own security context 13 | * @author anilallewar 14 | * 15 | */ 16 | @Retention(RUNTIME) 17 | @Target(METHOD) 18 | @WithSecurityContext(factory = WithOAuth2MockAccessTokenSecurityContextFactory.class) 19 | public @interface WithMockOAuth2Token { 20 | 21 | // Default OAuth2 scope 22 | String[] scopes() default { "openid" }; 23 | 24 | // Default roles 25 | String[] authorities() default { "ROLE_ADMIN", "ROLE_USER" }; 26 | 27 | // Default user name 28 | String userName() default "anil"; 29 | 30 | // Default password 31 | String password() default "password"; 32 | 33 | // Default redirect Url 34 | String redirectUrl() default "http://localhost:8765"; 35 | 36 | // Default client id 37 | String clientId() default "acme"; 38 | } 39 | -------------------------------------------------------------------------------- /understanding_notes.pages: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/understanding_notes.pages -------------------------------------------------------------------------------- /user-webservice/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | .classpath -------------------------------------------------------------------------------- /user-webservice/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | user-webservice 4 | 5 | 6 | 7 | org.springsource.ide.eclipse.gradle.core.nature 8 | org.eclipse.jdt.core.javanature 9 | 10 | 11 | 12 | org.eclipse.jdt.core.javabuilder 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /user-webservice/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.arguments= 2 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) 3 | connection.java.home=null 4 | connection.jvm.arguments= 5 | connection.project.dir= 6 | derived.resources=.gradle,build 7 | eclipse.preferences.version=1 8 | project.path=\: 9 | -------------------------------------------------------------------------------- /user-webservice/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | # 2 | #Wed Dec 19 19:11:15 IST 2018 3 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 7 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 8 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 9 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 10 | eclipse.preferences.version=1 11 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 12 | org.eclipse.jdt.core.compiler.source=1.8 13 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 14 | -------------------------------------------------------------------------------- /user-webservice/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | This application provides the **user** related functionality and serves as one component. It defines the REST endpoints that are used to provide user functionality. 4 | 5 | ##Pre-requisites 6 | 7 | ### Projects that need to be started before 8 | * [config server](/../../blob/master/config-server/README.md) - For pulling the configuration information 9 | * [webservice-registry](/../../blob/master/webservice-registry/README.md) - For starting the Eureka server since the authorization server also is a micro-service that needs to be registered with Eureka server. 10 | 11 | ### Running the application 12 | * Build the application by running the `./gradlew clean build` gradle command at the "user-webservice" project root folder on the terminal. 13 | * If you want to run the application as jar file, then run `java -jar build/libs/basic-user-webservice-0.0.1.jar` command at the terminal. 14 | 15 | ## External Configuration 16 | The project derives it's external configuration from the [config server](/../../blob/master/config-server/README.md) service. Note that we have defined the `spring.cloud.config.uri` in the `bootstrap.yml` file and that tells the application where to pick up the external confiurations. In our case, the URL points to the running [config server](/../../blob/master/config-server/README.md) server. You also need to have the `spring-cloud-starter-config` dependency in the classpath so that the application can comsume the config server. 17 | 18 | A Spring Cloud application operates by creating a "bootstrap" context, which is a parent context for the main application. This bootstrap context loads properties from external sources (the config-server) and decrypts the properties if required. 19 | 20 | The bootstrap context for external configuration is located by convention at `bootstrap.yml` whereas the internal configuration is located by convention at `application.yml`. Note that you can also have `.properties` file instead of `.yml` files. -------------------------------------------------------------------------------- /user-webservice/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Build file for user-webservice 3 | */ 4 | apply plugin: 'java' 5 | apply plugin: 'org.springframework.boot' 6 | apply plugin: 'application' 7 | apply plugin: 'docker' 8 | apply plugin: 'eclipse' 9 | 10 | buildscript { 11 | project.ext { 12 | springBootVersion = '1.5.6.RELEASE' 13 | jarName = 'basic-user-webservice' 14 | versionName = '0.0.1' 15 | gradleDockerVersion = '1.2' 16 | swagger2version = '2.7.0' 17 | } 18 | repositories { 19 | jcenter() 20 | mavenCentral() 21 | } 22 | 23 | dependencies { 24 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.springBootVersion}" 25 | classpath "se.transmode.gradle:gradle-docker:${project.gradleDockerVersion}" 26 | } 27 | } 28 | 29 | task createWrapper(type: Wrapper) { 30 | gradleVersion = '3.5' 31 | } 32 | 33 | // Used by the Docker gradle plugin, group refers to the account under which the docker image is created 34 | group = 'anilallewar' 35 | mainClassName = 'com.anilallewar.microservices.user.UserApplication' 36 | sourceCompatibility = 1.8 37 | targetCompatibility = 1.8 38 | 39 | repositories { 40 | mavenCentral() 41 | jcenter() 42 | } 43 | 44 | ext { 45 | springCloudVersion = 'Dalston.SR3' 46 | } 47 | 48 | dependencyManagement { 49 | imports { 50 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 51 | } 52 | } 53 | 54 | dependencies { 55 | // Basic Spring boot with config client 56 | compile('org.springframework.cloud:spring-cloud-starter-config') 57 | compile("org.springframework.boot:spring-boot-starter-web") 58 | compile("org.springframework.boot:spring-boot-starter-actuator") 59 | 60 | // Spring OAuth2 security 61 | compile("org.springframework.boot:spring-boot-starter-security") 62 | compile("org.springframework.security.oauth:spring-security-oauth2") 63 | compile("org.springframework.security:spring-security-jwt") 64 | 65 | // Eureka client 66 | compile('org.springframework.cloud:spring-cloud-starter-eureka') 67 | 68 | // Zipkin tracing 69 | compile('org.springframework.cloud:spring-cloud-starter-zipkin') 70 | 71 | // Swagger for API testing 72 | compile("io.springfox:springfox-swagger2:${swagger2version}") 73 | compile("io.springfox:springfox-swagger-ui:${swagger2version}") 74 | } 75 | 76 | jar { 77 | baseName = "${project.jarName}" 78 | version = "${project.versionName}" 79 | } 80 | 81 | /* 82 | * This task builds the docker image by copying the output of the "jar" gradle command 83 | * and moving it to the "build/docker" directory which is used as the staging directory 84 | * by the docker gradle plugin. We then build the docker image by invoking the appropriate 85 | * Dockerfile. 86 | */ 87 | task buildDocker(type: Docker, dependsOn: build) { 88 | push = false 89 | applicationName = jar.baseName 90 | tagVersion = jar.version 91 | dockerfile = file('src/main/docker/Dockerfile') 92 | doFirst { 93 | // Copy the built fat jar to the Docker plugin staging directory 94 | copy { 95 | from jar 96 | into stageDir 97 | } 98 | // Copy the run.sh file to the Docker plugin staging directory 99 | copy { 100 | from "${project.buildDir}/resources/main/run.sh" 101 | into stageDir 102 | } 103 | } 104 | } 105 | 106 | run { 107 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4200,suspend=n','-Dspring.profiles.active=default'] 108 | } 109 | 110 | -------------------------------------------------------------------------------- /user-webservice/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/user-webservice/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /user-webservice/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 26 13:18:22 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip 7 | -------------------------------------------------------------------------------- /user-webservice/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /user-webservice/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------------------------------- 2 | # User Service 3 | #----------------------------------------------------------------------------------------------------- 4 | FROM openjdk:8u121-jdk-alpine 5 | 6 | MAINTAINER Anil Allewar 7 | 8 | # Keep consistent with build.gradle 9 | ENV APP_JAR_NAME basic-user-webservice 10 | ENV APP_JAR_VERSION 0.0.1 11 | 12 | # Install curl 13 | RUN apk --update add curl bash && \ 14 | rm -rf /var/cache/apk/* 15 | 16 | RUN mkdir /app 17 | 18 | ADD ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar /app/ 19 | ADD run.sh /app/ 20 | RUN chmod +x /app/run.sh 21 | 22 | WORKDIR /app 23 | 24 | EXPOSE 8080 25 | 26 | ENTRYPOINT ["/bin/bash","-c"] 27 | CMD ["/app/run.sh"] -------------------------------------------------------------------------------- /user-webservice/src/main/java/com/anilallewar/microservices/user/UserApplication.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.user; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; 7 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 8 | 9 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 10 | 11 | /** 12 | * The boot application class that defines the spring boot application to have 13 | * the following properties
14 | *
15 | * 16 | *
    17 | *
  1. Act as a Eureka client; this behavior is provided by the 18 | * {@link EnableEurekaClient} annotation. The Eureka server URL is provided by 19 | * the external configuration provided by the config server.
  2. 20 | *
  3. @EnableEurekaClient makes the app into both a Eureka "instance" (i.e. it 21 | * registers itself) and a "client" (i.e. it can query the registry to locate 22 | * other services).
  4. 23 | *
  5. Note that all these annotations work in conjunction with properties 24 | * defined in the external configuration files specified by the config server. 25 | *
  6. 26 | *
27 | * 28 | * @author anilallewar 29 | */ 30 | @SpringBootApplication 31 | @EnableEurekaClient 32 | @EnableResourceServer 33 | @EnableSwagger2 34 | @EnableOAuth2Client 35 | public class UserApplication { 36 | 37 | public static void main(String[] args) { 38 | SpringApplication.run(UserApplication.class, args); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /user-webservice/src/main/java/com/anilallewar/microservices/user/api/UserController.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.user.api; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestMethod; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import com.anilallewar.microservices.user.dto.UserDTO; 15 | 16 | /** 17 | * REST endpoint for the user functionality 18 | * 19 | * @author anilallewar 20 | * 21 | */ 22 | @RestController 23 | @RequestMapping("/") 24 | public class UserController { 25 | 26 | private static final Logger LOGGER = Logger.getLogger(UserController.class.getName()); 27 | 28 | @Value("${mail.domain ?: google.com}") 29 | private String mailDomain; 30 | 31 | private List users = Arrays.asList(new UserDTO("Anil", "Allewar", "1", "anil.allewar@" + mailDomain), 32 | new UserDTO("Stefan", "Weber", "2", "stefan.weber@" + mailDomain), 33 | new UserDTO("John", "Snow", "3", "john.snow@" + mailDomain)); 34 | 35 | /** 36 | * Return all users 37 | * 38 | * @return 39 | */ 40 | @RequestMapping(method = RequestMethod.GET, headers = "Accept=application/json") 41 | public List getUsers() { 42 | return users; 43 | } 44 | 45 | /** 46 | * Return user associated with specific user name 47 | * 48 | * @param userName 49 | * @return 50 | */ 51 | @RequestMapping(value = "{userName}", method = RequestMethod.GET, headers = "Accept=application/json") 52 | public UserDTO getUserByUserName(@PathVariable("userName") String userName) { 53 | UserDTO userDtoToReturn = null; 54 | for (UserDTO currentUser : users) { 55 | if (currentUser.getUserName().equalsIgnoreCase(userName)) { 56 | userDtoToReturn = currentUser; 57 | if (LOGGER.isLoggable(Level.INFO)) { 58 | LOGGER.info(String.format("Found matching user: %s", userDtoToReturn.toString())); 59 | } 60 | break; 61 | } 62 | } 63 | 64 | return userDtoToReturn; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /user-webservice/src/main/java/com/anilallewar/microservices/user/config/UserBeanFactory.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.user.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | import springfox.documentation.builders.PathSelectors; 7 | import springfox.documentation.builders.RequestHandlerSelectors; 8 | import springfox.documentation.spi.DocumentationType; 9 | import springfox.documentation.spring.web.plugins.Docket; 10 | 11 | @Configuration 12 | public class UserBeanFactory { 13 | 14 | /** 15 | * Swagger2 support 16 | * 17 | * @return 18 | */ 19 | @Bean 20 | public Docket api() { 21 | return new Docket(DocumentationType.SWAGGER_2).select() 22 | .apis(RequestHandlerSelectors.basePackage("com.anilallewar.microservices.user")).paths(PathSelectors.any()) 23 | .paths(PathSelectors.any()).build(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /user-webservice/src/main/java/com/anilallewar/microservices/user/config/security/ResourceServerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.user.config.security; 2 | 3 | import org.springframework.boot.autoconfigure.security.SecurityProperties; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 7 | import org.springframework.security.config.http.SessionCreationPolicy; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 10 | 11 | /** 12 | * Override the security properties for the resources exposed by this 13 | * application. NOTE that the {@link EnableResourceServer} annotation creates a 14 | * filter with Order as {@link SecurityProperties#ACCESS_OVERRIDE_ORDER} - 1, 15 | * hence this security filter would be applied before the filter defined for web 16 | * security at {@link OAuth2SecurityConfiguration}.
17 | *
18 | * 19 | * What this essentially means is that the rules for the endpoint applied here 20 | * would be applied before the rules defined in the 21 | * {@link WebSecurityConfigurerAdapter} class. 22 | * 23 | * @author anilallewar 24 | * 25 | */ 26 | @Configuration 27 | @EnableResourceServer 28 | public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { 29 | 30 | /* 31 | * (non-Javadoc) 32 | * 33 | * @see org.springframework.security.oauth2.config.annotation.web.configuration. 34 | * ResourceServerConfigurerAdapter#configure(org.springframework.security.config 35 | * .annotation.web.builders.HttpSecurity) 36 | */ 37 | @Override 38 | public void configure(HttpSecurity http) throws Exception { 39 | // @formatter:off 40 | http 41 | .sessionManagement() 42 | .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 43 | .and() 44 | .authorizeRequests() 45 | .anyRequest() 46 | .authenticated(); 47 | // @formatter:on 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /user-webservice/src/main/java/com/anilallewar/microservices/user/config/security/WebSecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.user.config.security; 2 | 3 | import org.springframework.boot.autoconfigure.security.SecurityProperties; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.core.annotation.Order; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.builders.WebSecurity; 8 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 10 | 11 | @Configuration 12 | @EnableWebSecurity 13 | @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) 14 | public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { 15 | @Override 16 | protected void configure(HttpSecurity http) throws Exception { 17 | // @formatter:off 18 | http 19 | .authorizeRequests() 20 | .anyRequest() 21 | .authenticated(); 22 | // @formatter:on 23 | } 24 | 25 | // Swagger specific, allow access 26 | @Override 27 | public void configure(WebSecurity web) throws Exception { 28 | // @formatter:off 29 | web 30 | .ignoring() 31 | .antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources/**", "/configuration/**", 32 | "/swagger-ui.html", "/webjars/**"); 33 | // @formatter:on 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /user-webservice/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: 3 | org: 4 | springframework: 5 | security: DEBUG -------------------------------------------------------------------------------- /user-webservice/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | # Name of the service that is using with Zuul routes to forward specific requests to this service 4 | name: user-webservice 5 | cloud: 6 | config: 7 | # Define the URL from where this service would pick up it's external configuration. Note that it is 8 | # pointing to the config-server aplication 9 | uri: http://localhost:8888 10 | 11 | --- 12 | 13 | spring: 14 | profiles: docker 15 | cloud: 16 | config: 17 | uri: http://configserver:8888 -------------------------------------------------------------------------------- /user-webservice/src/main/resources/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SPRING_ACTIVE_PROFILE=${SPRING_ACTIVE_PROFILE:-"local-docker"} 4 | GIT_BRANCH_LABEL=${GIT_BRANCH_LABEL:-"develop"} 5 | 6 | # The environment variables are already set up by the Dockerfile 7 | exec java -Djava.security.egd=file:/dev/urandom -Dspring.profiles.active=${SPRING_ACTIVE_PROFILE} -Dgit.config.active.branch=${GIT_BRANCH_LABEL} -Duser.timezone=Asia/Kolkata -XX:+PrintFlagsFinal $JAVA_OPTIONS -jar ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar -------------------------------------------------------------------------------- /web-portal/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | .classpath -------------------------------------------------------------------------------- /web-portal/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | web-portal 4 | 5 | 6 | 7 | org.springsource.ide.eclipse.gradle.core.nature 8 | org.eclipse.jdt.core.javanature 9 | 10 | 11 | 12 | org.eclipse.jdt.core.javabuilder 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /web-portal/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.arguments= 2 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) 3 | connection.java.home=null 4 | connection.jvm.arguments= 5 | connection.project.dir= 6 | derived.resources=.gradle,build 7 | eclipse.preferences.version=1 8 | project.path=\: 9 | -------------------------------------------------------------------------------- /web-portal/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | # 2 | #Sat Nov 17 23:37:18 IST 2018 3 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 7 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 8 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 9 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 10 | eclipse.preferences.version=1 11 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 12 | org.eclipse.jdt.core.compiler.source=1.8 13 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 14 | -------------------------------------------------------------------------------- /web-portal/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | This is a Single Page Application(SPA) that has the user facing UI beinng used in the application. It uses the following technologies 4 | * Angular - (base, routes) 5 | * Bootstrap for CSS and layout 6 | * Gradle for build - we could have used grunt/gulp instead 7 | 8 | It is perfectly acceptable to have the SPA not start using the Spring boot application. You would only need to change the Zuul route to forward the request to the actual SPA hosted URL. 9 | 10 | ##Pre-requisites 11 | 12 | ### Projects that need to be started before 13 | * [config server](/../../blob/master/config-server/README.md) - For pulling the configuration information 14 | * [webserver-registry](/../../blob/master/webservice-registry/README.md) - For starting the Eureka server since the authorization server also is a micro-service that needs to be registered with Eureka server. 15 | 16 | ### Running the application 17 | * Build the application by running the `./gradlew clean build` gradle command at the "web-portal" project root folder on the terminal. 18 | * If you want to run the application as jar file, then run `java -jar build/libs/basic-web-portal-0.0.1.jar` command at the terminal. 19 | 20 | ## External Configuration 21 | Please refer to [user webservice](/../../blob/master/user-webservice/README.md) for details on how the external configuration works. Note that there is separate configuration file for each Spring application; the application should refer to it's own .yml file for configuration. 22 | -------------------------------------------------------------------------------- /web-portal/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Build file for Web Portal 3 | */ 4 | apply plugin: 'java' 5 | apply plugin: 'org.springframework.boot' 6 | apply plugin: 'application' 7 | apply plugin: 'docker' 8 | apply plugin: 'eclipse' 9 | 10 | buildscript { 11 | project.ext { 12 | springBootVersion = '1.5.6.RELEASE' 13 | jarName = 'basic-web-portal' 14 | versionName = '0.0.1' 15 | gradleDockerVersion = '1.2' 16 | } 17 | repositories { 18 | jcenter() 19 | mavenCentral() 20 | } 21 | 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.springBootVersion}" 24 | classpath "se.transmode.gradle:gradle-docker:${project.gradleDockerVersion}" 25 | } 26 | } 27 | 28 | task createWrapper(type: Wrapper) { 29 | gradleVersion = '3.5' 30 | } 31 | 32 | /** 33 | * These values(group & mainClassName) are required by the gradle docker plugin. 34 | * 35 | * The "group" value feeds into the docker tag and is required if you want to push the images 36 | * to docker hub. 37 | * 38 | * The "mainClassName" value tells which class has the "main" entry point for running the 39 | * Spring boot application. 40 | */ 41 | 42 | group = 'anilallewar' 43 | mainClassName = 'com.anilallewar.microservices.portal.PortalApplication' 44 | sourceCompatibility = 1.8 45 | targetCompatibility = 1.8 46 | 47 | repositories { 48 | mavenCentral() 49 | jcenter() 50 | } 51 | 52 | ext { 53 | springCloudVersion = 'Dalston.SR3' 54 | } 55 | 56 | dependencyManagement { 57 | imports { 58 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 59 | } 60 | } 61 | 62 | dependencies { 63 | // Basic Spring boot with config client 64 | compile('org.springframework.cloud:spring-cloud-starter-config') 65 | compile("org.springframework.boot:spring-boot-starter-web") 66 | compile("org.springframework.boot:spring-boot-starter-actuator") 67 | 68 | // Spring OAuth2 security 69 | compile("org.springframework.boot:spring-boot-starter-security") 70 | compile("org.springframework.security.oauth:spring-security-oauth2") 71 | 72 | // Eureka client 73 | compile('org.springframework.cloud:spring-cloud-starter-eureka') 74 | 75 | // Hsytrix dashboard 76 | compile('org.springframework.cloud:spring-cloud-starter-hystrix') 77 | compile('org.springframework.cloud:spring-cloud-starter-hystrix-dashboard') 78 | compile('org.springframework.cloud:spring-cloud-starter-turbine') 79 | } 80 | 81 | jar { 82 | baseName = "${project.jarName}" 83 | version = "${project.versionName}" 84 | } 85 | 86 | /* 87 | * This task builds the docker image by copying the output of the "jar" gradle command 88 | * and moving it to the "build/docker" directory which is used as the staging directory 89 | * by the docker gradle plugin. We then build the docker image by invoking the appropriate 90 | * Dockerfile. 91 | */ 92 | task buildDocker(type: Docker, dependsOn: build) { 93 | push = false 94 | applicationName = jar.baseName 95 | tagVersion = jar.version 96 | dockerfile = file('src/main/docker/Dockerfile') 97 | doFirst { 98 | // Copy the built fat jar to the Docker plugin staging directory 99 | copy { 100 | from jar 101 | into stageDir 102 | } 103 | // Copy the run.sh file to the Docker plugin staging directory 104 | copy { 105 | from "${project.buildDir}/resources/main/run.sh" 106 | into stageDir 107 | } 108 | } 109 | } 110 | 111 | run { 112 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4300,suspend=n','-Dspring.profiles.active=default'] 113 | } -------------------------------------------------------------------------------- /web-portal/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/web-portal/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /web-portal/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 26 19:04:56 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip 7 | -------------------------------------------------------------------------------- /web-portal/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /web-portal/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------------------------------- 2 | # API Gateway 3 | #----------------------------------------------------------------------------------------------------- 4 | FROM openjdk:8u121-jdk-alpine 5 | 6 | MAINTAINER Anil Allewar 7 | 8 | # Keep consistent with build.gradle 9 | ENV APP_JAR_NAME basic-web-portal 10 | ENV APP_JAR_VERSION 0.0.1 11 | 12 | # Install curl 13 | RUN apk --update add curl bash && \ 14 | rm -rf /var/cache/apk/* 15 | 16 | RUN mkdir /app 17 | 18 | ADD ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar /app/ 19 | ADD run.sh /app/ 20 | RUN chmod +x /app/run.sh 21 | 22 | WORKDIR /app 23 | 24 | EXPOSE 8080 25 | 26 | ENTRYPOINT ["/bin/bash","-c"] 27 | CMD ["/app/run.sh"] 28 | -------------------------------------------------------------------------------- /web-portal/src/main/java/com/anilallewar/microservices/portal/PortalApplication.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.portal; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; 7 | import org.springframework.cloud.netflix.turbine.EnableTurbine; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 10 | 11 | /** 12 | * The boot application class that defines the spring boot application to have 13 | * the following properties
14 | *
15 | * 16 | *
    17 | *
  1. Act as a Eureka client; this behavior is provided by the 18 | * {@link EnableEurekaClient} annotation. The Eureka server URL is provided by 19 | * the external configuration provided by the config server.
  2. 20 | *
  3. No security is defined for this application since it's the client facing 21 | * UI application.
  4. 22 | *
  5. All the UI artifacts are stored under the "public" folder at 23 | * the root.
  6. 24 | *
25 | * 26 | * @author anilallewar 27 | * 28 | */ 29 | @SpringBootApplication 30 | @EnableEurekaClient 31 | @EnableHystrixDashboard 32 | @EnableTurbine 33 | public class PortalApplication extends WebSecurityConfigurerAdapter { 34 | 35 | public static void main(String[] args) { 36 | SpringApplication.run(PortalApplication.class, args); 37 | } 38 | 39 | @Override 40 | public void configure(HttpSecurity http) throws Exception { 41 | // @formatter:off 42 | http.logout().and().authorizeRequests().antMatchers("/**/*.html", "/", "/login","/hystrix/**","/turbine.stream").permitAll().anyRequest() 43 | .authenticated(); 44 | // @formatter:on 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /web-portal/src/main/resources/application.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/web-portal/src/main/resources/application.yml -------------------------------------------------------------------------------- /web-portal/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: web-portal 4 | cloud: 5 | config: 6 | uri: http://localhost:8888 7 | 8 | --- 9 | 10 | spring: 11 | profiles: docker 12 | cloud: 13 | config: 14 | uri: http://configserver:8888 -------------------------------------------------------------------------------- /web-portal/src/main/resources/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SPRING_ACTIVE_PROFILE=${SPRING_ACTIVE_PROFILE:-"local-docker"} 4 | GIT_BRANCH_LABEL=${GIT_BRANCH_LABEL:-"develop"} 5 | 6 | # The environment variables are already set up by the Dockerfile 7 | exec java -Djava.security.egd=file:/dev/urandom -Dspring.profiles.active=${SPRING_ACTIVE_PROFILE} -Dgit.config.active.branch=${GIT_BRANCH_LABEL} -Duser.timezone=Asia/Kolkata -XX:+PrintFlagsFinal $JAVA_OPTIONS -jar ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar -------------------------------------------------------------------------------- /web-portal/src/main/resources/static/js/app/controller/homeController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('oauthApp') 4 | .controller('homeCtrl', function () {}); 5 | -------------------------------------------------------------------------------- /web-portal/src/main/resources/static/js/app/controller/navController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('oauthApp') 4 | .controller('navigationCtrl', ['$rootScope', '$scope', '$http', '$location', 'dataService', function ($rootScope, $scope, $http, $location, dataService) { 5 | 6 | var assignAuthenticationStatus = function (data) { 7 | if (data.name) { 8 | $rootScope.userAuthenticated = true; 9 | $rootScope.loggedInUserName = data.name; 10 | } else { 11 | $rootScope.userAuthenticated = false; 12 | } 13 | }; 14 | 15 | var handleError = function (error) { 16 | console.log(error); 17 | $rootScope.userAuthenticated = false; 18 | }; 19 | 20 | dataService.getLoggedInUser().then(assignAuthenticationStatus, handleError); 21 | 22 | $scope.logout = function () { 23 | $http.post('logout', {}).success(function () { 24 | $rootScope.userAuthenticated = false; 25 | $location.path("/"); 26 | }).error(function (data) { 27 | $rootScope.userAuthenticated = false; 28 | }); 29 | } 30 | }]); 31 | -------------------------------------------------------------------------------- /web-portal/src/main/resources/static/js/app/controller/taskController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc function 5 | * @name oauthApp.controller:UserCtrl 6 | * @description 7 | * # PreviewPlaceHolderCtrl 8 | * Controller of the alertApp 9 | */ 10 | angular.module('oauthApp') 11 | .controller('taskCtrl', function ($scope, $location, $http, dataService) { 12 | 13 | // Assigns data from the task service into "token" 14 | // variables in controller scope. 15 | var assignAllTaskDataToScope = function (data) { 16 | $scope.taskDataArray = data; 17 | }; 18 | 19 | var logError = function (error) { 20 | console.log(error); 21 | }; 22 | 23 | // Assign data for a single user 24 | var assignTaskDataToScope = function (data) { 25 | $scope.taskData = data; 26 | }; 27 | 28 | var assignUserTaskDataToScope = function (data) { 29 | $scope.taskDataForUser = data; 30 | }; 31 | 32 | // Method exposed to get specific task data 33 | this.getTaskDataByTaskId = function (taskId) { 34 | dataService.getTaskDataByTaskId(taskId) 35 | .then(assignTaskDataToScope, logError); 36 | }; 37 | 38 | // Method exposed to get specific task data 39 | this.getTaskDataByUserName = function (userName) { 40 | dataService.getTaskDataByUserName(userName) 41 | .then(assignUserTaskDataToScope, logError); 42 | }; 43 | 44 | //When the script loads, get all the user's data 45 | dataService.getAllTaskData() 46 | .then(assignAllTaskDataToScope, logError); 47 | }); 48 | -------------------------------------------------------------------------------- /web-portal/src/main/resources/static/js/app/controller/userController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc function 5 | * @name oauthApp.controller:UserCtrl 6 | * @description 7 | * # PreviewPlaceHolderCtrl 8 | * Controller of the alertApp 9 | */ 10 | angular.module('oauthApp') 11 | .controller('userCtrl', function ($scope, $location, $http, dataService) { 12 | 13 | // Assigns data from the user service into "token" 14 | // variables in controller scope. 15 | var assignAllUserDataToScope = function (data) { 16 | $scope.userDataArray = data; 17 | }; 18 | 19 | var logError = function (error) { 20 | console.log(error); 21 | }; 22 | 23 | // Assign data for a single user 24 | var assignUserDataToScope = function (data) { 25 | $scope.userData = data; 26 | }; 27 | 28 | // Method exposed to get specific user data 29 | this.getUserDataByUserName = function (userName) { 30 | dataService.getUserDataByUserName(userName) 31 | .then(assignUserDataToScope, logError); 32 | }; 33 | 34 | //When the script loads, get all the user's data 35 | dataService.getAllUserData() 36 | .then(assignAllUserDataToScope, logError); 37 | }); -------------------------------------------------------------------------------- /web-portal/src/main/resources/static/js/app/oauthapp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('oauthApp', ['ngRoute']) 4 | .config(function ($routeProvider, $httpProvider) { 5 | $routeProvider.when('/', { 6 | templateUrl: 'views/home.html', 7 | controller: 'homeCtrl' 8 | }).when('/user', { 9 | templateUrl: 'views/user.html', 10 | controller: 'userCtrl', 11 | controllerAs: 'userController' 12 | }).when('/task', { 13 | templateUrl: 'views/task.html', 14 | controller: 'taskCtrl', 15 | controllerAs: 'taskController' 16 | }).otherwise('/'); 17 | 18 | //Custom header is needed starting angular 1.3; else Spring security might pop authentication dialog 19 | // by sending the WWW-Authenticate header field in the 401 Unauhorized HTTP response 20 | $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest'; 21 | }) 22 | .directive("taskComments", function () { 23 | return { 24 | restrict: 'E', 25 | scope: { 26 | taskComments: '=comments' 27 | }, 28 | templateUrl: "views/task-comments.html" 29 | }; 30 | }) 31 | .directive("taskDetails", function () { 32 | return { 33 | restrict: 'E', 34 | templateUrl: "views/task-details.html" 35 | }; 36 | }); 37 | -------------------------------------------------------------------------------- /web-portal/src/main/resources/static/js/app/services/dataservice.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc service 5 | * @name alertApp.dataService 6 | * @description 7 | * # dataService 8 | * Factory in the alertApp. 9 | */ 10 | angular.module('oauthApp') 11 | .factory('dataService', function ($http, $q) { 12 | // We always use this angular service within the preview context 13 | var userApi = '/user-service/'; 14 | 15 | var taskApi = '/task-service/'; 16 | 17 | var loggedInUserApi = '/api/loggedinuser/me'; 18 | 19 | // This method makes the REST call and the response is parsed by 20 | // Angular.js by default to convert to JSON. If the response is 21 | // successfully parsed then the JSON is available as an 'object' 22 | var makeRestCall = function (url) { 23 | return $http.get(url) 24 | .then(function (response) { 25 | 26 | if (typeof response.data === 'object') { 27 | return response.data; 28 | } else { 29 | // invalid response 30 | return $q.reject(response.data); 31 | } 32 | 33 | }, function (response) { 34 | // something went wrong 35 | return $q.reject(response.data); 36 | }); 37 | }; 38 | 39 | return { 40 | getAllUserData: function () { 41 | // Make call to the api to get all users 42 | return makeRestCall(userApi); 43 | }, 44 | 45 | getAllTaskData: function () { 46 | // Make call to the api to get all tasks 47 | return makeRestCall(taskApi); 48 | }, 49 | 50 | getUserDataByUserName: function (userName) { 51 | // Make call to the api to get user details by user name 52 | return makeRestCall(userApi + userName); 53 | }, 54 | 55 | getTaskDataByTaskId: function (taskId) { 56 | // Make call to theapi to get task details by task id 57 | return makeRestCall(taskApi + taskId); 58 | }, 59 | 60 | getTaskDataByUserName: function (userName) { 61 | return makeRestCall(taskApi + 'usertask' + '/' + userName); 62 | }, 63 | 64 | getLoggedInUser: function () { 65 | // Make call to get the current logged in user 66 | return makeRestCall(loggedInUserApi); 67 | } 68 | }; 69 | }); -------------------------------------------------------------------------------- /web-portal/src/main/resources/static/views/home.html: -------------------------------------------------------------------------------- 1 |
2 |

Hi {{loggedInUserName}}

3 |
4 | Click on the login link to authenticate 5 |
6 |
7 | -------------------------------------------------------------------------------- /web-portal/src/main/resources/static/views/task-comments.html: -------------------------------------------------------------------------------- 1 |
2 |

Task Comments

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
IDCommentDate
{{comment.taskId}}{{comment.comment}}{{comment.posted}}
15 |
16 | -------------------------------------------------------------------------------- /web-portal/src/main/resources/static/views/task-details.html: -------------------------------------------------------------------------------- 1 |

Task Details

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
IDDescriptionCompletedUser Name
{{taskData.taskId}}{{taskData.description}}{{taskData.completed}}{{taskData.userName}}
17 | -------------------------------------------------------------------------------- /web-portal/src/main/resources/static/views/task.html: -------------------------------------------------------------------------------- 1 |
2 |

Task Summary

3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
IDDescriptionCompleted
{{task.taskId}}{{task.description}}{{task.completed}}
17 |
18 | 19 |
20 | 21 | 22 | 23 | 24 |
25 | 26 |
27 | -------------------------------------------------------------------------------- /web-portal/src/main/resources/static/views/user.html: -------------------------------------------------------------------------------- 1 |
2 |

User Summary

3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 |
IDFirst NameLast Name
{{user.userName}}{{user.firstName}}{{user.lastName}}
18 |
19 | 20 |
21 |

User Details

22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
IDFirst NameLastNameEmail
{{userData.userName}}{{userData.firstName}}{{userData.lastName}}{{userData.emailAddress}}
37 |
38 | 39 |
-------------------------------------------------------------------------------- /webservice-registry/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | .classpath -------------------------------------------------------------------------------- /webservice-registry/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | webservice-registry 4 | 5 | 6 | 7 | org.springsource.ide.eclipse.gradle.core.nature 8 | org.eclipse.jdt.core.javanature 9 | 10 | 11 | 12 | org.eclipse.jdt.core.javabuilder 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /webservice-registry/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | # 2 | #Thu Apr 27 19:28:56 IST 2017 3 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 7 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 8 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 9 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 10 | eclipse.preferences.version=1 11 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 12 | org.eclipse.jdt.core.compiler.source=1.8 13 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 14 | -------------------------------------------------------------------------------- /webservice-registry/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | This application provides the **Eureka Server** that provides service discovery and enables all Eureka clients to discover each other. 4 | 5 | When a client registers with Eureka, it provides meta-data about itself such as host and port, health indicator URL, home page etc. Eureka receives heartbeat messages from each instance belonging to a service. If the heartbeat fails over a configurable timetable, the instance is normally removed from the registry. 6 | 7 | ##Pre-requisites 8 | 9 | ### Projects that need to be started before 10 | * [config server](/../../blob/master/config-server/README.md) - For pulling the configuration information 11 | 12 | ### Running the application 13 | * Build the application by running the `./gradlew clean build` gradle command at the "webservice-registry" project root folder on the terminal. 14 | * If you want to run the application as jar file, then run `java -jar build/libs/basic-webservice-registry-0.0.1.jar` command at the terminal. 15 | 16 | ## External Configuration 17 | Please refer to [user webservice](/../../blob/master/user-webservice/README.md) for details on how the external configuration works. Note that there is separate configuration file for each Spring application; the application should refer to it's own .yml file for configuration. -------------------------------------------------------------------------------- /webservice-registry/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Build file for discovery server 3 | */ 4 | apply plugin: 'java' 5 | apply plugin: 'org.springframework.boot' 6 | apply plugin: 'application' 7 | apply plugin: 'docker' 8 | apply plugin: 'eclipse' 9 | 10 | buildscript { 11 | project.ext { 12 | springBootVersion = '1.5.6.RELEASE' 13 | jarName = 'basic-webservice-registry' 14 | versionName = '0.0.1' 15 | gradleDockerVersion = '1.2' 16 | } 17 | repositories { 18 | jcenter() 19 | mavenCentral() 20 | } 21 | 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.springBootVersion}" 24 | classpath "se.transmode.gradle:gradle-docker:${project.gradleDockerVersion}" 25 | } 26 | } 27 | 28 | task createWrapper(type: Wrapper) { 29 | gradleVersion = '3.5' 30 | } 31 | 32 | // Used by the Docker gradle plugin, group refers to the account under which the docker image is created 33 | group = 'anilallewar' 34 | mainClassName = 'com.anilallewar.microservices.registry.RegistryApplication' 35 | sourceCompatibility = 1.8 36 | targetCompatibility = 1.8 37 | 38 | repositories { 39 | mavenCentral() 40 | jcenter() 41 | } 42 | 43 | ext { 44 | springCloudVersion = 'Dalston.SR3' 45 | } 46 | 47 | dependencyManagement { 48 | imports { 49 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 50 | } 51 | } 52 | 53 | dependencies { 54 | compile('org.springframework.cloud:spring-cloud-starter-config') 55 | compile('org.springframework.boot:spring-boot-starter-actuator') 56 | compile("org.springframework.cloud:spring-cloud-starter-eureka-server") 57 | } 58 | 59 | jar { 60 | baseName = "${project.jarName}" 61 | version = "${project.versionName}" 62 | } 63 | 64 | /* 65 | * This task builds the docker image by copying the output of the "jar" gradle command 66 | * and moving it to the "build/docker" directory which is used as the staging directory 67 | * by the docker gradle plugin. We then build the docker image by invoking the appropriate 68 | * Dockerfile. 69 | */ 70 | task buildDocker(type: Docker, dependsOn: build) { 71 | push = false 72 | applicationName = jar.baseName 73 | tagVersion = jar.version 74 | dockerfile = file('src/main/docker/Dockerfile') 75 | doFirst { 76 | // Copy the built fat jar to the Docker plugin staging directory 77 | copy { 78 | from jar 79 | into stageDir 80 | } 81 | // Copy the run.sh file to the Docker plugin staging directory 82 | copy { 83 | from "${project.buildDir}/resources/main/run.sh" 84 | into stageDir 85 | } 86 | } 87 | } 88 | 89 | run { 90 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4100,suspend=n','-Dspring.profiles.active=default'] 91 | } -------------------------------------------------------------------------------- /webservice-registry/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/webservice-registry/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /webservice-registry/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Apr 24 15:05:23 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip 7 | -------------------------------------------------------------------------------- /webservice-registry/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /webservice-registry/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------------------------------- 2 | # Discovery Server 3 | #----------------------------------------------------------------------------------------------------- 4 | FROM openjdk:8u121-jdk-alpine 5 | 6 | MAINTAINER Anil Allewar 7 | 8 | # Keep consistent with build.gradle 9 | ENV APP_JAR_NAME basic-webservice-registry 10 | ENV APP_JAR_VERSION 0.0.1 11 | 12 | # Install curl 13 | RUN apk --update add curl bash && \ 14 | rm -rf /var/cache/apk/* 15 | 16 | RUN mkdir /app 17 | 18 | ADD ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar /app/ 19 | ADD run.sh /app/ 20 | RUN chmod +x /app/run.sh 21 | 22 | WORKDIR /app 23 | 24 | EXPOSE 8761 25 | 26 | ENTRYPOINT ["/bin/bash","-c"] 27 | CMD ["/app/run.sh"] 28 | -------------------------------------------------------------------------------- /webservice-registry/src/main/java/com/anilallewar/microservices/registry/RegistryApplication.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.registry; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | /** 8 | * The Main Spring Boot Application class that starts the Eureka discovery 9 | * server since the application is annotated with {@link EnableEurekaServer}. 10 | *
11 | *
12 | * 13 | * Note that all these annotations work in conjunction with properties defined 14 | * in the external configuration files specified by the config server. 15 | * 16 | * @author anilallewar 17 | */ 18 | 19 | @EnableEurekaServer 20 | @SpringBootApplication 21 | public class RegistryApplication { 22 | 23 | /** 24 | * The main method. 25 | * 26 | * @param args the arguments 27 | */ 28 | public static void main(String[] args) { 29 | SpringApplication.run(RegistryApplication.class, args); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /webservice-registry/src/main/resources/application.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/webservice-registry/src/main/resources/application.yml -------------------------------------------------------------------------------- /webservice-registry/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: webservice-registry 4 | cloud: 5 | config: 6 | uri: http://localhost:8888 7 | 8 | --- 9 | 10 | spring: 11 | profiles: docker 12 | cloud: 13 | config: 14 | uri: http://configserver:8888 15 | -------------------------------------------------------------------------------- /webservice-registry/src/main/resources/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SPRING_ACTIVE_PROFILE=${SPRING_ACTIVE_PROFILE:-"local-docker"} 4 | GIT_BRANCH_LABEL=${GIT_BRANCH_LABEL:-"develop"} 5 | 6 | # The environment variables are already set up by the Dockerfile 7 | exec java -Djava.security.egd=file:/dev/urandom -Dspring.profiles.active=${SPRING_ACTIVE_PROFILE} -Dgit.config.active.branch=${GIT_BRANCH_LABEL} -Duser.timezone=Asia/Kolkata -XX:+PrintFlagsFinal $JAVA_OPTIONS -jar ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar -------------------------------------------------------------------------------- /zipkin-server/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | .classpath -------------------------------------------------------------------------------- /zipkin-server/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | zipkin-server 4 | 5 | 6 | 7 | org.eclipse.jdt.core.javanature 8 | 9 | 10 | 11 | org.eclipse.jdt.core.javabuilder 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /zipkin-server/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | # 2 | #Mon Jul 03 12:51:16 IST 2017 3 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 7 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 8 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 9 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 10 | eclipse.preferences.version=1 11 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 12 | org.eclipse.jdt.core.compiler.source=1.8 13 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 14 | -------------------------------------------------------------------------------- /zipkin-server/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | This application provides the **Zipkin Server** that provides UI for the [Zipkin distributed tracing](http://zipkin.io/). 4 | 5 | When we enable tracing on the applications, they send the tracing data (timing, components called etc) to the Zipkin server so that we can visualize it. 6 | 7 | ##Pre-requisites 8 | 9 | ### Projects that need to be started before 10 | * [config server](/../../blob/master/config-server/README.md) - For pulling the configuration information 11 | 12 | ### Running the application 13 | * Build the application by running the `./gradlew clean build` gradle command at the "webservice-registry" project root folder on the terminal. 14 | * If you want to run the application as jar file, then run `java -jar build/libs/basic-zipkin-server-0.0.1.jar` command at the terminal. 15 | 16 | ## External Configuration 17 | Please refer to [user webservice](/../../blob/master/user-webservice/README.md) for details on how the external configuration works. Note that there is separate configuration file for each Spring application; the application should refer to it's own .yml file for configuration. -------------------------------------------------------------------------------- /zipkin-server/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Build file for Zipkin server that is used for tracing 3 | */ 4 | apply plugin: 'java' 5 | apply plugin: 'org.springframework.boot' 6 | apply plugin: 'application' 7 | apply plugin: 'docker' 8 | apply plugin: 'eclipse' 9 | 10 | buildscript { 11 | project.ext { 12 | springBootVersion = '1.5.6.RELEASE' 13 | jarName = 'basic-zipkin-server' 14 | versionName = '0.0.1' 15 | gradleDockerVersion = '1.2' 16 | } 17 | repositories { 18 | jcenter() 19 | mavenCentral() 20 | } 21 | 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.springBootVersion}" 24 | 25 | // Gradle docker plugin dependency 26 | classpath "se.transmode.gradle:gradle-docker:${project.gradleDockerVersion}" 27 | 28 | } 29 | } 30 | 31 | task createWrapper(type: Wrapper) { 32 | gradleVersion = '3.5' 33 | } 34 | 35 | // Used by the Docker gradle plugin, group refers to the account under which the docker image is created 36 | group = 'anilallewar' 37 | mainClassName = 'com.anilallewar.microservices.tracing.ZipkinTracingApplication' 38 | sourceCompatibility = 1.8 39 | targetCompatibility = 1.8 40 | 41 | repositories { 42 | mavenCentral() 43 | jcenter() 44 | } 45 | 46 | ext { 47 | springCloudVersion = 'Dalston.SR3' 48 | } 49 | 50 | dependencyManagement { 51 | imports { 52 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 53 | } 54 | } 55 | 56 | dependencies { 57 | // Basic Spring boot with config client 58 | compile('org.springframework.cloud:spring-cloud-starter-config') 59 | compile("org.springframework.boot:spring-boot-starter-web") 60 | compile("org.springframework.boot:spring-boot-starter-actuator") 61 | 62 | // Zipkin tracing 63 | compile('org.springframework.cloud:spring-cloud-starter-zipkin') 64 | runtime('io.zipkin.java:zipkin-autoconfigure-ui') 65 | compile('io.zipkin.java:zipkin-server') 66 | } 67 | 68 | jar { 69 | baseName = "${project.jarName}" 70 | version = "${project.versionName}" 71 | } 72 | 73 | /* 74 | * This task builds the docker image by copying the output of the "jar" gradle command 75 | * and moving it to the "build/docker" directory which is used as the staging directory 76 | * by the docker gradle plugin. We then build the docker image by invoking the appropriate 77 | * Dockerfile. 78 | */ 79 | task buildDocker(type: Docker, dependsOn: build) { 80 | push = false 81 | applicationName = jar.baseName 82 | tagVersion = jar.version 83 | dockerfile = file('src/main/docker/Dockerfile') 84 | doFirst { 85 | // Copy the built fat jar to the Docker plugin staging directory 86 | copy { 87 | from jar 88 | into stageDir 89 | } 90 | // Copy the run.sh file to the Docker plugin staging directory 91 | copy { 92 | from "${project.buildDir}/resources/main/run.sh" 93 | into stageDir 94 | } 95 | } 96 | } 97 | 98 | run { 99 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4300,suspend=n','-Dspring.profiles.active=default'] 100 | } -------------------------------------------------------------------------------- /zipkin-server/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/zipkin-server/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /zipkin-server/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jul 03 12:15:58 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip 7 | -------------------------------------------------------------------------------- /zipkin-server/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /zipkin-server/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------------------------------------- 2 | # User Service 3 | #----------------------------------------------------------------------------------------------------- 4 | FROM openjdk:8u121-jdk-alpine 5 | 6 | MAINTAINER Anil Allewar 7 | 8 | # Keep consistent with build.gradle 9 | ENV APP_JAR_NAME basic-zipkin-server 10 | ENV APP_JAR_VERSION 0.0.1 11 | 12 | # Install curl 13 | RUN apk --update add curl bash && \ 14 | rm -rf /var/cache/apk/* 15 | 16 | RUN mkdir /app 17 | 18 | ADD ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar /app/ 19 | ADD run.sh /app/ 20 | RUN chmod +x /app/run.sh 21 | 22 | WORKDIR /app 23 | 24 | EXPOSE 9411 25 | 26 | ENTRYPOINT ["/bin/bash","-c"] 27 | CMD ["/app/run.sh"] 28 | -------------------------------------------------------------------------------- /zipkin-server/src/main/java/com/anilallewar/microservices/tracing/ZipkinTracingApplication.java: -------------------------------------------------------------------------------- 1 | package com.anilallewar.microservices.tracing; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | import zipkin.server.EnableZipkinServer; 7 | 8 | /** 9 | * The boot application class that provides the zipkin server UI. 10 | * 11 | * @author anilallewar 12 | * 13 | */ 14 | @SpringBootApplication 15 | @EnableZipkinServer 16 | public class ZipkinTracingApplication { 17 | 18 | public static void main(String[] args) { 19 | SpringApplication.run(ZipkinTracingApplication.class,args); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /zipkin-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anilallewar/microservices-basics-spring-boot/ac0a249156471ad98fa5ba5508fda9deabba6975/zipkin-server/src/main/resources/application.yml -------------------------------------------------------------------------------- /zipkin-server/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: zipkin-tracing 4 | cloud: 5 | config: 6 | 7 | # Define the URL from where this service would pick up it's external configuration. Note that it is 8 | # pointing to the config-server aplication 9 | uri: http://localhost:8888 10 | 11 | --- 12 | 13 | spring: 14 | profiles: docker 15 | cloud: 16 | config: 17 | uri: http://configserver:8888 -------------------------------------------------------------------------------- /zipkin-server/src/main/resources/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SPRING_ACTIVE_PROFILE=${SPRING_ACTIVE_PROFILE:-"local-docker"} 4 | GIT_BRANCH_LABEL=${GIT_BRANCH_LABEL:-"develop"} 5 | 6 | # The environment variables are already set up by the Dockerfile 7 | exec java -Djava.security.egd=file:/dev/urandom -Dspring.profiles.active=${SPRING_ACTIVE_PROFILE} -Dgit.config.active.branch=${GIT_BRANCH_LABEL} -Duser.timezone=Asia/Kolkata -XX:+PrintFlagsFinal $JAVA_OPTIONS -jar ${APP_JAR_NAME}-${APP_JAR_VERSION}.jar --------------------------------------------------------------------------------