Exemple #1
0
func (s *Server) serveCharm(w http.ResponseWriter, r *http.Request) {
	if !strings.HasPrefix(r.URL.Path, "/charm/") {
		panic("serveCharm: bad url")
	}
	curl, err := charm.ParseURL("cs:" + r.URL.Path[len("/charm/"):])
	if err != nil {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	info, rc, err := s.store.OpenCharm(curl)
	if err == ErrNotFound {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		log.Printf("store: cannot open charm %q: %v", curl, err)
		return
	}
	if statsEnabled(r) {
		go s.store.IncCounter(charmStatsKey(curl, "charm-bundle"))
	}
	defer rc.Close()
	w.Header().Set("Connection", "close") // No keep-alive for now.
	w.Header().Set("Content-Type", "application/octet-stream")
	w.Header().Set("Content-Length", strconv.FormatInt(info.BundleSize(), 10))
	_, err = io.Copy(w, rc)
	if err != nil {
		log.Printf("store: failed to stream charm %q: %v", curl, err)
	}
}
Exemple #2
0
// ServiceSetCharm sets the charm for a given service.
func (c *Client) ServiceSetCharm(args params.ServiceSetCharm) error {
	service, err := c.api.state.Service(args.ServiceName)
	if err != nil {
		return err
	}
	curl, err := charm.ParseURL(args.CharmUrl)
	if err != nil {
		return err
	}
	if curl.Schema != "cs" {
		return fmt.Errorf(`charm url has unsupported schema %q`, curl.Schema)
	}
	if curl.Revision < 0 {
		return fmt.Errorf("charm url must include revision")
	}
	conn, err := juju.NewConnFromState(c.api.state)
	if err != nil {
		return err
	}
	ch, err := conn.PutCharm(curl, CharmStore, false)
	if err != nil {
		return err
	}
	return service.SetCharm(ch, args.Force)
}
Exemple #3
0
// ReadCharmURL reads the charm identity file from the supplied GitDir.
func ReadCharmURL(d *GitDir) (*charm.URL, error) {
	path := filepath.Join(d.path, ".juju-charm")
	surl := ""
	if err := utils.ReadYaml(path, &surl); err != nil {
		return nil, err
	}
	return charm.ParseURL(surl)
}
Exemple #4
0
func (s *URLSuite) TestParseURL(c *C) {
	for _, t := range urlTests {
		url, err := charm.ParseURL(t.s)
		comment := Commentf("ParseURL(%q)", t.s)
		if t.err != "" {
			c.Check(err.Error(), Matches, t.err, comment)
		} else {
			c.Check(url, DeepEquals, t.url, comment)
			c.Check(t.url.String(), Equals, t.s)
		}
	}
}
Exemple #5
0
func (s *URLSuite) TestInferURLNoDefaultSeries(c *C) {
	for _, t := range inferNoDefaultSeriesTests {
		inferred, err := charm.InferURL(t.vague, "")
		if t.exact == "" {
			c.Assert(err, ErrorMatches, fmt.Sprintf("cannot infer charm URL for %q: no series provided", t.vague))
		} else {
			parsed, err := charm.ParseURL(t.exact)
			c.Assert(err, IsNil)
			c.Assert(inferred, DeepEquals, parsed, Commentf(`InferURL(%q, "")`, t.vague))
		}
	}
}
Exemple #6
0
func (s *UniterSuite) TestSubordinateDying(c *C) {
	// Create a test context for later use.
	ctx := &context{
		st:      s.State,
		path:    filepath.Join(s.dataDir, "agents", "unit-u-0"),
		dataDir: s.dataDir,
		charms:  coretesting.ResponseMap{},
	}
	defer os.RemoveAll(ctx.path)

	// Create the subordinate service.
	dir := coretesting.Charms.ClonedDir(c.MkDir(), "series", "logging")
	curl, err := charm.ParseURL("cs:series/logging")
	c.Assert(err, IsNil)
	curl = curl.WithRevision(dir.Revision())
	step(c, ctx, addCharm{dir, curl})
	ctx.svc, err = s.State.AddService("u", ctx.sch)
	c.Assert(err, IsNil)

	// Create the principal service and add a relation.
	wps, err := s.State.AddService("wordpress", s.AddTestingCharm(c, "wordpress"))
	c.Assert(err, IsNil)
	wpu, err := wps.AddUnit()
	c.Assert(err, IsNil)
	eps, err := s.State.InferEndpoints([]string{"wordpress", "u"})
	c.Assert(err, IsNil)
	rel, err := s.State.AddRelation(eps...)
	c.Assert(err, IsNil)

	// Create the subordinate unit by entering scope as the principal.
	wpru, err := rel.Unit(wpu)
	c.Assert(err, IsNil)
	err = wpru.EnterScope(nil)
	c.Assert(err, IsNil)
	ctx.unit, err = s.State.Unit("u/0")
	c.Assert(err, IsNil)

	// Run the actual test.
	ctx.run(c, []stepper{
		serveCharm{},
		startUniter{},
		waitAddresses{},
		custom{func(c *C, ctx *context) {
			c.Assert(rel.Destroy(), IsNil)
		}},
		waitUniterDead{},
	})
}
Exemple #7
0
func (s *Server) serveEvent(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/charm-event" {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	r.ParseForm()
	response := map[string]*charm.EventResponse{}
	for _, url := range r.Form["charms"] {
		digest := ""
		if i := strings.Index(url, "@"); i >= 0 && i+1 < len(url) {
			digest = url[i+1:]
			url = url[:i]
		}
		c := &charm.EventResponse{}
		response[url] = c
		curl, err := charm.ParseURL(url)
		var event *CharmEvent
		if err == nil {
			event, err = s.store.CharmEvent(curl, digest)
		}
		var skey []string
		if err == nil {
			skey = charmStatsKey(curl, "charm-event")
			c.Kind = event.Kind.String()
			c.Revision = event.Revision
			c.Digest = event.Digest
			c.Errors = event.Errors
			c.Warnings = event.Warnings
			c.Time = event.Time.UTC().Format(time.RFC3339)
		} else {
			c.Errors = append(c.Errors, err.Error())
		}
		if skey != nil && statsEnabled(r) {
			go s.store.IncCounter(skey)
		}
	}
	data, err := json.Marshal(response)
	if err == nil {
		w.Header().Set("Content-Type", "application/json")
		_, err = w.Write(data)
	}
	if err != nil {
		log.Errorf("store: cannot write content: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
}
Exemple #8
0
// CharmInfo returns information about the requested charm.
func (c *Client) CharmInfo(args params.CharmInfo) (api.CharmInfo, error) {
	curl, err := charm.ParseURL(args.CharmURL)
	if err != nil {
		return api.CharmInfo{}, err
	}
	charm, err := c.api.state.Charm(curl)
	if err != nil {
		return api.CharmInfo{}, err
	}
	info := api.CharmInfo{
		Revision: charm.Revision(),
		URL:      curl.String(),
		Config:   charm.Config(),
		Meta:     charm.Meta(),
	}
	return info, nil
}
Exemple #9
0
// uniqueNameURLs returns the branch URL and the charm URL for the
// provided Launchpad branch unique name. The unique name must be
// in the form:
//
//     ~<user>/charms/<series>/<charm name>/trunk
//
// For testing purposes, if name has a prefix preceding a string in
// this format, the prefix is stripped out for computing the charm
// URL, and the unique name is returned unchanged as the branch URL.
func uniqueNameURLs(name string) (burl string, curl *charm.URL, err error) {
	u := strings.Split(name, "/")
	if len(u) > 5 {
		u = u[len(u)-5:]
		burl = name
	} else {
		burl = "lp:" + name
	}
	if len(u) < 5 || u[1] != "charms" || u[4] != "trunk" || len(u[0]) == 0 || u[0][0] != '~' {
		return "", nil, fmt.Errorf("unwanted branch name: %s", name)
	}
	curl, err = charm.ParseURL(fmt.Sprintf("cs:%s/%s/%s", u[0], u[2], u[3]))
	if err != nil {
		return "", nil, err
	}
	return burl, curl, nil
}
Exemple #10
0
func (s *URLSuite) TestInferURL(c *C) {
	for _, t := range inferTests {
		comment := Commentf("InferURL(%q, %q)", t.vague, "defseries")
		inferred, ierr := charm.InferURL(t.vague, "defseries")
		parsed, perr := charm.ParseURL(t.exact)
		if parsed != nil {
			c.Check(inferred, DeepEquals, parsed, comment)
		} else {
			expect := perr.Error()
			if t.vague != t.exact {
				expect = fmt.Sprintf("%s (URL inferred from %q)", expect, t.vague)
			}
			c.Check(ierr.Error(), Equals, expect, comment)
		}
	}
	u, err := charm.InferURL("~blah", "defseries")
	c.Assert(u, IsNil)
	c.Assert(err, ErrorMatches, "cannot infer charm URL with user but no schema: .*")
}
Exemple #11
0
func (s *Server) serveInfo(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/charm-info" {
		w.WriteHeader(http.StatusNotFound)
		return
	}
	r.ParseForm()
	response := map[string]*charm.InfoResponse{}
	for _, url := range r.Form["charms"] {
		c := &charm.InfoResponse{}
		response[url] = c
		curl, err := charm.ParseURL(url)
		var info *CharmInfo
		if err == nil {
			info, err = s.store.CharmInfo(curl)
		}
		var skey []string
		if err == nil {
			skey = charmStatsKey(curl, "charm-info")
			c.Sha256 = info.BundleSha256()
			c.Revision = info.Revision()
			c.Digest = info.Digest()
		} else {
			if err == ErrNotFound {
				skey = charmStatsKey(curl, "charm-missing")
			}
			c.Errors = append(c.Errors, err.Error())
		}
		if skey != nil && statsEnabled(r) {
			go s.store.IncCounter(skey)
		}
	}
	data, err := json.Marshal(response)
	if err == nil {
		w.Header().Set("Content-Type", "application/json")
		_, err = w.Write(data)
	}
	if err != nil {
		log.Printf("store: cannot write content: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
}
Exemple #12
0
// serviceSetCharm sets the charm for the given service.
func serviceSetCharm(state *state.State, service *state.Service, url string, force bool) error {
	curl, err := charm.ParseURL(url)
	if err != nil {
		return err
	}
	if curl.Schema != "cs" {
		return fmt.Errorf(`charm url has unsupported schema %q`, curl.Schema)
	}
	if curl.Revision < 0 {
		return fmt.Errorf("charm url must include revision")
	}
	conn, err := juju.NewConnFromState(state)
	if err != nil {
		return err
	}
	ch, err := conn.PutCharm(curl, CharmStore, false)
	if err != nil {
		return err
	}
	return service.SetCharm(ch, force)
}
Exemple #13
0
// ServiceDeploy fetches the charm from the charm store and deploys it. Local
// charms are not supported.
func (c *Client) ServiceDeploy(args params.ServiceDeploy) error {
	curl, err := charm.ParseURL(args.CharmUrl)
	if err != nil {
		return err
	}
	if curl.Schema != "cs" {
		return fmt.Errorf(`charm url has unsupported schema %q`, curl.Schema)
	}
	if curl.Revision < 0 {
		return fmt.Errorf("charm url must include revision")
	}
	conn, err := juju.NewConnFromState(c.api.state)
	if err != nil {
		return err
	}
	ch, err := conn.PutCharm(curl, CharmStore, false)
	if err != nil {
		return err
	}
	var settings charm.Settings
	if len(args.ConfigYAML) > 0 {
		settings, err = ch.Config().ParseSettingsYAML([]byte(args.ConfigYAML), args.ServiceName)
	} else if len(args.Config) > 0 {
		settings, err = ch.Config().ParseSettingsStrings(args.Config)
	}
	if err != nil {
		return err
	}
	_, err = conn.DeployService(juju.DeployServiceParams{
		ServiceName:    args.ServiceName,
		Charm:          ch,
		NumUnits:       args.NumUnits,
		ConfigSettings: settings,
		Constraints:    args.Constraints,
		ToMachineSpec:  args.ToMachineSpec,
	})
	return err
}