Skip to content

Commit

Permalink
Merge pull request spinnaker#88 from OpsMx/OP-10250
Browse files Browse the repository at this point in the history
Op 10250
  • Loading branch information
ramyaravi-opsmx authored Dec 14, 2021
2 parents 2d44d39 + 0a356d2 commit df57e9e
Show file tree
Hide file tree
Showing 13 changed files with 337 additions and 19 deletions.
3 changes: 3 additions & 0 deletions docker_build/gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ retrofit:
writeTimeout: 30000
retryOnConnectionFailure: true

cache:
expiryTime: 600000

security:
basic:
enabled: false
Expand Down
2 changes: 2 additions & 0 deletions gate-web/gate-web.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ dependencies {
implementation "io.springfox:springfox-swagger2"

implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: '2.9.2'


implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-openfeign', version: '2.2.4.RELEASE'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.netflix.spinnaker.gate.controllers
import com.netflix.spinnaker.gate.services.internal.OpsmxDashboardService
import com.opsmx.spinnaker.gate.factory.dashboard.DashboardCachingServiceBeanFactory
import com.opsmx.spinnaker.gate.service.DashboardCachingService
import com.opsmx.spinnaker.gate.util.CacheUtil
import groovy.util.logging.Slf4j
import io.swagger.annotations.ApiOperation
import org.springframework.beans.factory.annotation.Autowired
Expand Down Expand Up @@ -63,7 +64,7 @@ class OpsmxDashboardController {
Object response = null
String path = httpServletRequest.getRequestURI()

if (DashboardCachingService.isRegisteredCachingEndpoint(path)) {
if (CacheUtil.isRegisteredCachingEndpoint(path)) {
DashboardCachingService dashboardCachingService = dashboardCachingServiceBeanFactory.getBean(path)
response = handleCaching(httpServletRequest, version, type, dashboardCachingService)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ package com.netflix.spinnaker.gate.controllers

import com.netflix.spinnaker.gate.config.ServiceConfiguration
import com.netflix.spinnaker.gate.services.internal.OpsmxPlatformService
import com.opsmx.spinnaker.gate.factory.platform.PlatformCachingServiceBeanFactory
import com.opsmx.spinnaker.gate.service.PlatformCachingService
import com.opsmx.spinnaker.gate.util.CacheUtil
import groovy.util.logging.Slf4j
import io.swagger.annotations.ApiOperation
import okhttp3.OkHttpClient
Expand All @@ -28,6 +31,8 @@ import org.springframework.web.bind.annotation.*
import retrofit.client.Response
import org.apache.commons.io.IOUtils
import org.springframework.http.MediaType

import javax.servlet.http.HttpServletRequest
import java.util.stream.Collectors
import org.springframework.http.ResponseEntity

Expand Down Expand Up @@ -55,6 +60,9 @@ class OpsmxPlatformController {
@Autowired
OpsmxPlatformService opsmxPlatformService

@Autowired
PlatformCachingServiceBeanFactory platformCachingServiceBeanFactory

@ApiOperation(value = "Endpoint for platform rest services")
@RequestMapping(value = "/{version}/{type}", method = RequestMethod.GET)
Object getPlatformResponse1(@PathVariable("version") String version,
Expand All @@ -78,13 +86,31 @@ class OpsmxPlatformController {
@ApiOperation(value = "Endpoint for platform rest services")
@RequestMapping(value = "/{version}/{type}/{source}/{source1}", method = RequestMethod.GET)
Object getPlatformResponse4(@PathVariable("version") String version,
@PathVariable("type") String type,
@PathVariable("source") String source,
@PathVariable("source1") String source1,
@RequestParam(value = "datasourceType", required = false) String datasourceType,
@RequestParam(value = "permissionId", required = false) String permissionId) {
@PathVariable("type") String type,
@PathVariable("source") String source,
@PathVariable("source1") String source1,
@RequestParam(value = "datasourceType", required = false) String datasourceType,
@RequestParam(value = "permissionId", required = false) String permissionId, HttpServletRequest httpServletRequest) {

return opsmxPlatformService.getPlatformResponse4(version, type, source, source1,datasourceType, permissionId)
String path = httpServletRequest.getRequestURI()
if (CacheUtil.isRegisteredCachingEndpoint(path)){
return handleCaching(path, httpServletRequest, version, type, source, source1, datasourceType, permissionId)
} else {
return opsmxPlatformService.getPlatformResponse4(version, type, source, source1, datasourceType, permissionId)
}
}

private Object handleCaching(String path, HttpServletRequest httpServletRequest, String version, String type, String source, String source1, String datasourceType, String permissionId) {
Object response
PlatformCachingService platformCachingService = platformCachingServiceBeanFactory.getBean(path)

String userName = httpServletRequest.getUserPrincipal().getName()
response = platformCachingService.fetchResponseFromCache(userName)
if (response == null) {
response = opsmxPlatformService.getPlatformResponse4(version, type, source, source1, datasourceType, permissionId)
platformCachingService.cacheResponse(response, userName)
}
return response
}

@ApiOperation(value = "Endpoint for platform rest services")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ public interface Constants {

String GET_ALL_DATASOURCES_ENDPOINT = "/dashboardservice/v4/getAllDatasources";
String GET_DATASOURCE_BY_ID_ENDPOINT = "/dashboardservice/v4/datasource/{id}";
String CHECK_IS_ADMIN_ENDPOINT = "/platformservice/v1/users/{username}/isadmin";
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,42 @@

package com.opsmx.spinnaker.gate.cache;

import com.github.benmanes.caffeine.cache.Caffeine;
import java.util.concurrent.TimeUnit;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Configuration
public class OesCacheManager {

@Getter private CacheManager concurrentMapCacheManager;

@Getter private CaffeineCacheManager caffeineCacheManager;

@Value("${cache.expiryTime:600000}")
private String cacheExpiryTimeout;

@Primary
@Bean(name = "concurrentMapCacheManager")
public CacheManager concurrentMapCacheManager() {
concurrentMapCacheManager = new ConcurrentMapCacheManager("datasource");
return concurrentMapCacheManager;
}

@Bean(name = "caffeineCacheManager")
public CacheManager cacheManager() {

CaffeineCacheManager cacheManager = new CaffeineCacheManager("adminAuth");
cacheManager.setCaffeine(
Caffeine.newBuilder()
.expireAfterWrite(Long.parseLong(cacheExpiryTimeout), TimeUnit.MILLISECONDS));
caffeineCacheManager = cacheManager;
return cacheManager;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2021 OpsMx, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.opsmx.spinnaker.gate.cache.platform;

import java.util.Map;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;

public interface AuthorizationCaching {

@CachePut(value = "adminAuth", key = "#userName", cacheManager = "caffeineCacheManager")
Map<String, Object> populateAdminAuthCache(String userName, Map<String, Object> response);

@Cacheable(value = "adminAuth", key = "#userName", cacheManager = "caffeineCacheManager")
Map<String, Object> getRecordFromAdminAuthCache(String userName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2021 OpsMx, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.opsmx.spinnaker.gate.cache.platform;

import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class AuthorizationCachingImpl implements AuthorizationCaching {

@Override
public Map<String, Object> populateAdminAuthCache(String userName, Map<String, Object> response) {
log.debug("populating admin auth cache");
return response;
}

@Override
public Map<String, Object> getRecordFromAdminAuthCache(String userName) {
log.debug("getting record from admin auth cache");
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2021 OpsMx, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.opsmx.spinnaker.gate.factory.platform;

import com.opsmx.spinnaker.gate.cache.Constants;
import com.opsmx.spinnaker.gate.service.AdminAuthService;
import com.opsmx.spinnaker.gate.service.PlatformCachingService;
import com.opsmx.spinnaker.gate.util.CacheUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class PlatformCachingServiceBeanFactory {

@Autowired private AdminAuthService adminAuthService;

public PlatformCachingService getBean(String path) {

PlatformCachingService platformCachingService = null;
path = CacheUtil.formatPath(path);
switch (path) {
case Constants.CHECK_IS_ADMIN_ENDPOINT:
platformCachingService = adminAuthService;
break;
}
return platformCachingService;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2021 OpsMx, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.opsmx.spinnaker.gate.service;

import com.google.gson.Gson;
import com.opsmx.spinnaker.gate.cache.OesCacheManager;
import com.opsmx.spinnaker.gate.cache.platform.AuthorizationCaching;
import java.util.Map;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class AdminAuthService implements PlatformCachingService {

private Gson gson = new Gson();

@Autowired private OesCacheManager oesCacheManager;

@Autowired private AuthorizationCaching authorizationCaching;

@Override
public void cacheResponse(Object response, String userName) {

String responseBody = gson.toJson(response);
Map<String, Object> adminAuthResponse = gson.fromJson(responseBody, Map.class);
authorizationCaching.populateAdminAuthCache(userName, adminAuthResponse);
}

@Override
public boolean isCacheNotEmpty(String userName) {

CacheManager cacheManager = oesCacheManager.getCaffeineCacheManager();
CaffeineCache caffeineCache = (CaffeineCache) cacheManager.getCache("adminAuth");
Set<Object> keySet = caffeineCache.getNativeCache().asMap().keySet();
return keySet.stream()
.filter(key -> ((String) key).trim().contains(userName))
.findFirst()
.isPresent();
}

@Override
public Object fetchResponseFromCache(String userName) {
return authorizationCaching.getRecordFromAdminAuthCache(userName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,11 @@

package com.opsmx.spinnaker.gate.service;

import com.opsmx.spinnaker.gate.cache.Constants;

public interface DashboardCachingService {

void cacheResponse(Object response, String userName);

boolean isCacheNotEmpty(String userName);

Object fetchResponseFromCache(String userName);

static boolean isRegisteredCachingEndpoint(String path) {
boolean flag = Boolean.FALSE;
switch (path) {
case Constants.GET_ALL_DATASOURCES_ENDPOINT:
flag = Boolean.TRUE;
break;
}
return flag;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright 2021 OpsMx, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.opsmx.spinnaker.gate.service;

public interface PlatformCachingService {

void cacheResponse(Object response, String userName);

boolean isCacheNotEmpty(String userName);

Object fetchResponseFromCache(String userName);
}
Loading

0 comments on commit df57e9e

Please sign in to comment.