All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.spinnaker.front50.model.OracleStorageService Maven / Gradle / Ivy

There is a newer version: 2.37.0
Show newest version
/*
 * Copyright (c) 2017, 2018 Oracle Corporation and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the Apache License Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * If a copy of the Apache License Version 2.0 was not distributed with this file,
 * You can obtain one at https://www.apache.org/licenses/LICENSE-2.0.html
 */
package com.netflix.spinnaker.front50.model;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.google.common.base.Supplier;
import com.netflix.spinnaker.front50.api.model.Timestamped;
import com.netflix.spinnaker.front50.api.model.pipeline.Pipeline;
import com.netflix.spinnaker.front50.config.OracleProperties;
import com.netflix.spinnaker.front50.jackson.mixins.PipelineMixins;
import com.netflix.spinnaker.front50.jackson.mixins.TimestampedMixins;
import com.netflix.spinnaker.kork.web.exceptions.NotFoundException;
import com.oracle.bmc.auth.AuthenticationDetailsProvider;
import com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider;
import com.oracle.bmc.auth.SimplePrivateKeySupplier;
import com.oracle.bmc.http.internal.ExplicitlySetFilter;
import com.oracle.bmc.http.signing.DefaultRequestSigner;
import com.oracle.bmc.http.signing.RequestSigner;
import com.oracle.bmc.objectstorage.model.CreateBucketDetails;
import com.oracle.bmc.objectstorage.model.ListObjects;
import com.oracle.bmc.objectstorage.model.ObjectSummary;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientRequest;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.client.filter.ClientFilter;
import com.sun.jersey.client.urlconnection.URLConnectionClientHandler;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;

public class OracleStorageService implements StorageService {

  private final Client client;

  private final String endpoint = "https://objectstorage.{arg0}.oraclecloud.com";
  private final String region;
  private final String namespace;
  private final String compartmentId;
  private final String bucketName;

  private final ObjectMapper objectMapper =
      new ObjectMapper()
          .addMixIn(Timestamped.class, TimestampedMixins.class)
          .addMixIn(Pipeline.class, PipelineMixins.class);

  private class RequestSigningFilter extends ClientFilter {
    private final RequestSigner signer;

    public RequestSigningFilter(RequestSigner requestSigner) {
      this.signer = requestSigner;
    }

    @Override
    public ClientResponse handle(ClientRequest cr) throws ClientHandlerException {
      Map> stringHeaders = new HashMap<>();
      for (String key : cr.getHeaders().keySet()) {
        List vals = new ArrayList<>();
        for (Object val : cr.getHeaders().get(key)) {
          vals.add((String) val);
        }
        stringHeaders.put(key, vals);
      }

      Map signedHeaders =
          signer.signRequest(cr.getURI(), cr.getMethod(), stringHeaders, cr.getEntity());
      for (String key : signedHeaders.keySet()) {
        cr.getHeaders().putSingle(key, signedHeaders.get(key));
      }

      return getNext().handle(cr);
    }
  }

  public OracleStorageService(OracleProperties oracleProperties) throws IOException {
    this.region = oracleProperties.getRegion();
    this.bucketName = oracleProperties.getBucketName();
    this.namespace = oracleProperties.getNamespace();
    this.compartmentId = oracleProperties.getCompartmentId();

    Supplier privateKeySupplier =
        new SimplePrivateKeySupplier(oracleProperties.getSshPrivateKeyFilePath());
    AuthenticationDetailsProvider provider =
        SimpleAuthenticationDetailsProvider.builder()
            .userId(oracleProperties.getUserId())
            .fingerprint(oracleProperties.getFingerprint())
            .privateKeySupplier(privateKeySupplier)
            .passPhrase(oracleProperties.getPrivateKeyPassphrase())
            .tenantId(oracleProperties.getTenancyId())
            .build();

    RequestSigner requestSigner = DefaultRequestSigner.createRequestSigner(provider);

    ClientConfig clientConfig = new DefaultClientConfig();
    client = new Client(new URLConnectionClientHandler(), clientConfig);
    client.addFilter(new OracleStorageService.RequestSigningFilter(requestSigner));

    FilterProvider filters =
        new SimpleFilterProvider()
            .addFilter(ExplicitlySetFilter.NAME, ExplicitlySetFilter.INSTANCE);
    objectMapper.setFilterProvider(filters);
  }

