Skip to content

Commit

Permalink
Merge branch 'master' into 507-image-name-strategy-is-not-working-as-…
Browse files Browse the repository at this point in the history
…expected
  • Loading branch information
munishchouhan authored May 29, 2024
2 parents 1d5eac1 + bd5b55c commit 20c9c84
Show file tree
Hide file tree
Showing 38 changed files with 1,535 additions and 129 deletions.
3 changes: 2 additions & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
1.7.8
1.7.9

7 changes: 7 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
# Wave changelog
1.7.9 - 29 May 2024
- Improve JWT refresh handling (#512) [751edb03]
- Mark release as draft when ending with -Ax -Bx -RCx [ci skip] [66ba7ea7]
- Removed unused imports (#510) [182e3f0d]
- Fix Use atomic strategy for Cacheable ops [923ae67c]
- Fix failing build [8adb52ab]

1.7.8 - 15 May 2024
- Prevent container freeze without custom repo (#499) [ec5932df]
- Improve pairing record check (#500) [7ce86dc9]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ interface TokenConfig {
@Nullable
Duration getDuration()

@Deprecated
@Bindable(defaultValue = "10000")
@Nullable
int getMaxSize()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,15 @@ import io.seqera.wave.service.token.TokenData
import io.seqera.wave.service.validation.ValidationService
import io.seqera.wave.tower.PlatformId
import io.seqera.wave.tower.User
import io.seqera.wave.tower.auth.JwtAuth
import io.seqera.wave.tower.auth.JwtAuthStore
import io.seqera.wave.util.DataTimeUtils
import io.seqera.wave.util.LongRndKey
import jakarta.inject.Inject
import static io.micronaut.http.HttpHeaders.WWW_AUTHENTICATE
import static io.seqera.wave.service.builder.BuildFormat.DOCKER
import static io.seqera.wave.service.builder.BuildFormat.SINGULARITY
import static io.seqera.wave.service.pairing.PairingService.TOWER_SERVICE
import static io.seqera.wave.util.ContainerHelper.checkContainerSpec
import static io.seqera.wave.util.ContainerHelper.condaFileFromRequest
import static io.seqera.wave.util.ContainerHelper.containerFileFromPackages
Expand All @@ -84,8 +86,6 @@ import static io.seqera.wave.util.ContainerHelper.patchPlatformEndpoint
import static io.seqera.wave.util.ContainerHelper.spackFileFromRequest
import static io.seqera.wave.util.SpackHelper.prependBuilderTemplate
import static java.util.concurrent.CompletableFuture.completedFuture
import static io.seqera.wave.service.pairing.PairingService.TOWER_SERVICE

/**
* Implement a controller to receive container token requests
*
Expand Down Expand Up @@ -187,11 +187,15 @@ class ContainerController {
if( !registration )
throw new BadRequestException("Missing pairing record for Tower endpoint '$req.towerEndpoint'")

// store the tower JWT tokens
jwtAuthStore.putJwtAuth(req.towerEndpoint, req.towerRefreshToken, req.towerAccessToken)
// store the jwt record only the very first time it has been
// to avoid overridden a newer refresh token that may have
final auth = JwtAuth.of(req)
if( auth.refresh )
jwtAuthStore.storeIfAbsent(auth)

// find out the user associated with the specified tower access token
return userService
.getUserByAccessTokenAsync(registration.endpoint, req.towerAccessToken)
.getUserByAccessTokenAsync(registration.endpoint, auth)
.thenApply((User user) -> handleRequest(httpRequest, req, PlatformId.of(user,req), v2))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import io.seqera.wave.service.inspect.ContainerInspectService
import io.seqera.wave.service.pairing.PairingService
import io.seqera.wave.tower.PlatformId
import io.seqera.wave.tower.User
import io.seqera.wave.tower.auth.JwtAuth
import jakarta.inject.Inject
import static io.seqera.wave.util.ContainerHelper.patchPlatformEndpoint
/**
Expand Down Expand Up @@ -92,7 +93,7 @@ class InspectController {

// find out the user associated with the specified tower access token
return userService
.getUserByAccessTokenAsync(registration.endpoint, req.towerAccessToken)
.getUserByAccessTokenAsync(registration.endpoint, JwtAuth.of(req))
.thenApply((User user) -> makeResponse(req, PlatformId.of(user,req)) )

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Wave, containers provisioning service
* Copyright (c) 2023-2024, Seqera Labs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package io.seqera.wave.memstore.range


import groovy.transform.CompileStatic
import io.seqera.wave.memstore.range.impl.RangeProvider
/**
* Abstract implementation for range set similar to Redis `zrange`
*
* @author Paolo Di Tommaso <[email protected]>
*/
@CompileStatic
abstract class AbstractRangeStore implements RangeStore {

private RangeProvider delegate

protected abstract String getKey()

AbstractRangeStore(RangeProvider provider) {
this.delegate = provider
}

@Override
void add(String name, double score) {
delegate.add(getKey(), name, score)
}

@Override
List<String> getRange(double min, double max, int count) {
return getRange(min, max, count, true)
}

List<String> getRange(double min, double max, int count, boolean remove) {
return delegate.getRange(getKey(), min, max, count, remove) ?: List.<String>of()
}

}
30 changes: 30 additions & 0 deletions src/main/groovy/io/seqera/wave/memstore/range/RangeStore.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Wave, containers provisioning service
* Copyright (c) 2023-2024, Seqera Labs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package io.seqera.wave.memstore.range
/**
* Define the contract for a storage range set similar to Redis `zrange`
*
* @author Paolo Di Tommaso <[email protected]>
*/
interface RangeStore {

void add(String member, double score)

List<String> getRange(double min, double max, int count)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Wave, containers provisioning service
* Copyright (c) 2023-2024, Seqera Labs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package io.seqera.wave.memstore.range.impl


import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import io.micronaut.context.annotation.Requires
import jakarta.inject.Singleton
/**
* Local based implementation for a range set
*
* @author Paolo Di Tommaso <[email protected]>
*/
@Slf4j
@Requires(missingProperty = 'redis.uri')
@Singleton
@CompileStatic
class LocalRangeProvider implements RangeProvider {

private Map<String,Map<String,Double>> store = new HashMap<>()

@Override
void add(String key, String element, double score) {
final map = store.getOrDefault(key, [:])
map.put(element, score)
store.put(key, map)
log.trace "* add range - store: $store"
}

@Override
List<String> getRange(String key, double min, double max, int count, boolean remove) {
final map = store.getOrDefault(key, [:])
final result = new ArrayList<String>()
for( Map.Entry<String,Double> entry : map.entrySet().sort(it->it.value) ) {
if( result.size()>=count )
break
if( entry.value>=min && entry.value<=max ) {
result.add(entry.key)
if( remove )
map.remove(entry.key)
}
}
log.trace "* get range result=$result - store: $store"
return result
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Wave, containers provisioning service
* Copyright (c) 2023-2024, Seqera Labs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package io.seqera.wave.memstore.range.impl
/**
* Contract for range store provider
*
* @author Paolo Di Tommaso <[email protected]>
*/
interface RangeProvider {

void add(String key, String member, double score)

List<String> getRange(String key, double min, double max, int count, boolean remove)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Wave, containers provisioning service
* Copyright (c) 2023-2024, Seqera Labs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package io.seqera.wave.memstore.range.impl


import groovy.transform.CompileStatic
import io.micronaut.context.annotation.Requires
import jakarta.inject.Inject
import jakarta.inject.Singleton
import redis.clients.jedis.Jedis
import redis.clients.jedis.JedisPool
import redis.clients.jedis.resps.Tuple

/**
* Redis base implementation for range set
*
* @author Paolo Di Tommaso <[email protected]>
*/
@Requires(property = 'redis.uri')
@Singleton
@CompileStatic
class RedisRangeProvider implements RangeProvider {

@Inject
private JedisPool pool

@Override
void add(String key, String element, double score) {
try(Jedis conn = pool.getResource()) {
conn.zadd(key, score, element)
}
}

@Override
List<String> getRange(String key, double min, double max, int count, boolean remove) {
try(Jedis conn = pool.getResource()) {
List<Tuple> found = conn.zrangeByScoreWithScores(key, min, max, 0, count)
final result = new ArrayList<String>(found.size())
for( Tuple it : found ) {
result.add(it.element)
if( remove )
conn.zrem(key, it.element)
}
return result
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@

package io.seqera.wave.service


import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import io.seqera.tower.crypto.AsymmetricCipher
import io.seqera.tower.crypto.EncryptedPacket
import io.seqera.wave.service.pairing.PairingService
import io.seqera.wave.tower.PlatformId
import io.seqera.wave.tower.auth.JwtAuth
import io.seqera.wave.tower.client.TowerClient
import jakarta.inject.Inject
import jakarta.inject.Singleton
Expand Down Expand Up @@ -58,7 +58,7 @@ class CredentialServiceImpl implements CredentialsService {
if (pairing.isExpired())
log.debug("Exchange key registered for service ${PairingService.TOWER_SERVICE} at endpoint: ${identity.towerEndpoint} used after expiration, should be renewed soon")

final all = towerClient.listCredentials(identity.towerEndpoint, identity.accessToken, identity.workspaceId).get().credentials
final all = towerClient.listCredentials(identity.towerEndpoint, JwtAuth.of(identity), identity.workspaceId).get().credentials

if (!all) {
log.debug "No credentials found for userId=$identity.userId; workspaceId=$identity.workspaceId; endpoint=$identity.towerEndpoint"
Expand Down Expand Up @@ -87,7 +87,7 @@ class CredentialServiceImpl implements CredentialsService {
// log for debugging purposes
log.debug "Credentials matching criteria registryName=$registryName; userId=$identity.userId; workspaceId=$identity.workspaceId; endpoint=$identity.towerEndpoint => $creds"
// now fetch the encrypted key
final encryptedCredentials = towerClient.fetchEncryptedCredentials(identity.towerEndpoint, identity.accessToken, creds.id, pairing.pairingId, identity.workspaceId).get()
final encryptedCredentials = towerClient.fetchEncryptedCredentials(identity.towerEndpoint, JwtAuth.of(identity), creds.id, pairing.pairingId, identity.workspaceId).get()
final privateKey = pairing.privateKey
final credentials = decryptCredentials(privateKey, encryptedCredentials.keys)
return parsePayload(credentials)
Expand Down
5 changes: 3 additions & 2 deletions src/main/groovy/io/seqera/wave/service/UserService.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package io.seqera.wave.service
import java.util.concurrent.CompletableFuture

import io.seqera.wave.tower.User
import io.seqera.wave.tower.auth.JwtAuth

/**
* Declare a service to access a Tower user
Expand All @@ -29,8 +30,8 @@ import io.seqera.wave.tower.User
*/
interface UserService {

User getUserByAccessToken(String endpoint, String accessToken)
User getUserByAccessToken(String endpoint, JwtAuth auth)

CompletableFuture<User> getUserByAccessTokenAsync(String endpoint, String accessToken)
CompletableFuture<User> getUserByAccessTokenAsync(String endpoint, JwtAuth auth)

}
Loading

0 comments on commit 20c9c84

Please sign in to comment.