Comment se connecter sur une bucket S3 interne?

Bonjour,
ma question est posée dans un contexte de v4 - Version=4.0.P25 BuiltOn=2021-04-23 19:51 (revision 3addcb9b49a1c3b8d3cfe4fd9e06a69e2d4b9681) mais se pose aussi potentiellement sur la v5.

Comment puis-je initialiser un CloudStorageTool sur une bucket S3 interne (cf. illustration “use Amazon S3 compatible storage” ci-dessous) ?

à la lecture de la documentation disponible, je crois comprendre qu’il faudrait pouvoir surcharger (override) la propriété [AtrifactID].endpoint (aws-s3.endpoint?) avec l’URL de notre conteneur privé…

Est-ce possible avec l’intégration actuelle sachant que le bloc JSON de configuration proposé dans la doc n’explicite pas ce cas ?

{
    "provider": "aws-s3",
    "accessKeyId": "<your access key ID>",
    "secretAccessKey": "<your access key secret>",
    "bucket": "<your bucket name>"
}

image

En l’état de l’implémentation de la classe helper CloudStorageTool il n’est pas possible de spécifier un endpoint custom. On peut sans doute faire évoluer cette classe pour permettre cela.

Cela dit cette classe helper utilise les libs JClouds, vous pouvez toujours la zapper et taper directement au niveau des APIs JClouds si besoin.

Je vais tester l’ajout d’un endpoint custom et je te tiens au courant.

Est il possible pour toi de faire un tests sur une instance de test avec la 5.1 (beta / release candidate) = images 5-beta[-light].

Pour ce genre de modif qu’on ne peux pas tester, je préfère ne pas impacter immédiatement la release (5.0) et la maintenance (4.0). Si oui je builde les images 5.1 tout de suite

PS: attention je parle bien de déployer d’une instance temporaire, n’upgrade une instance en 4.0 car l’upgrade en 5.1 serait irréversible.

Bonjour David,
oui j’initialise une instance beta-light et je reviens vers toi.
Merci beaucoup.

Attends mon feu vert, le build est en cours

OK, j’ai déjà une instance bcsidev en version “5r” (actuellement en 5.0.46) dans le SIM → pour reconfigurer sur la beta, je lance juste un upgrade ?

Sur le SIM il faut changer la version de l’instance (de 5r à 5p) puis lancer un upgrade, je peux le faire car je ne pense pas que tu puisse le faire.

Attention un upgrade de 5.0 (5r) à 5.1 (5p) sera irréversible aussi ? Tu est bien sûr de vouloir upgrader cette instance bcsidev ?

NB: La 5.1 est actuellement en beta “release candidate” => elle va devenir la release d’ici peu

OK je te laisse la main alors:

Oui tu peux y aller…

C’est fait:

PS: Il faut ajouter `“endpoint”: “http(s)://…” aux settings S3

Merci beaucoup David.

J’ai mis en ligne un code pour tester et je vois dans les logs que l’url pour accéder au fichier test.hml est https://{bucket}.{endpoint}/test.html au lieu de https://{endpoint}/{bucket}/test.html.

La config ajustée est la suivante:

{
    "provider": "aws-s3",
    "accessKeyId": "{accesskeyid}",
    "secretAccessKey": "{secretaccesskey}",
    "bucket": "{bucket}",
    "endpoint": "https://{endpoint}"
}

Je pense que le nom du endpoint “privé” a pu t’induire en erreur: dans “bucket.s3storage.renault.fr”, bucket est un terme constant faisant partie de notre url interne. L’url d’accès complète est https://bucket.s3storage.renault.fr/{nom de la bucket}/{nom du fichier}

On ne construis pas l’URL c’est JCloud qui le fait, notre code est (en simplifié):

BlobStoreContext ctx = ContextBuilder.newBuilder("aws-s3")
  .credentials(config.optString("accessKeyId"), config.optString("secretAccessKey"))
  .endpoint(config.optString("endpoint"))
  .buildView(BlobStoreContext.class);

BlobStore store = m_context.getBlobStore();

(...)

// Cas du put:
Blob blob = store.blobBuilder(name)
  .payload(data)
  .contentType(mime)
  .contentLength(data.length)
  .build();
store.putBlob(config.optString("bucket"), blob, PutOptions.Builder.multipart());

Je ne sais pas trop ce qu’il faut que tu mette exactement dans endpoint (dans le cas du S3 Amazon on a pas à préciser le endpoint et ça marche directement).

Peut être faudrait il aussi mettre d’autres properties JClouds pour influer sur la manière dont l’URL est fabriquée. Visiblement il y a des différences selon les “clones” de S3 cf. Apache jclouds® :: S3: In Depth => genre peut être le jclouds.s3.virtual-host-buckets=false et peut être faut il gérer le provider s3 et pas seulement le aws-s3, etc. actuellement on ne gère pas ces properties additionnelles ni le provider s3

Peux tu tester directement avec les APIs JClouds jusqu’à trouver la config “en dur” qui marche dans ton cas, ensuite on verra comment intégrer ce cas à la classe helper CloudStorageTool qui consolide tous les cas qu’on a rencontrés jusqu’ici = AWS S3, Openstack Swift, Google Cloud storage et AzureBlobs

OK, je fais ça et je reviens vers toi avec des éléments plus étayés afin de voir ce qu’il sera éventuellement possible de gérer au niveau du socle (ou arriver à la conclusion que l’implémentation est trop spécifique et que ça reste au niveau applicatif). Le squelette de code fourni aide déjà beaucoup :wink:

OK, visiblement pour forcer d’éventuelles properties additionnelles il faut écrire:

Properties overrides = new Properties();
overrides.put("jclouds.s3.virtual-host-buckets", "false");
BlobStoreContext blobStoreContext = ContextBuilder.newBuilder("aws-s3")
(...)
  .overrides(overrides)
(...)
1 Like

Eureka!
Merci pour tes snipets de code qui m’ont bien aidé: il faut donc préciser un provider “s3” (et pas “aws-s3”), forcer le endpoint (via overrides de Properties) et le tour est joué.

Properties overrides = new Properties();
overrides.put("s3.endpoint", config.optString("endpoint"));

context = ContextBuilder.newBuilder("s3")
	.credentials(config.optString("accessKeyId"), config.optString("secretAccessKey"))
	.overrides(overrides)
	.buildView(BlobStoreContext.class);

store = context.getBlobStore();

Blob blob = store.blobBuilder(file).payload(content).contentType(mime).contentLength(content.length()).build();
store.putBlob(config.optString("bucket"), blob, PutOptions.Builder.multipart());

Le cas du get a l’air plus compliqué que le post car il est apparemment possible de récupérer les métadata du fichier d’une part et le contenu d’autre part… je verrai ça demain :slight_smile:

Du coup, est-ce envisageable de confier la gestion de l’override de properties au CloudStorageTool ?

J’ai poussé une mise à jour des versions 5.x 4.0 qui permet de mettre un provider “s3”` et de préciser des properties d’overrides de la manière suivante:

{
    "provider": "s3",
    "overrides": {
        "jclouds.s3.virtual-host-buckets": "false",
        ...
    }
    ...
}

La config permet de mettre "endpoint" au 1er niveau qui sera passé au builder via .endpoint() je ne sais pas si ça marche aussi dans ton cas…

ça marche impec!

[EDIT : suite à mauvaise manip (j’ai fermé le fil en cliquant sur “Solution” avant d’avoir posté ma réponse et le forum n’en veut plus… :hot_face: je poste donc ma réponse là où l’ai la main…]

Version=4.0.P25
BuiltOn=2021-05-04 23:26 (revision fc264504a796dafe39e855086c681bc359140df6)

Tout fonctionne parfaitement comme attendu
Merci beaucoup (comme d’habitude) pour ton support efficace et infaillible!

J’ai encapsulé l’instanciation du cst dans ma propre classe S3Tool car je vais y ajouter des méthodes permettant de générer des formulaires d’upload direct vers la bucket depuis le browser en générant un form intégrant une politique signée (cf. javascript - Amazon S3 direct file upload from client browser - private key disclosure - Stack Overflow).

Le formulaire étant servi par un objet externe habilité, nous pourrons intégrer son usage dans le modèle d’habilitation standard. Notre bucket S3 servira de zone d’échange avec plusieurs métiers et je ne souhaite pas exp(l)oser la plateforme si un bourrin dépose un fichier de taille non supportée ou avec un contenu pouvant être compromettant.

L’étape suivante sera d’explorer les possibilités de post traitements (fonctions lambda) pour déléguer à la couche storage S3 le fait de valider le fichier. Simplicité n’aura ainsi plus qu’à faire un get du fichier déposé et validé auparavant en y appliquant le traitement prévu (import ou autre).

Nous envisageons aussi de servir des url d’accès (get) pré-signées pour permettre aux utilisateurs habilités de récupérer des fichiers déposés (éventuellement par un traitement d’export Simplicité) sans traverser le backend.

Voici le dernier code testé qui fonctionne très bien :

public Boolean put(ExternalObject _this, JSONObject config, String file, String content, String mime) {
  CloudStorageTool cst = null;
  Boolean success = true;
  try {
    cst = new CloudStorageTool(config);
    cst.put(new JSONObject()
      .put("name", file)
      .put("mime", mime != null ? mime : HTTPTool.MIME_TYPE_DATA)
      .put("encoding", Globals.getPlatformEncoding())
      .put("content", content)
    );
  } catch (Exception e) {
    AppLog.error(_this.getClass(), "BCSIS3Toolbox.put", null, e, _this.getGrant());
    success = false;
  } finally {
    if (cst != null) cst.close();
  }
  return success;
}
public JSONObject get(ExternalObject _this, JSONObject config, String name, Boolean read) {
  CloudStorageTool cst = null;
  JSONObject file = null;
  try {
    cst = new CloudStorageTool(config);
    file = cst.get(name,read);
  } catch (Exception e) {
    AppLog.error(_this.getClass(), "BCSIS3Toolbox.get", null, e, _this.getGrant());
  } finally {
    if (cst != null) cst.close();
  }
  return file;
}

Tu as pu tester avec la nouvelle version de CloudStorageTool car ça gère désormais le provider “s3” et le paramètre endpoint

This topic was automatically closed 60 minutes after the last reply. New replies are no longer allowed.