  public void ensureBucketExists() {
    WebResource wr =
        client.resource(
            UriBuilder.fromPath(endpoint + "/n/{arg1}/b/{arg2}")
                .build(region, namespace, bucketName));
    wr.accept(MediaType.APPLICATION_JSON_TYPE);
    ClientResponse rsp = wr.head();
    if (rsp.getStatus() == 404) {
      CreateBucketDetails createBucketDetails =
          CreateBucketDetails.builder().name(bucketName).compartmentId(compartmentId).build();
      wr = client.resource(UriBuilder.fromPath(endpoint + "/n/{arg1}/b/").build(region, namespace));
      wr.accept(MediaType.APPLICATION_JSON_TYPE);
      try {
        byte[] bytes = objectMapper.writeValueAsBytes(createBucketDetails);
        wr.post(new String(bytes, StandardCharsets.UTF_8));
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    } else if (rsp.getStatus() != 200) {
      throw new RuntimeException(rsp.toString());
    }
  }

  @Override
  public boolean supportsVersioning() {
    return false;
  }

  @Override
  public  T loadObject(ObjectType objectType, String objectKey)
      throws NotFoundException {
    WebResource wr =
        client.resource(
            UriBuilder.fromPath(endpoint + "/n/{arg1}/b/{arg2}/o/{arg3}")
                .build(
                    region,
                    namespace,
                    bucketName,
                    buildOSSKey(objectType.group, objectKey, objectType.defaultMetadataFilename)));
    wr.accept(MediaType.APPLICATION_JSON_TYPE);
    try {
      T obj = (T) wr.get(objectType.clazz);
      return obj;
    } catch (UniformInterfaceException e) {
      if (e.getResponse().getStatus() == 404) {
        throw new NotFoundException("Object not found (key: " + objectKey + ")");
      }
      throw e;
    }
  }

  @Override
  public void deleteObject(ObjectType objectType, String objectKey) {
    WebResource wr =
        client.resource(
            UriBuilder.fromPath(endpoint + "/n/{arg1}/b/{arg2}/o/{arg3}")
                .build(
                    region,
                    namespace,
                    bucketName,
                    buildOSSKey(objectType.group, objectKey, objectType.defaultMetadataFilename)));
    wr.accept(MediaType.APPLICATION_JSON_TYPE);
    try {
      wr.delete();
    } catch (UniformInterfaceException e) {
      if (e.getResponse().getStatus() == 404) {
        return;
      }
      throw e;
    }

    updateLastModified(objectType);
  }

  @Override
  public  void storeObject(ObjectType objectType, String objectKey, T item) {
    WebResource wr =
        client.resource(
            UriBuilder.fromPath(endpoint + "/n/{arg1}/b/{arg2}/o/{arg3}")
                .build(
                    region,
                    namespace,
                    bucketName,
                    buildOSSKey(objectType.group, objectKey, objectType.defaultMetadataFilename)));
    wr.accept(MediaType.APPLICATION_JSON_TYPE);
    try {
      byte[] bytes = objectMapper.writeValueAsBytes(item);
      wr.put(new String(bytes, StandardCharsets.UTF_8));
    } catch (IOException e) {
      throw new RuntimeException(e);
    }

    updateLastModified(objectType);
  }

  @Override
  public Map listObjectKeys(ObjectType objectType) {
    WebResource wr =
        client.resource(
            UriBuilder.fromPath(endpoint + "/n/{arg1}/b/{arg2}/o")
                .queryParam("prefix", objectType.group)
                .queryParam("fields", "name,timeModified")
                .build(region, namespace, bucketName));
    wr.accept(MediaType.APPLICATION_JSON_TYPE);
    ListObjects listObjects = wr.get(ListObjects.class);
    Map results = new HashMap<>();
    for (ObjectSummary summary : listObjects.getObjects()) {
      if (summary.getName().endsWith(objectType.defaultMetadataFilename)) {
        results.put(
            buildObjectKey(objectType, summary.getName()), summary.getTimeModified().getTime());
      }
    }
    return results;
  }

  @Override
  public  Collection listObjectVersions(
      ObjectType objectType, String objectKey, int maxResults) throws NotFoundException {
    throw new RuntimeException("Oracle Object Store does not support versioning");
  }

  @Override
  public long getLastModified(ObjectType objectType) {
    WebResource wr =
        client.resource(
            UriBuilder.fromPath(endpoint + "/n/{arg1}/b/{arg2}/o/{arg3}")
                .build(region, namespace, bucketName, objectType.group + "/last-modified.json"));
    wr.accept(MediaType.APPLICATION_JSON_TYPE);
    try {
      LastModified lastModified = wr.get(LastModified.class);
      return lastModified.getLastModified();
    } catch (Exception e) {
      return 0L;
    }
  }

  private void updateLastModified(ObjectType objectType) {
    WebResource wr =
        client.resource(
            UriBuilder.fromPath(endpoint + "/n/{arg1}/b/{arg2}/o/{arg3}")
                .build(region, namespace, bucketName, objectType.group + "/last-modified.json"));
    wr.accept(MediaType.APPLICATION_JSON_TYPE);
    try {
      byte[] bytes = objectMapper.writeValueAsBytes(new LastModified());
      wr.put(new String(bytes, StandardCharsets.UTF_8));
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  private String buildOSSKey(String group, String objectKey, String metadataFilename) {
    if (objectKey.endsWith(metadataFilename)) {
      return objectKey;
    }

    return (group + "/" + objectKey.toLowerCase() + "/" + metadataFilename).replace("//", "/");
  }

  private String buildObjectKey(ObjectType objectType, String ossKey) {
    return ossKey
        .replaceAll(objectType.group + "/", "")
        .replaceAll("/" + objectType.defaultMetadataFilename, "");
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy