@Override
  public NodeAndInitialCredentials<Instance> createNodeWithGroupEncodedIntoName(
      String group, String name, Template template) {
    GoogleComputeEngineTemplateOptions options =
        GoogleComputeEngineTemplateOptions.class.cast(template.getOptions());

    checkNotNull(options.getNetworks(), "template options must specify a network");
    checkNotNull(template.getHardware().getUri(), "hardware must have a URI");
    checkNotNull(template.getImage().getUri(), "image URI is null");

    List<AttachDisk> disks = Lists.newArrayList();
    disks.add(AttachDisk.newBootDisk(template.getImage().getUri()));

    Iterator<String> networks = options.getNetworks().iterator();

    URI network = URI.create(networks.next());
    assert !networks.hasNext() : "Error: Options should specify only one network";

    // Add tags from template
    ArrayList<String> tags = new ArrayList<String>(options.getTags());

    // Add tags for firewalls
    FirewallTagNamingConvention naming = firewallTagNamingConvention.get(group);
    List<String> ports = simplifyPorts(options.getInboundPorts());
    if (ports != null) {
      tags.add(naming.name(ports));
    }

    NewInstance newInstance =
        new NewInstance.Builder(
                name,
                template.getHardware().getUri(), // machineType
                network,
                disks)
            .description(group)
            .tags(Tags.create(null, ImmutableList.copyOf(tags)))
            .serviceAccounts(options.serviceAccounts())
            .build();

    // Add metadata from template and for ssh key and image id
    newInstance.metadata().putAll(options.getUserMetadata());

    LoginCredentials credentials = resolveNodeCredentials(template);
    if (options.getPublicKey() != null) {
      newInstance
          .metadata()
          .put(
              "sshKeys",
              format(
                  "%s:%s %s@localhost",
                  credentials.getUser(), options.getPublicKey(), credentials.getUser()));
    }

    String zone = template.getLocation().getId();
    InstanceApi instanceApi = api.instancesInZone(zone);
    Operation create = instanceApi.create(newInstance);

    // We need to see the created instance so that we can access the newly created disk.
    AtomicReference<Instance> instance =
        Atomics.newReference(
            Instance.create( //
                "0000000000000000000", // id can't be null, but isn't available until provisioning
                                       // is done.
                null, // creationTimestamp
                create.targetLink(), // selfLink
                newInstance.name(), // name
                newInstance.description(), // description
                newInstance.tags(), // tags
                newInstance.machineType(), // machineType
                Instance.Status.PROVISIONING, // status
                null, // statusMessage
                create.zone(), // zone
                null, // canIpForward
                null, // networkInterfaces
                null, // disks
                newInstance.metadata(), // metadata
                newInstance.serviceAccounts(), // serviceAccounts
                Scheduling.create(OnHostMaintenance.MIGRATE, true) // scheduling
                ));
    checkState(instanceVisible.apply(instance), "instance %s is not api visible!", instance.get());

    // Add lookup for InstanceToNodeMetadata
    diskToSourceImage.put(instance.get().disks().get(0).source(), template.getImage().getUri());

    return new NodeAndInitialCredentials<Instance>(
        instance.get(), instance.get().selfLink().toString(), credentials);
  }