Skip to content

Commit

Permalink
Server side implementation of the resolveJobSpecification rpc API. Fi…
Browse files Browse the repository at this point in the history
…rst versions of supporting v4 proto definitions and DTO classes
  • Loading branch information
tgianos committed Mar 2, 2018
1 parent 964fe3f commit 0230c09
Show file tree
Hide file tree
Showing 33 changed files with 4,235 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
*
* Copyright 2018 Netflix, 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.netflix.genie.agent.execution.services;

import com.netflix.genie.common.dto.v4.JobRequest;
import com.netflix.genie.common.dto.v4.JobSpecification;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;

/**
* Agent side job specification service for resolving and retrieving job specifications from the server.
*
* @author tgianos
* @since 4.0.0
*/
@Validated
public interface AgentJobSpecificationService {

/**
* Given the parameters supplied by the job request attempt to resolve a job specification on the server.
*
* @param jobRequest The job request
* @return The job specification
*/
JobSpecification resolveJobSpecification(@Valid final JobRequest jobRequest);

/**
* Given a job id retrieve the job specification from the server.
*
* @param id The id of the job to get the specification for
* @return The job specification
*/
JobSpecification getJobSpecification(final String id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
*
* Copyright 2018 Netflix, 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.netflix.genie.agent.execution.services.impl.grpc;

import com.netflix.genie.agent.execution.services.AgentJobSpecificationService;
import com.netflix.genie.common.dto.v4.JobRequest;
import com.netflix.genie.common.dto.v4.JobSpecification;
import com.netflix.genie.proto.JobSpecificationServiceGrpc;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.validation.Valid;

/**
* Implementation of the job specification service.
*
* @author tgianos
* @since 4.0.0
*/
@Lazy
@Service
@Slf4j
public class GRpcAgentJobSpecificationServiceImpl implements AgentJobSpecificationService {

private final JobSpecificationServiceGrpc.JobSpecificationServiceFutureStub client;

/**
* Constructor.
*
* @param client The gRPC client to use to call the server. Asynchronous version to allow timeouts.
*/
public GRpcAgentJobSpecificationServiceImpl(
final JobSpecificationServiceGrpc.JobSpecificationServiceFutureStub client
) {
this.client = client;
}

/**
* {@inheritDoc}
*/
@Override
public JobSpecification resolveJobSpecification(@Valid final JobRequest jobRequest) {
return null;
}

/**
* {@inheritDoc}
*/
@Override
public JobSpecification getJobSpecification(final String id) {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
*
* Copyright 2018 Netflix, 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.
*
*/

/**
* gRPC based implementations of the agent execution services.
*
* @author tgianos
* @since 4.0.0
*/
@ParametersAreNonnullByDefault
package com.netflix.genie.agent.execution.services.impl.grpc;

import javax.annotation.ParametersAreNonnullByDefault;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
*
* Copyright 2018 Netflix, 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.
*
*/

/**
* Implementations of execution services for the Agent.
*
* @author tgianos
* @since 4.0.0
*/
@ParametersAreNonnullByDefault
package com.netflix.genie.agent.execution.services.impl;

import javax.annotation.ParametersAreNonnullByDefault;
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import com.netflix.genie.agent.cli.ArgumentDelegates;
import com.netflix.genie.proto.AgentRegistrationServiceGrpc;
import com.netflix.genie.proto.JobSpecificationServiceGrpc;
import com.netflix.genie.proto.PingServiceGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
Expand Down Expand Up @@ -64,4 +65,12 @@ AgentRegistrationServiceGrpc.AgentRegistrationServiceFutureStub agentRegistratio
) {
return AgentRegistrationServiceGrpc.newFutureStub(channel);
}

@Bean
@Scope("prototype")
JobSpecificationServiceGrpc.JobSpecificationServiceFutureStub jobSpecificationClient(
final ManagedChannel channel
) {
return JobSpecificationServiceGrpc.newFutureStub(channel);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/*
*
* Copyright 2018 Netflix, 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.netflix.genie.common.dto.v4;

import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.ImmutableSet;
import com.netflix.genie.common.exceptions.GeniePreconditionException;
import com.netflix.genie.common.util.GenieObjectMapper;
import lombok.Data;

import javax.annotation.Nullable;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.io.IOException;
import java.util.Optional;
import java.util.Set;

/**
* Metadata fields common to all Genie resources (Jobs, clusters, etc).
*
* @author tgianos
* @since 4.0.0
*/
@Data
public abstract class CommonUserMetadata {
@NotEmpty(message = "A name is required and must be at most 255 characters")
@Size(max = 255, message = "The name can be no longer than 255 characters")
private final String name;
@NotEmpty(message = "A user is required and must be at most 255 characters")
@Size(max = 255, message = "The user can be no longer than 255 characters")
private final String user;
@Size(max = 255, message = "The version can be no longer than 255 characters")
private final String version;
@Size(max = 1000, message = "The description can be no longer than 1000 characters")
private final String description;
private final JsonNode metadata;
private final ImmutableSet<@Size(max = 255, message = "A tag can't be longer than 255 characters") String> tags;

@SuppressWarnings("unchecked")
CommonUserMetadata(final Builder builder) {
this.name = builder.bName;
this.user = builder.bUser;
this.version = builder.bVersion;
this.description = builder.bDescription;
this.metadata = builder.bMetadata;
this.tags = builder.bTags == null ? ImmutableSet.of() : ImmutableSet.copyOf(builder.bTags);
}

/**
* Get the version.
*
* @return The version as an {@link Optional}
*/
public Optional<String> getVersion() {
return Optional.ofNullable(this.version);
}

/**
* Get the description.
*
* @return The description as an {@link Optional}
*/
public Optional<String> getDescription() {
return Optional.ofNullable(this.description);
}

/**
* Get the metadata of this resource as a JSON Node.
*
* @return {@link Optional} of the metadata if it exists
*/
public Optional<JsonNode> getMetadata() {
return Optional.ofNullable(this.metadata);
}

/**
* Get the tags associated with this resource. Will be returned as an immutable set and any attempt to modify will
* result in an exception being thrown.
*
* @return The tags
*/
public Set<String> getTags() {
return this.tags;
}

/**
* Builder for common fields.
*
* @param <T> Type of builder that extends this
* @author tgianos
* @since 4.0.0
*/
// NOTE: These abstract class builders are marked public not protected due to a JDK bug from 1999 which caused
// issues with Clojure clients which use reflection to make the Java API calls.
// http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4283544
// Setting them to public seems to have solved the issue at the expense of "proper" code design
@SuppressWarnings("unchecked")
public abstract static class Builder<T extends Builder> {

private final String bName;
private final String bUser;
private String bVersion;
private String bDescription;
private JsonNode bMetadata;
private ImmutableSet<String> bTags;

protected Builder(final String name, final String user) {
this.bName = name;
this.bUser = user;
}

/**
* Set the version of the resource.
*
* @param version The version to set
* @return The builder
*/
public T withVersion(@Nullable final String version) {
this.bVersion = version;
return (T) this;
}

/**
* Set the description for the resource.
*
* @param description The description to use
* @return The builder
*/
public T withDescription(@Nullable final String description) {
this.bDescription = description;
return (T) this;
}

/**
* Set the tags to use for the resource.
*
* @param tags The tags to use
* @return The builder
*/
public T withTags(@Nullable final Set<String> tags) {
this.bTags = tags == null ? ImmutableSet.of() : ImmutableSet.copyOf(tags);
return (T) this;
}

/**
* With the metadata to set for the job as a JsonNode.
*
* @param metadata The metadata to set
* @return The builder
*/
@JsonSetter
public T withMetadata(@Nullable final JsonNode metadata) {
this.bMetadata = metadata;
return (T) this;
}

/**
* With the adhoc metadata to set for the resource as a string of valid JSON.
*
* @param metadata The metadata to set. Must be valid JSON
* @return The builder
* @throws GeniePreconditionException On invalid JSON
*/
public T withMetadata(@Nullable final String metadata) throws GeniePreconditionException {
if (metadata == null) {
this.bMetadata = null;
} else {
try {
this.bMetadata = GenieObjectMapper.getMapper().readTree(metadata);
} catch (final IOException ioe) {
throw new GeniePreconditionException("Invalid metadata JSON string passed in " + metadata, ioe);
}
}
return (T) this;
}
}
}
Loading

0 comments on commit 0230c09

Please sign in to comment.