<commit_before>//
// Copyright (C) 2013 The Docker Cloud authors
//
// 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 dockercloud

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"os/user"
	"path"
	"strings"
	"time"

	"code.google.com/p/goauth2/oauth"
	compute "code.google.com/p/google-api-go-client/compute/v1"
)

var (
	instanceType = flag.String("instancetype",
		"/zones/us-central1-a/machineTypes/n1-standard-1",
		"The reference to the instance type to create.")
	image = flag.String("image",
		"https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/backports-debian-7-wheezy-v20131127",
		"The GCE image to boot from.")
	diskName   = flag.String("diskname", "docker-root", "Name of the instance root disk")
	diskSizeGb = flag.Int64("disksize", 100, "Size of the root disk in GB")
)

const startup = `#!/bin/bash
sysctl -w net.ipv4.ip_forward=1
wget -qO- https://get.docker.io/ | sh
until test -f /var/run/docker.pid; do sleep 1 && echo waiting; done
grep mtu /etc/default/docker || (echo 'DOCKER_OPTS="-H :8000 -mtu 1460"' >> /etc/default/docker)
service docker restart
until echo 'GET /' >/dev/tcp/localhost/8000; do sleep 1 && echo waiting; done
`

// A Google Compute Engine implementation of the Cloud interface
type GCECloud struct {
	service   *compute.Service
	projectId string
}

type gceConfig struct {
	clientId     string
	clientSecret string
	scope        string
	refreshToken string
	projectId    string
}

func gceConfAbsPath() (string, error) {
	usr, err := user.Current()
	if err != nil {
		return "", err
	}
	return path.Join(usr.HomeDir, "docker-cloud.json"), nil
}

func (conf *gceConfig) Read() (err error) {
	confPath, err := gceConfAbsPath()
	if err != nil {
		return
	}
	var data []byte
	if data, err = ioutil.ReadFile(confPath); err != nil {
		return
	}
	err = json.Unmarshal(data, conf)
	return
}

func (conf *gceConfig) Write() error {
	confPath, err := gceConfAbsPath()
	if err != nil {
		return err
	}
	var data []byte
	if data, err = json.Marshal(conf); err != nil {
		return err
	}
	return ioutil.WriteFile(confPath, data, 0644)
}

// Create a GCE Cloud instance.  'clientId', 'clientSecret' and 'scope' are used to ask for a client
// credential.  'code' is optional and is only used if a cached credential can not be found.
// 'projectId' is the Google Cloud project name.
func NewCloudGCE(projectId string) (cloud *GCECloud, err error) {
	// TODO(jbd): Reuse gcloud credentials if available.
	conf := &gceConfig{}
	if err = conf.Read(); err != nil {
		return nil, errors.New("Did you authorize the client? Run `docker-cloud auth`.")
	}
	if projectId == "" {
		projectId = conf.projectId
	}

	oAuth2Conf := newGCEOAuth2Config(conf.clientId, conf.clientSecret, conf.scope)
	transport := &oauth.Transport{Config: oAuth2Conf, Transport: http.DefaultTransport}
	// Make the actual request using the cached token to authenticate.
	// ("Here's the token, let me in!")
	transport.Token.RefreshToken = conf.refreshToken

	// TODO(jbd): Does it need to refresh the token, transport will auto do it if
	// it fails with an auth error on the first request.
	err = transport.Refresh()
	if err != nil {
		return
	}
	svc, err := compute.New(transport.Client())
	if err != nil {
		return
	}
	return &GCECloud{
		service:   svc,
		projectId: projectId,
	}, nil
}

// Implementation of the Cloud interface<commit_msg>gce: fallback on reading credentials from gcloud<commit_after>//
// Copyright (C) 2013 The Docker Cloud authors
//
// 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 dockercloud

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"os/user"
	"path"
	"strings"
	"time"

	"code.google.com/p/goauth2/oauth"
	compute "code.google.com/p/google-api-go-client/compute/v1"
)

var (
	instanceType = flag.String("instancetype",
		"/zones/us-central1-a/machineTypes/n1-standard-1",
		"The reference to the instance type to create.")
	image = flag.String("image",
		"https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/backports-debian-7-wheezy-v20131127",
		"The GCE image to boot from.")
	diskName   = flag.String("diskname", "docker-root", "Name of the instance root disk")
	diskSizeGb = flag.Int64("disksize", 100, "Size of the root disk in GB")
)

const startup = `#!/bin/bash
sysctl -w net.ipv4.ip_forward=1
wget -qO- https://get.docker.io/ | sh
until test -f /var/run/docker.pid; do sleep 1 && echo waiting; done
grep mtu /etc/default/docker || (echo 'DOCKER_OPTS="-H :8000 -mtu 1460"' >> /etc/default/docker)
service docker restart
until echo 'GET /' >/dev/tcp/localhost/8000; do sleep 1 && echo waiting; done
`

// A Google Compute Engine implementation of the Cloud interface
type GCECloud struct {
	service   *compute.Service
	projectId string
}

type gceConfig struct {
	clientId     string
	clientSecret string
	scope        string
	refreshToken string
	projectId    string
}

type gcloudCredentialsCache struct {
	Data []struct {
		Credential struct {
			Client_Id     string
			Client_Secret string
			Access_Token  string
			Refresh_Token string
			Token_Expiry  time.Time
		}
		Key struct {
			Scope string
		}
	}
}

func gceConfAbsPath() (string, error) {
	usr, err := user.Current()
	if err != nil {
		return "", err
	}
	return path.Join(usr.HomeDir, "docker-cloud.json"), nil
}

func gcloudConfAbsPath() (string, error) {
	usr, err := user.Current()
	if err != nil {
		return "", err
	}
	return path.Join(usr.HomeDir, ".config/gcloud/credentials"), nil
}

func (conf *gceConfig) Read() (err error) {
	if err = conf.readDockerCloud(); err == nil {
		return
	}
	if err = conf.readGCloud(); err == nil {
		return
	}
	return
}

func (conf *gceConfig) readDockerCloud() (err error) {
	confPath, err := gceConfAbsPath()
	if err != nil {
		return
	}
	var data []byte
	if data, err = ioutil.ReadFile(confPath); err != nil {
		return
	}
	err = json.Unmarshal(data, conf)
	return
}

func (conf *gceConfig) readGCloud() error {
	confPath, err := gcloudConfAbsPath()
	if err != nil {
		return err
	}
	f, err := os.Open(confPath)
	if err != nil {
		return fmt.Errorf("unable to load gcloud credentials: %q", confPath)
	}
	defer f.Close()
	cache := &gcloudCredentialsCache{}
	if err := json.NewDecoder(f).Decode(cache); err != nil {
		return err
	}
	if len(cache.Data) == 0 {
		return fmt.Errorf("no gcloud credentials cached in: %q", confPath)
	}
	gcloud := cache.Data[0]
	conf.clientId = gcloud.Credential.Client_Id
	conf.clientSecret = gcloud.Credential.Client_Secret
	conf.scope = gcloud.Key.Scope
	conf.refreshToken = gcloud.Credential.Refresh_Token
	// TODO(proppy): read projectId from properties.
	return nil
}

func (conf *gceConfig) Write() error {
	confPath, err := gceConfAbsPath()
	if err != nil {
		return err
	}
	var data []byte
	if data, err = json.Marshal(conf); err != nil {
		return err
	}
	return ioutil.WriteFile(confPath, data, 0644)
}

// Create a GCE Cloud instance.  'clientId', 'clientSecret' and 'scope' are used to ask for a client
// credential.  'code' is optional and is only used if a cached credential can not be found.
// 'projectId' is the Google Cloud project name.
func NewCloudGCE(projectId string) (cloud *GCECloud, err error) {
	conf := &gceConfig{}
	if err = conf.Read(); err != nil {
		return nil, errors.New("Did you authorize the client? Run `docker-cloud auth`.")
	}
	if projectId == "" {
		if conf.projectId == "" {
			return nil, errors.New("Did you define project id? Run `docker-cloud start -project=<project-id>`")
		}
		projectId = conf.projectId
	}

	oAuth2Conf := newGCEOAuth2Config(conf.clientId, conf.clientSecret, conf.scope)
	transport := &oauth.Transport{
		Config: oAuth2Conf,
		// Make the actual request using the cached token to authenticate.
		// ("Here's the token, let me in!")
		Token:     &oauth.Token{RefreshToken: conf.refreshToken},
		Transport: http.DefaultTransport,
	}

	// TODO(jbd): Does it need to refresh the token, transport will auto do it if
	// it fails with an auth error on the first request.
	err = transport.Refresh()
	if err != nil {
		return
	}
	svc, err := compute.New(transport.Client())
	if err != nil {
		return
	}
	return &GCECloud{
		service:   svc,
		projectId: projectId,
	}, nil
}

// Implementation of the Cloud interface
{'fraction_non_alphanumeric': 0.12627509932352626, 'fraction_numerical': 0.011167185654461505, 'mean_word_length': 3.6827551533433884, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 10, 'https://': 4, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2531790', 'n_tokens_mistral': 3282, 'n_tokens_neox': 3109, 'n_words': 1008}